diff --git a/.github/workflows/buf-push.yml b/.github/workflows/buf-push.yml
index a7a66cdf3124..47fde85a1f87 100644
--- a/.github/workflows/buf-push.yml
+++ b/.github/workflows/buf-push.yml
@@ -18,5 +18,7 @@ jobs:
- uses: bufbuild/buf-action@v1
with:
input: "proto"
+ # Breaking changes are managed by the rpcchainvm protocol version.
+ breaking: false
token: ${{ secrets.BUF_TOKEN }}
version: 1.35.0
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 68c1dc63a9dd..619547b0eb4a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -133,6 +133,8 @@ jobs:
with:
input: "proto"
pr_comment: false
+ # Breaking changes are managed by the rpcchainvm protocol version.
+ breaking: false
# buf-action defaults to pushing on non-fork branch pushes
# which is never desirable for this job. The buf-push job is
# responsible for pushes.
diff --git a/RELEASES.md b/RELEASES.md
index 8dc7d0cd8db2..6d8537c08afc 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -6,10 +6,35 @@ This version is backwards compatible to [v1.12.0](https://github.com/ava-labs/av
The plugin version is unchanged at `38` and is compatible with versions `v1.12.0-v1.12.1`.
+**This release removes the support for the long deprecated Keystore API. Any users still relying on the keystore API will not be able to update to this version, or any later versions, of Avalanchego until their dependency on the keystore API has been removed.**
+
### APIs
- Deprecated:
- `info.GetTxFee`
+ - `keystore.createUser`
+ - `keystore.deleteUser`
+ - `keystore.listUsers`
+ - `keystore.importUser`
+ - `keystore.exportUser`
+ - `avm.createAddress`
+ - `avm.createFixedCapAsset`
+ - `avm.createNFTAsset`
+ - `avm.createVariableCapAsset`
+ - `avm.export`
+ - `avm.exportKey`
+ - `avm.import`
+ - `avm.importKey`
+ - `avm.listAddresses`
+ - `avm.mint`
+ - `avm.mintNFT`
+ - `avm.send`
+ - `avm.sendMultiple`
+ - `avm.sendNFT`
+ - `wallet.send`
+ - `wallet.sendMultiple`
+ - `platform.exportKey`
+ - `platform.listAddresses`
- Added:
- `avm.GetTxFee`
- `platform.getValidatorFeeConfig`
@@ -25,6 +50,7 @@ The plugin version is unchanged at `38` and is compatible with versions `v1.12.0
- `--add-primary-network-delegator-fee`
- `--add-subnet-validator-fee`
- `--add-subnet-delegator-fee`
+- Removed `--api-keystore-enabled`
### What's Changed
diff --git a/api/common_args_responses.go b/api/common_args_responses.go
index 3517e0582939..84edca03c26b 100644
--- a/api/common_args_responses.go
+++ b/api/common_args_responses.go
@@ -22,12 +22,6 @@ type JSONTxID struct {
TxID ids.ID `json:"txID"`
}
-// UserPass contains a username and a password
-type UserPass struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
// JSONAddress contains an address
type JSONAddress struct {
Address string `json:"address"`
@@ -38,32 +32,6 @@ type JSONAddresses struct {
Addresses []string `json:"addresses"`
}
-// JSONChangeAddr is the address change is sent to, if any
-type JSONChangeAddr struct {
- ChangeAddr string `json:"changeAddr"`
-}
-
-// JSONTxIDChangeAddr is a tx ID and change address
-type JSONTxIDChangeAddr struct {
- JSONTxID
- JSONChangeAddr
-}
-
-// JSONFromAddrs is a list of addresses to send funds from
-type JSONFromAddrs struct {
- From []string `json:"from"`
-}
-
-// JSONSpendHeader is 3 arguments to a method that spends (including those with tx fees)
-// 1) The username/password
-// 2) The addresses used in the method
-// 3) The address to send change to
-type JSONSpendHeader struct {
- UserPass
- JSONFromAddrs
- JSONChangeAddr
-}
-
// GetBlockArgs is the parameters supplied to the GetBlock API
type GetBlockArgs struct {
BlockID ids.ID `json:"blockID"`
diff --git a/api/keystore/blockchain_keystore.go b/api/keystore/blockchain_keystore.go
deleted file mode 100644
index 31a3bdc59109..000000000000
--- a/api/keystore/blockchain_keystore.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "go.uber.org/zap"
-
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/encdb"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/logging"
-)
-
-var _ BlockchainKeystore = (*blockchainKeystore)(nil)
-
-type BlockchainKeystore interface {
- // Get a database that is able to read and write unencrypted values from the
- // underlying database.
- GetDatabase(username, password string) (*encdb.Database, error)
-
- // Get the underlying database that is able to read and write encrypted
- // values. This Database will not perform any encrypting or decrypting of
- // values and is not recommended to be used when implementing a VM.
- GetRawDatabase(username, password string) (database.Database, error)
-}
-
-type blockchainKeystore struct {
- blockchainID ids.ID
- ks *keystore
-}
-
-func (bks *blockchainKeystore) GetDatabase(username, password string) (*encdb.Database, error) {
- bks.ks.log.Warn("deprecated keystore called",
- zap.String("method", "getDatabase"),
- logging.UserString("username", username),
- zap.Stringer("blockchainID", bks.blockchainID),
- )
-
- return bks.ks.GetDatabase(bks.blockchainID, username, password)
-}
-
-func (bks *blockchainKeystore) GetRawDatabase(username, password string) (database.Database, error) {
- bks.ks.log.Warn("deprecated keystore called",
- zap.String("method", "getRawDatabase"),
- logging.UserString("username", username),
- zap.Stringer("blockchainID", bks.blockchainID),
- )
-
- return bks.ks.GetRawDatabase(bks.blockchainID, username, password)
-}
diff --git a/api/keystore/client.go b/api/keystore/client.go
deleted file mode 100644
index 9d12ea0d1df9..000000000000
--- a/api/keystore/client.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "context"
-
- "github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/utils/formatting"
- "github.com/ava-labs/avalanchego/utils/rpc"
-)
-
-var _ Client = (*client)(nil)
-
-// Client interface for Avalanche Keystore API Endpoint
-//
-// Deprecated: The Keystore API is deprecated. Dedicated wallets should be used
-// instead.
-type Client interface {
- CreateUser(context.Context, api.UserPass, ...rpc.Option) error
- // Returns the usernames of all keystore users
- ListUsers(context.Context, ...rpc.Option) ([]string, error)
- // Returns the byte representation of the given user
- ExportUser(context.Context, api.UserPass, ...rpc.Option) ([]byte, error)
- // Import [exportedUser] to [importTo]
- ImportUser(ctx context.Context, importTo api.UserPass, exportedUser []byte, options ...rpc.Option) error
- // Delete the given user
- DeleteUser(context.Context, api.UserPass, ...rpc.Option) error
-}
-
-// Client implementation for Avalanche Keystore API Endpoint
-type client struct {
- requester rpc.EndpointRequester
-}
-
-// Deprecated: The Keystore API is deprecated. Dedicated wallets should be used
-// instead.
-func NewClient(uri string) Client {
- return &client{requester: rpc.NewEndpointRequester(
- uri + "/ext/keystore",
- )}
-}
-
-func (c *client) CreateUser(ctx context.Context, user api.UserPass, options ...rpc.Option) error {
- return c.requester.SendRequest(ctx, "keystore.createUser", &user, &api.EmptyReply{}, options...)
-}
-
-func (c *client) ListUsers(ctx context.Context, options ...rpc.Option) ([]string, error) {
- res := &ListUsersReply{}
- err := c.requester.SendRequest(ctx, "keystore.listUsers", struct{}{}, res, options...)
- return res.Users, err
-}
-
-func (c *client) ExportUser(ctx context.Context, user api.UserPass, options ...rpc.Option) ([]byte, error) {
- res := &ExportUserReply{
- Encoding: formatting.Hex,
- }
- err := c.requester.SendRequest(ctx, "keystore.exportUser", &user, res, options...)
- if err != nil {
- return nil, err
- }
- return formatting.Decode(res.Encoding, res.User)
-}
-
-func (c *client) ImportUser(ctx context.Context, user api.UserPass, account []byte, options ...rpc.Option) error {
- accountStr, err := formatting.Encode(formatting.Hex, account)
- if err != nil {
- return err
- }
-
- return c.requester.SendRequest(ctx, "keystore.importUser", &ImportUserArgs{
- UserPass: user,
- User: accountStr,
- Encoding: formatting.Hex,
- }, &api.EmptyReply{}, options...)
-}
-
-func (c *client) DeleteUser(ctx context.Context, user api.UserPass, options ...rpc.Option) error {
- return c.requester.SendRequest(ctx, "keystore.deleteUser", &user, &api.EmptyReply{}, options...)
-}
diff --git a/api/keystore/codec.go b/api/keystore/codec.go
deleted file mode 100644
index 3f6df0cf765f..000000000000
--- a/api/keystore/codec.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "github.com/ava-labs/avalanchego/codec"
- "github.com/ava-labs/avalanchego/codec/linearcodec"
- "github.com/ava-labs/avalanchego/utils/units"
-)
-
-const (
- CodecVersion = 0
-
- maxPackerSize = 1 * units.GiB // max size, in bytes, of something being marshalled by Marshal()
-)
-
-var Codec codec.Manager
-
-func init() {
- lc := linearcodec.NewDefault()
- Codec = codec.NewManager(maxPackerSize)
- if err := Codec.RegisterCodec(CodecVersion, lc); err != nil {
- panic(err)
- }
-}
diff --git a/api/keystore/gkeystore/keystore_client.go b/api/keystore/gkeystore/keystore_client.go
deleted file mode 100644
index 87527a640412..000000000000
--- a/api/keystore/gkeystore/keystore_client.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package gkeystore
-
-import (
- "context"
-
- "github.com/ava-labs/avalanchego/api/keystore"
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/encdb"
- "github.com/ava-labs/avalanchego/database/rpcdb"
- "github.com/ava-labs/avalanchego/vms/rpcchainvm/grpcutils"
-
- keystorepb "github.com/ava-labs/avalanchego/proto/pb/keystore"
- rpcdbpb "github.com/ava-labs/avalanchego/proto/pb/rpcdb"
-)
-
-var _ keystore.BlockchainKeystore = (*Client)(nil)
-
-// Client is a snow.Keystore that talks over RPC.
-type Client struct {
- client keystorepb.KeystoreClient
-}
-
-// NewClient returns a keystore instance connected to a remote keystore instance
-func NewClient(client keystorepb.KeystoreClient) *Client {
- return &Client{
- client: client,
- }
-}
-
-func (c *Client) GetDatabase(username, password string) (*encdb.Database, error) {
- bcDB, err := c.GetRawDatabase(username, password)
- if err != nil {
- return nil, err
- }
- return encdb.New([]byte(password), bcDB)
-}
-
-func (c *Client) GetRawDatabase(username, password string) (database.Database, error) {
- resp, err := c.client.GetDatabase(context.Background(), &keystorepb.GetDatabaseRequest{
- Username: username,
- Password: password,
- })
- if err != nil {
- return nil, err
- }
-
- clientConn, err := grpcutils.Dial(resp.ServerAddr)
- if err != nil {
- return nil, err
- }
-
- dbClient := rpcdb.NewClient(rpcdbpb.NewDatabaseClient(clientConn))
- return dbClient, err
-}
diff --git a/api/keystore/gkeystore/keystore_server.go b/api/keystore/gkeystore/keystore_server.go
deleted file mode 100644
index 65e6e90e99d9..000000000000
--- a/api/keystore/gkeystore/keystore_server.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package gkeystore
-
-import (
- "context"
-
- "github.com/ava-labs/avalanchego/api/keystore"
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/rpcdb"
- "github.com/ava-labs/avalanchego/vms/rpcchainvm/grpcutils"
-
- keystorepb "github.com/ava-labs/avalanchego/proto/pb/keystore"
- rpcdbpb "github.com/ava-labs/avalanchego/proto/pb/rpcdb"
-)
-
-var _ keystorepb.KeystoreServer = (*Server)(nil)
-
-// Server is a snow.Keystore that is managed over RPC.
-type Server struct {
- keystorepb.UnsafeKeystoreServer
- ks keystore.BlockchainKeystore
-}
-
-// NewServer returns a keystore connected to a remote keystore
-func NewServer(ks keystore.BlockchainKeystore) *Server {
- return &Server{
- ks: ks,
- }
-}
-
-func (s *Server) GetDatabase(
- _ context.Context,
- req *keystorepb.GetDatabaseRequest,
-) (*keystorepb.GetDatabaseResponse, error) {
- db, err := s.ks.GetRawDatabase(req.Username, req.Password)
- if err != nil {
- return nil, err
- }
-
- closer := dbCloser{Database: db}
-
- serverListener, err := grpcutils.NewListener()
- if err != nil {
- return nil, err
- }
-
- server := grpcutils.NewServer()
- closer.closer.Add(server)
- rpcdbpb.RegisterDatabaseServer(server, rpcdb.NewServer(&closer))
-
- // start the db server
- go grpcutils.Serve(serverListener, server)
-
- return &keystorepb.GetDatabaseResponse{ServerAddr: serverListener.Addr().String()}, nil
-}
-
-type dbCloser struct {
- database.Database
- closer grpcutils.ServerCloser
-}
-
-func (db *dbCloser) Close() error {
- err := db.Database.Close()
- db.closer.Stop()
- return err
-}
diff --git a/api/keystore/keystore.go b/api/keystore/keystore.go
deleted file mode 100644
index ed3c9d21e57e..000000000000
--- a/api/keystore/keystore.go
+++ /dev/null
@@ -1,382 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "errors"
- "fmt"
- "net/http"
- "sync"
-
- "github.com/gorilla/rpc/v2"
-
- "github.com/ava-labs/avalanchego/chains/atomic"
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/encdb"
- "github.com/ava-labs/avalanchego/database/prefixdb"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/json"
- "github.com/ava-labs/avalanchego/utils/logging"
- "github.com/ava-labs/avalanchego/utils/password"
-)
-
-const (
- // maxUserLen is the maximum allowed length of a username
- maxUserLen = 1024
-)
-
-var (
- errEmptyUsername = errors.New("empty username")
- errUserMaxLength = fmt.Errorf("username exceeds maximum length of %d chars", maxUserLen)
- errUserAlreadyExists = errors.New("user already exists")
- errIncorrectPassword = errors.New("incorrect password")
- errNonexistentUser = errors.New("user doesn't exist")
-
- usersPrefix = []byte("users")
- bcsPrefix = []byte("bcs")
-
- _ Keystore = (*keystore)(nil)
-)
-
-type Keystore interface {
- // Create the API endpoint for this keystore.
- CreateHandler() (http.Handler, error)
-
- // NewBlockchainKeyStore returns this keystore limiting the functionality to
- // a single blockchain database.
- NewBlockchainKeyStore(blockchainID ids.ID) BlockchainKeystore
-
- // Get a database that is able to read and write unencrypted values from the
- // underlying database.
- GetDatabase(bID ids.ID, username, password string) (*encdb.Database, error)
-
- // Get the underlying database that is able to read and write encrypted
- // values. This Database will not perform any encrypting or decrypting of
- // values and is not recommended to be used when implementing a VM.
- GetRawDatabase(bID ids.ID, username, password string) (database.Database, error)
-
- // CreateUser attempts to register this username and password as a new user
- // of the keystore.
- CreateUser(username, pw string) error
-
- // DeleteUser attempts to remove the provided username and all of its data
- // from the keystore.
- DeleteUser(username, pw string) error
-
- // ListUsers returns all the users that currently exist in this keystore.
- ListUsers() ([]string, error)
-
- // ImportUser imports a serialized encoding of a user's information complete
- // with encrypted database values. The password is integrity checked.
- ImportUser(username, pw string, user []byte) error
-
- // ExportUser exports a serialized encoding of a user's information complete
- // with encrypted database values.
- ExportUser(username, pw string) ([]byte, error)
-
- // Get the password that is used by [username]. If [username] doesn't exist,
- // no error is returned and a nil password hash is returned.
- getPassword(username string) (*password.Hash, error)
-}
-
-type kvPair struct {
- Key []byte `serialize:"true"`
- Value []byte `serialize:"true"`
-}
-
-// user describes the full content of a user
-type user struct {
- password.Hash `serialize:"true"`
- Data []kvPair `serialize:"true"`
-}
-
-type keystore struct {
- lock sync.Mutex
- log logging.Logger
-
- // Key: username
- // Value: The hash of that user's password
- usernameToPassword map[string]*password.Hash
-
- // Used to persist users and their data
- userDB database.Database
- bcDB database.Database
-}
-
-func New(log logging.Logger, db database.Database) Keystore {
- return &keystore{
- log: log,
- usernameToPassword: make(map[string]*password.Hash),
- userDB: prefixdb.New(usersPrefix, db),
- bcDB: prefixdb.New(bcsPrefix, db),
- }
-}
-
-func (ks *keystore) CreateHandler() (http.Handler, error) {
- newServer := rpc.NewServer()
- codec := json.NewCodec()
- newServer.RegisterCodec(codec, "application/json")
- newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
- if err := newServer.RegisterService(&service{ks: ks}, "keystore"); err != nil {
- return nil, err
- }
- return newServer, nil
-}
-
-func (ks *keystore) NewBlockchainKeyStore(blockchainID ids.ID) BlockchainKeystore {
- return &blockchainKeystore{
- blockchainID: blockchainID,
- ks: ks,
- }
-}
-
-func (ks *keystore) GetDatabase(bID ids.ID, username, password string) (*encdb.Database, error) {
- bcDB, err := ks.GetRawDatabase(bID, username, password)
- if err != nil {
- return nil, err
- }
- return encdb.New([]byte(password), bcDB)
-}
-
-func (ks *keystore) GetRawDatabase(bID ids.ID, username, pw string) (database.Database, error) {
- if username == "" {
- return nil, errEmptyUsername
- }
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- passwordHash, err := ks.getPassword(username)
- if err != nil {
- return nil, err
- }
- if passwordHash == nil || !passwordHash.Check(pw) {
- return nil, fmt.Errorf("%w: user %q", errIncorrectPassword, username)
- }
-
- userDB := prefixdb.New([]byte(username), ks.bcDB)
- bcDB := prefixdb.NewNested(bID[:], userDB)
- return bcDB, nil
-}
-
-func (ks *keystore) CreateUser(username, pw string) error {
- if username == "" {
- return errEmptyUsername
- }
- if len(username) > maxUserLen {
- return errUserMaxLength
- }
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- passwordHash, err := ks.getPassword(username)
- if err != nil {
- return err
- }
- if passwordHash != nil {
- return fmt.Errorf("%w: %s", errUserAlreadyExists, username)
- }
-
- if err := password.IsValid(pw, password.OK); err != nil {
- return err
- }
-
- passwordHash = &password.Hash{}
- if err := passwordHash.Set(pw); err != nil {
- return err
- }
-
- passwordBytes, err := Codec.Marshal(CodecVersion, passwordHash)
- if err != nil {
- return err
- }
-
- if err := ks.userDB.Put([]byte(username), passwordBytes); err != nil {
- return err
- }
- ks.usernameToPassword[username] = passwordHash
-
- return nil
-}
-
-func (ks *keystore) DeleteUser(username, pw string) error {
- if username == "" {
- return errEmptyUsername
- }
- if len(username) > maxUserLen {
- return errUserMaxLength
- }
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- // check if user exists and valid user.
- passwordHash, err := ks.getPassword(username)
- switch {
- case err != nil:
- return err
- case passwordHash == nil:
- return fmt.Errorf("%w: %s", errNonexistentUser, username)
- case !passwordHash.Check(pw):
- return fmt.Errorf("%w: user %q", errIncorrectPassword, username)
- }
-
- userNameBytes := []byte(username)
- userBatch := ks.userDB.NewBatch()
- if err := userBatch.Delete(userNameBytes); err != nil {
- return err
- }
-
- userDataDB := prefixdb.New(userNameBytes, ks.bcDB)
- dataBatch := userDataDB.NewBatch()
-
- it := userDataDB.NewIterator()
- defer it.Release()
-
- for it.Next() {
- if err := dataBatch.Delete(it.Key()); err != nil {
- return err
- }
- }
-
- if err := it.Error(); err != nil {
- return err
- }
-
- if err := atomic.WriteAll(dataBatch, userBatch); err != nil {
- return err
- }
-
- // delete from users map.
- delete(ks.usernameToPassword, username)
- return nil
-}
-
-func (ks *keystore) ListUsers() ([]string, error) {
- users := []string{}
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- it := ks.userDB.NewIterator()
- defer it.Release()
- for it.Next() {
- users = append(users, string(it.Key()))
- }
- return users, it.Error()
-}
-
-func (ks *keystore) ImportUser(username, pw string, userBytes []byte) error {
- if username == "" {
- return errEmptyUsername
- }
- if len(username) > maxUserLen {
- return errUserMaxLength
- }
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- passwordHash, err := ks.getPassword(username)
- if err != nil {
- return err
- }
- if passwordHash != nil {
- return fmt.Errorf("%w: %s", errUserAlreadyExists, username)
- }
-
- userData := user{}
- if _, err := Codec.Unmarshal(userBytes, &userData); err != nil {
- return err
- }
- if !userData.Hash.Check(pw) {
- return fmt.Errorf("%w: user %q", errIncorrectPassword, username)
- }
-
- usrBytes, err := Codec.Marshal(CodecVersion, &userData.Hash)
- if err != nil {
- return err
- }
-
- userBatch := ks.userDB.NewBatch()
- if err := userBatch.Put([]byte(username), usrBytes); err != nil {
- return err
- }
-
- userDataDB := prefixdb.New([]byte(username), ks.bcDB)
- dataBatch := userDataDB.NewBatch()
- for _, kvp := range userData.Data {
- if err := dataBatch.Put(kvp.Key, kvp.Value); err != nil {
- return fmt.Errorf("error on database put: %w", err)
- }
- }
-
- if err := atomic.WriteAll(dataBatch, userBatch); err != nil {
- return err
- }
- ks.usernameToPassword[username] = &userData.Hash
- return nil
-}
-
-func (ks *keystore) ExportUser(username, pw string) ([]byte, error) {
- if username == "" {
- return nil, errEmptyUsername
- }
- if len(username) > maxUserLen {
- return nil, errUserMaxLength
- }
-
- ks.lock.Lock()
- defer ks.lock.Unlock()
-
- passwordHash, err := ks.getPassword(username)
- if err != nil {
- return nil, err
- }
- if passwordHash == nil || !passwordHash.Check(pw) {
- return nil, fmt.Errorf("%w: user %q", errIncorrectPassword, username)
- }
-
- userDB := prefixdb.New([]byte(username), ks.bcDB)
-
- userData := user{Hash: *passwordHash}
- it := userDB.NewIterator()
- defer it.Release()
- for it.Next() {
- userData.Data = append(userData.Data, kvPair{
- Key: it.Key(),
- Value: it.Value(),
- })
- }
- if err := it.Error(); err != nil {
- return nil, err
- }
-
- // Return the byte representation of the user
- return Codec.Marshal(CodecVersion, &userData)
-}
-
-func (ks *keystore) getPassword(username string) (*password.Hash, error) {
- // If the user is already in memory, return it
- passwordHash, exists := ks.usernameToPassword[username]
- if exists {
- return passwordHash, nil
- }
-
- // The user is not in memory; try the database
- userBytes, err := ks.userDB.Get([]byte(username))
- if err == database.ErrNotFound {
- // The user doesn't exist
- return nil, nil
- }
- if err != nil {
- // An unexpected database error occurred
- return nil, err
- }
-
- passwordHash = &password.Hash{}
- _, err = Codec.Unmarshal(userBytes, passwordHash)
- return passwordHash, err
-}
diff --git a/api/keystore/service.go b/api/keystore/service.go
deleted file mode 100644
index aa56433ee6e7..000000000000
--- a/api/keystore/service.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "fmt"
- "net/http"
-
- "go.uber.org/zap"
-
- "github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/utils/formatting"
- "github.com/ava-labs/avalanchego/utils/logging"
-)
-
-type service struct {
- ks *keystore
-}
-
-func (s *service) CreateUser(_ *http.Request, args *api.UserPass, _ *api.EmptyReply) error {
- s.ks.log.Warn("deprecated API called",
- zap.String("service", "keystore"),
- zap.String("method", "createUser"),
- logging.UserString("username", args.Username),
- )
-
- return s.ks.CreateUser(args.Username, args.Password)
-}
-
-func (s *service) DeleteUser(_ *http.Request, args *api.UserPass, _ *api.EmptyReply) error {
- s.ks.log.Warn("deprecated API called",
- zap.String("service", "keystore"),
- zap.String("method", "deleteUser"),
- logging.UserString("username", args.Username),
- )
-
- return s.ks.DeleteUser(args.Username, args.Password)
-}
-
-type ListUsersReply struct {
- Users []string `json:"users"`
-}
-
-func (s *service) ListUsers(_ *http.Request, _ *struct{}, reply *ListUsersReply) error {
- s.ks.log.Warn("deprecated API called",
- zap.String("service", "keystore"),
- zap.String("method", "listUsers"),
- )
-
- var err error
- reply.Users, err = s.ks.ListUsers()
- return err
-}
-
-type ImportUserArgs struct {
- // The username and password of the user being imported
- api.UserPass
- // The string representation of the user
- User string `json:"user"`
- // The encoding of [User] ("hex")
- Encoding formatting.Encoding `json:"encoding"`
-}
-
-func (s *service) ImportUser(_ *http.Request, args *ImportUserArgs, _ *api.EmptyReply) error {
- s.ks.log.Warn("deprecated API called",
- zap.String("service", "keystore"),
- zap.String("method", "importUser"),
- logging.UserString("username", args.Username),
- )
-
- // Decode the user from string to bytes
- user, err := formatting.Decode(args.Encoding, args.User)
- if err != nil {
- return fmt.Errorf("couldn't decode 'user' to bytes: %w", err)
- }
-
- return s.ks.ImportUser(args.Username, args.Password, user)
-}
-
-type ExportUserArgs struct {
- // The username and password
- api.UserPass
- // The encoding for the exported user ("hex")
- Encoding formatting.Encoding `json:"encoding"`
-}
-
-type ExportUserReply struct {
- // String representation of the user
- User string `json:"user"`
- // The encoding for the exported user ("hex")
- Encoding formatting.Encoding `json:"encoding"`
-}
-
-func (s *service) ExportUser(_ *http.Request, args *ExportUserArgs, reply *ExportUserReply) error {
- s.ks.log.Warn("deprecated API called",
- zap.String("service", "keystore"),
- zap.String("method", "exportUser"),
- logging.UserString("username", args.Username),
- )
-
- userBytes, err := s.ks.ExportUser(args.Username, args.Password)
- if err != nil {
- return err
- }
-
- // Encode the user from bytes to string
- reply.User, err = formatting.Encode(args.Encoding, userBytes)
- if err != nil {
- return fmt.Errorf("couldn't encode user to string: %w", err)
- }
- reply.Encoding = args.Encoding
- return nil
-}
diff --git a/api/keystore/service.md b/api/keystore/service.md
deleted file mode 100644
index 62c593e26d47..000000000000
--- a/api/keystore/service.md
+++ /dev/null
@@ -1,245 +0,0 @@
-
-Because the node operator has access to your plain-text password, you should only create a keystore user on a node that you operate. If that node is breached, you could lose all your tokens. Keystore APIs are not recommended for use on Mainnet.
-
-
-Every node has a built-in keystore. Clients create users on the keystore, which act as identities to be used when interacting with blockchains. A keystore exists at the node level, so if you create a user on a node it exists _only_ on that node. However, users may be imported and exported using this API.
-
-For validation and cross-chain transfer on the Mainnet, you should issue transactions through [AvalancheJS](/tooling/avalanche-js). That way control keys for your funds won't be stored on the node, which significantly lowers the risk should a computer running a node be compromised. See following docs for details:
-
-1. Transfer AVAX Tokens Between Chains:
- - C-Chain: [export](https://github.com/ava-labs/avalanchejs/blob/master/examples/c-chain/export.ts) and [import](https://github.com/ava-labs/avalanchejs/blob/master/examples/c-chain/import.ts)
- - P-Chain: [export](https://github.com/ava-labs/avalanchejs/blob/master/examples/p-chain/export.ts) and [import](https://github.com/ava-labs/avalanchejs/blob/master/examples/p-chain/import.ts)
- - X-Chain: [export](https://github.com/ava-labs/avalanchejs/blob/master/examples/x-chain/export.ts) and [import](https://github.com/ava-labs/avalanchejs/blob/master/examples/x-chain/import.ts)
-2. [Add a Node to the Validator Set](/nodes/validate/node-validator)
-
-
-This API set is for a specific node, it is unavailable on the [public server](/tooling/rpc-providers).
-
-
-## Format
-
-This API uses the `json 2.0` API format. For more information on making JSON RPC calls, see [here](/api-reference/standards/guides/issuing-api-calls).
-
-## Endpoint
-
-```
-/ext/keystore
-```
-
-## Methods
-
-### `keystore.createUser`
-
-Create a new user with the specified username and password.
-
-**Signature**:
-
-```
-keystore.createUser(
-{
- username:string,
- password:string
-}
-) -> {}
-```
-
-- `username` and `password` can be at most 1024 characters.
-- Your request will be rejected if `password` is too weak. `password` should be at least 8 characters and contain upper and lower case letters as well as numbers and symbols.
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"keystore.createUser",
- "params" :{
- "username":"myUsername",
- "password":"myPassword"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {}
-}
-```
-
-### `keystore.deleteUser`
-
-
-Deprecated as of [v1.9.12](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-Delete a user.
-
-**Signature**:
-
-```
-keystore.deleteUser({ username: string, password:string }) -> {}
-```
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"keystore.deleteUser",
- "params" : {
- "username":"myUsername",
- "password":"myPassword"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {}
-}
-```
-
-### `keystore.exportUser`
-
-
-Deprecated as of [v1.9.12](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-Export a user. The user can be imported to another node with [`keystore.importUser`](/api-reference/keystore-api#keystoreimportuser). The user's password remains encrypted.
-
-**Signature**:
-
-```
-keystore.exportUser(
-{
- username:string,
- password:string,
- encoding:string //optional
-}
-) -> {
- user:string,
- encoding:string
-}
-```
-
-`encoding` specifies the format of the string encoding user data. Can only be `hex` when a value is provided.
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"keystore.exportUser",
- "params" :{
- "username":"myUsername",
- "password":"myPassword"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "user": "7655a29df6fc2747b0874e1148b423b954a25fcdb1f170d0ec8eb196430f7001942ce55b02a83b1faf50a674b1e55bfc00000000",
- "encoding": "hex"
- }
-}
-```
-
-### `keystore.importUser`
-
-
-Deprecated as of [v1.9.12](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-Import a user. `password` must match the user's password. `username` doesn't have to match the username `user` had when it was exported.
-
-**Signature**:
-
-```
-keystore.importUser(
-{
- username:string,
- password:string,
- user:string,
- encoding:string //optional
-}
-) -> {}
-```
-
-`encoding` specifies the format of the string encoding user data. Can only be `hex` when a value is provided.
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"keystore.importUser",
- "params" :{
- "username":"myUsername",
- "password":"myPassword",
- "user" :"0x7655a29df6fc2747b0874e1148b423b954a25fcdb1f170d0ec8eb196430f7001942ce55b02a83b1faf50a674b1e55bfc000000008cf2d869"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {}
-}
-```
-
-### `keystore.listUsers`
-
-
-Deprecated as of [v1.9.12](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-List the users in this keystore.
-
-**Signature**:
-
-```
-keystore.ListUsers() -> { users: []string }
-```
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"keystore.listUsers"
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/keystore
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "users": ["myUsername"]
- }
-}
-```
diff --git a/api/keystore/service_test.go b/api/keystore/service_test.go
deleted file mode 100644
index c011c92e78e1..000000000000
--- a/api/keystore/service_test.go
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "encoding/hex"
- "math/rand"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/database/memdb"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/formatting"
- "github.com/ava-labs/avalanchego/utils/logging"
- "github.com/ava-labs/avalanchego/utils/password"
-)
-
-// strongPassword defines a password used for the following tests that
-// scores high enough to pass the password strength scoring system
-var strongPassword = "N_+=_jJ;^(<;{4,:*m6CET}'&N;83FYK.wtNpwp-Jt" // #nosec G101
-
-func TestServiceListNoUsers(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- reply := ListUsersReply{}
- require.NoError(s.ListUsers(nil, nil, &reply))
- require.Empty(reply.Users)
-}
-
-func TestServiceCreateUser(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- require.NoError(s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: strongPassword,
- }, &api.EmptyReply{}))
- }
-
- {
- reply := ListUsersReply{}
- require.NoError(s.ListUsers(nil, nil, &reply))
- require.Len(reply.Users, 1)
- require.Equal("bob", reply.Users[0])
- }
-}
-
-// genStr returns a string of given length
-func genStr(n int) string {
- b := make([]byte, n)
- rand.Read(b) // #nosec G404
- return hex.EncodeToString(b)[:n]
-}
-
-// TestServiceCreateUserArgsCheck generates excessively long usernames or
-// passwords to assure the sanity checks on string length are not exceeded
-func TestServiceCreateUserArgsCheck(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- reply := api.EmptyReply{}
- err := s.CreateUser(nil, &api.UserPass{
- Username: genStr(maxUserLen + 1),
- Password: strongPassword,
- }, &reply)
- require.ErrorIs(err, errUserMaxLength)
- }
-
- {
- reply := api.EmptyReply{}
- err := s.CreateUser(nil, &api.UserPass{
- Username: "shortuser",
- Password: genStr(maxUserLen + 1),
- }, &reply)
- require.ErrorIs(err, password.ErrPassMaxLength)
- }
-
- {
- reply := ListUsersReply{}
- require.NoError(s.ListUsers(nil, nil, &reply))
- require.Empty(reply.Users)
- }
-}
-
-// TestServiceCreateUserWeakPassword tests creating a new user with a weak
-// password to ensure the password strength check is working
-func TestServiceCreateUserWeakPassword(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- reply := api.EmptyReply{}
- err := s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: "weak",
- }, &reply)
- require.ErrorIs(err, password.ErrWeakPassword)
- }
-}
-
-func TestServiceCreateDuplicate(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- require.NoError(s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: strongPassword,
- }, &api.EmptyReply{}))
- }
-
- {
- err := s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: strongPassword,
- }, &api.EmptyReply{})
- require.ErrorIs(err, errUserAlreadyExists)
- }
-}
-
-func TestServiceCreateUserNoName(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- reply := api.EmptyReply{}
- err := s.CreateUser(nil, &api.UserPass{
- Password: strongPassword,
- }, &reply)
- require.ErrorIs(err, errEmptyUsername)
-}
-
-func TestServiceUseBlockchainDB(t *testing.T) {
- require := require.New(t)
-
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- require.NoError(s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: strongPassword,
- }, &api.EmptyReply{}))
- }
-
- {
- db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
- require.NoError(err)
- require.NoError(db.Put([]byte("hello"), []byte("world")))
- }
-
- {
- db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
- require.NoError(err)
- val, err := db.Get([]byte("hello"))
- require.NoError(err)
- require.Equal([]byte("world"), val)
- }
-}
-
-func TestServiceExportImport(t *testing.T) {
- require := require.New(t)
-
- encodings := []formatting.Encoding{formatting.Hex}
- for _, encoding := range encodings {
- ks := New(logging.NoLog{}, memdb.New())
- s := service{ks: ks.(*keystore)}
-
- {
- require.NoError(s.CreateUser(nil, &api.UserPass{
- Username: "bob",
- Password: strongPassword,
- }, &api.EmptyReply{}))
- }
-
- {
- db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
- require.NoError(err)
- require.NoError(db.Put([]byte("hello"), []byte("world")))
- }
-
- exportArgs := ExportUserArgs{
- UserPass: api.UserPass{
- Username: "bob",
- Password: strongPassword,
- },
- Encoding: encoding,
- }
- exportReply := ExportUserReply{}
- require.NoError(s.ExportUser(nil, &exportArgs, &exportReply))
-
- newKS := New(logging.NoLog{}, memdb.New())
- newS := service{ks: newKS.(*keystore)}
-
- {
- err := newS.ImportUser(nil, &ImportUserArgs{
- UserPass: api.UserPass{
- Username: "bob",
- Password: "",
- },
- User: exportReply.User,
- }, &api.EmptyReply{})
- require.ErrorIs(err, errIncorrectPassword)
- }
-
- {
- err := newS.ImportUser(nil, &ImportUserArgs{
- UserPass: api.UserPass{
- Username: "",
- Password: "strongPassword",
- },
- User: exportReply.User,
- }, &api.EmptyReply{})
- require.ErrorIs(err, errEmptyUsername)
- }
-
- {
- require.NoError(newS.ImportUser(nil, &ImportUserArgs{
- UserPass: api.UserPass{
- Username: "bob",
- Password: strongPassword,
- },
- User: exportReply.User,
- Encoding: encoding,
- }, &api.EmptyReply{}))
- }
-
- {
- db, err := newKS.GetDatabase(ids.Empty, "bob", strongPassword)
- require.NoError(err)
- val, err := db.Get([]byte("hello"))
- require.NoError(err)
- require.Equal([]byte("world"), val)
- }
- }
-}
-
-func TestServiceDeleteUser(t *testing.T) {
- testUser := "testUser"
- password := "passwTest@fake01ord"
- tests := []struct {
- desc string
- setup func(ks *keystore) error
- request *api.UserPass
- want *api.EmptyReply
- expectedErr error
- }{
- {
- desc: "empty user name case",
- request: &api.UserPass{},
- expectedErr: errEmptyUsername,
- },
- {
- desc: "user not exists case",
- request: &api.UserPass{Username: "dummy"},
- expectedErr: errNonexistentUser,
- },
- {
- desc: "user exists and invalid password case",
- setup: func(ks *keystore) error {
- s := service{ks: ks}
- return s.CreateUser(nil, &api.UserPass{Username: testUser, Password: password}, &api.EmptyReply{})
- },
- request: &api.UserPass{Username: testUser, Password: "password"},
- expectedErr: errIncorrectPassword,
- },
- {
- desc: "user exists and valid password case",
- setup: func(ks *keystore) error {
- s := service{ks: ks}
- return s.CreateUser(nil, &api.UserPass{Username: testUser, Password: password}, &api.EmptyReply{})
- },
- request: &api.UserPass{Username: testUser, Password: password},
- want: &api.EmptyReply{},
- },
- {
- desc: "delete a user, imported from import api case",
- setup: func(ks *keystore) error {
- s := service{ks: ks}
-
- reply := api.EmptyReply{}
- if err := s.CreateUser(nil, &api.UserPass{Username: testUser, Password: password}, &reply); err != nil {
- return err
- }
-
- // created data in bob db
- db, err := ks.GetDatabase(ids.Empty, testUser, password)
- if err != nil {
- return err
- }
-
- return db.Put([]byte("hello"), []byte("world"))
- },
- request: &api.UserPass{Username: testUser, Password: password},
- want: &api.EmptyReply{},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.desc, func(t *testing.T) {
- require := require.New(t)
-
- ksIntf := New(logging.NoLog{}, memdb.New())
- ks := ksIntf.(*keystore)
- s := service{ks: ks}
-
- if tt.setup != nil {
- require.NoError(tt.setup(ks))
- }
- got := &api.EmptyReply{}
- err := s.DeleteUser(nil, tt.request, got)
- require.ErrorIs(err, tt.expectedErr)
- if tt.expectedErr != nil {
- return
- }
- require.Equal(tt.want, got)
- require.NotContains(ks.usernameToPassword, testUser) // delete is successful
-
- // deleted user details should be available to create user again.
- require.NoError(s.CreateUser(nil, &api.UserPass{Username: testUser, Password: password}, &api.EmptyReply{}))
- })
- }
-}
diff --git a/chains/manager.go b/chains/manager.go
index fed7bbcc0d54..ec62071ec495 100644
--- a/chains/manager.go
+++ b/chains/manager.go
@@ -17,7 +17,6 @@ import (
"go.uber.org/zap"
"github.com/ava-labs/avalanchego/api/health"
- "github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/api/server"
"github.com/ava-labs/avalanchego/chains/atomic"
@@ -205,7 +204,6 @@ type ManagerConfig struct {
NetworkID uint32 // ID of the network this node is connected to
PartialSyncPrimaryNetwork bool
Server server.Server // Handles HTTP API calls
- Keystore keystore.Keystore
AtomicMemory *atomic.Memory
AVAXAssetID ids.ID
XChainID ids.ID // ID of the X-Chain,
@@ -505,7 +503,6 @@ func (m *manager) buildChain(chainParams ChainParameters, sb subnets.Subnet) (*c
AVAXAssetID: m.AVAXAssetID,
Log: chainLog,
- Keystore: m.Keystore.NewBlockchainKeyStore(chainParams.ID),
SharedMemory: m.AtomicMemory.NewSharedMemory(chainParams.ID),
BCLookup: m,
Metrics: metrics.NewPrefixGatherer(),
diff --git a/config/config.go b/config/config.go
index 08182d5dfe15..228379fc0b12 100644
--- a/config/config.go
+++ b/config/config.go
@@ -55,16 +55,12 @@ const (
chainConfigFileName = "config"
chainUpgradeFileName = "upgrade"
subnetConfigFileExt = ".json"
-
- keystoreDeprecationMsg = "keystore API is deprecated"
)
var (
// Deprecated key --> deprecation message (i.e. which key replaces it)
// TODO: deprecate "BootstrapIDsKey" and "BootstrapIPsKey"
- deprecatedKeys = map[string]string{
- KeystoreAPIEnabledKey: keystoreDeprecationMsg,
- }
+ deprecatedKeys = map[string]string{}
errConflictingACPOpinion = errors.New("supporting and objecting to the same ACP")
errConflictingImplicitACPOpinion = errors.New("objecting to enabled ACP")
@@ -181,11 +177,10 @@ func getHTTPConfig(v *viper.Viper) (node.HTTPConfig, error) {
IndexAPIEnabled: v.GetBool(IndexEnabledKey),
IndexAllowIncomplete: v.GetBool(IndexAllowIncompleteKey),
},
- AdminAPIEnabled: v.GetBool(AdminAPIEnabledKey),
- InfoAPIEnabled: v.GetBool(InfoAPIEnabledKey),
- KeystoreAPIEnabled: v.GetBool(KeystoreAPIEnabledKey),
- MetricsAPIEnabled: v.GetBool(MetricsAPIEnabledKey),
- HealthAPIEnabled: v.GetBool(HealthAPIEnabledKey),
+ AdminAPIEnabled: v.GetBool(AdminAPIEnabledKey),
+ InfoAPIEnabled: v.GetBool(InfoAPIEnabledKey),
+ MetricsAPIEnabled: v.GetBool(MetricsAPIEnabledKey),
+ HealthAPIEnabled: v.GetBool(HealthAPIEnabledKey),
},
HTTPHost: v.GetString(HTTPHostKey),
HTTPPort: uint16(v.GetUint(HTTPPortKey)),
diff --git a/config/config.md b/config/config.md
index 795fb930c3a1..1d8f22384919 100644
--- a/config/config.md
+++ b/config/config.md
@@ -35,11 +35,6 @@ available. Defaults to `false`. See
If set to `false`, this node will not expose the Info API. Defaults to `true`. See
[here](docs.avax.network/reference/avalanchego/info-api) for more information.
-#### `--api-keystore-enabled` (boolean)
-
-If set to `true`, this node will expose the Keystore API. Defaults to `false`.
-See [here](docs.avax.network/reference/avalanchego/keystore-api) for more information.
-
#### `--api-metrics-enabled` (boolean)
If set to `false`, this node will not expose the Metrics API. Defaults to
diff --git a/config/flags.go b/config/flags.go
index f49ca21a1cbf..a1ce6042a137 100644
--- a/config/flags.go
+++ b/config/flags.go
@@ -235,7 +235,6 @@ func addNodeFlags(fs *pflag.FlagSet) {
// Enable/Disable APIs
fs.Bool(AdminAPIEnabledKey, false, "If true, this node exposes the Admin API")
fs.Bool(InfoAPIEnabledKey, true, "If true, this node exposes the Info API")
- fs.Bool(KeystoreAPIEnabledKey, false, "If true, this node exposes the Keystore API")
fs.Bool(MetricsAPIEnabledKey, true, "If true, this node exposes the Metrics API")
fs.Bool(HealthAPIEnabledKey, true, "If true, this node exposes the Health API")
diff --git a/config/keys.go b/config/keys.go
index 1ce3287e9037..760bee97fd77 100644
--- a/config/keys.go
+++ b/config/keys.go
@@ -145,7 +145,6 @@ const (
TrackSubnetsKey = "track-subnets"
AdminAPIEnabledKey = "api-admin-enabled"
InfoAPIEnabledKey = "api-info-enabled"
- KeystoreAPIEnabledKey = "api-keystore-enabled"
MetricsAPIEnabledKey = "api-metrics-enabled"
HealthAPIEnabledKey = "api-health-enabled"
MeterVMsEnabledKey = "meter-vms-enabled"
diff --git a/config/node/config.go b/config/node/config.go
index af8914236049..459e8430649e 100644
--- a/config/node/config.go
+++ b/config/node/config.go
@@ -52,11 +52,10 @@ type APIConfig struct {
APIIndexerConfig `json:"indexerConfig"`
// Enable/Disable APIs
- AdminAPIEnabled bool `json:"adminAPIEnabled"`
- InfoAPIEnabled bool `json:"infoAPIEnabled"`
- KeystoreAPIEnabled bool `json:"keystoreAPIEnabled"`
- MetricsAPIEnabled bool `json:"metricsAPIEnabled"`
- HealthAPIEnabled bool `json:"healthAPIEnabled"`
+ AdminAPIEnabled bool `json:"adminAPIEnabled"`
+ InfoAPIEnabled bool `json:"infoAPIEnabled"`
+ MetricsAPIEnabled bool `json:"metricsAPIEnabled"`
+ HealthAPIEnabled bool `json:"healthAPIEnabled"`
}
type IPConfig struct {
diff --git a/database/encdb/codec.go b/database/encdb/codec.go
deleted file mode 100644
index b786bec66916..000000000000
--- a/database/encdb/codec.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package encdb
-
-import (
- "github.com/ava-labs/avalanchego/codec"
- "github.com/ava-labs/avalanchego/codec/linearcodec"
-)
-
-const CodecVersion = 0
-
-var Codec codec.Manager
-
-func init() {
- lc := linearcodec.NewDefault()
- Codec = codec.NewDefaultManager()
-
- if err := Codec.RegisterCodec(CodecVersion, lc); err != nil {
- panic(err)
- }
-}
diff --git a/database/encdb/db.go b/database/encdb/db.go
deleted file mode 100644
index ea82b16a3659..000000000000
--- a/database/encdb/db.go
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package encdb
-
-import (
- "context"
- "crypto/cipher"
- "crypto/rand"
- "slices"
- "sync"
-
- "golang.org/x/crypto/chacha20poly1305"
-
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/utils/hashing"
-)
-
-var (
- _ database.Database = (*Database)(nil)
- _ database.Batch = (*batch)(nil)
- _ database.Iterator = (*iterator)(nil)
-)
-
-// Database encrypts all values that are provided
-type Database struct {
- lock sync.RWMutex
- cipher cipher.AEAD
- db database.Database
- closed bool
-}
-
-// New returns a new encrypted database
-func New(password []byte, db database.Database) (*Database, error) {
- h := hashing.ComputeHash256(password)
- aead, err := chacha20poly1305.NewX(h)
- return &Database{
- cipher: aead,
- db: db,
- }, err
-}
-
-func (db *Database) Has(key []byte) (bool, error) {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- if db.closed {
- return false, database.ErrClosed
- }
- return db.db.Has(key)
-}
-
-func (db *Database) Get(key []byte) ([]byte, error) {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- if db.closed {
- return nil, database.ErrClosed
- }
- encVal, err := db.db.Get(key)
- if err != nil {
- return nil, err
- }
- return db.decrypt(encVal)
-}
-
-func (db *Database) Put(key, value []byte) error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- if db.closed {
- return database.ErrClosed
- }
-
- encValue, err := db.encrypt(value)
- if err != nil {
- return err
- }
- return db.db.Put(key, encValue)
-}
-
-func (db *Database) Delete(key []byte) error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- if db.closed {
- return database.ErrClosed
- }
- return db.db.Delete(key)
-}
-
-func (db *Database) NewBatch() database.Batch {
- return &batch{
- Batch: db.db.NewBatch(),
- db: db,
- }
-}
-
-func (db *Database) NewIterator() database.Iterator {
- return db.NewIteratorWithStartAndPrefix(nil, nil)
-}
-
-func (db *Database) NewIteratorWithStart(start []byte) database.Iterator {
- return db.NewIteratorWithStartAndPrefix(start, nil)
-}
-
-func (db *Database) NewIteratorWithPrefix(prefix []byte) database.Iterator {
- return db.NewIteratorWithStartAndPrefix(nil, prefix)
-}
-
-func (db *Database) NewIteratorWithStartAndPrefix(start, prefix []byte) database.Iterator {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- if db.closed {
- return &database.IteratorError{
- Err: database.ErrClosed,
- }
- }
- return &iterator{
- Iterator: db.db.NewIteratorWithStartAndPrefix(start, prefix),
- db: db,
- }
-}
-
-func (db *Database) Compact(start, limit []byte) error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- if db.closed {
- return database.ErrClosed
- }
- return db.db.Compact(start, limit)
-}
-
-func (db *Database) Close() error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- if db.closed {
- return database.ErrClosed
- }
- db.closed = true
- return nil
-}
-
-func (db *Database) isClosed() bool {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- return db.closed
-}
-
-func (db *Database) HealthCheck(ctx context.Context) (interface{}, error) {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- if db.closed {
- return nil, database.ErrClosed
- }
- return db.db.HealthCheck(ctx)
-}
-
-type batch struct {
- database.Batch
-
- db *Database
- ops []database.BatchOp
-}
-
-func (b *batch) Put(key, value []byte) error {
- b.ops = append(b.ops, database.BatchOp{
- Key: slices.Clone(key),
- Value: slices.Clone(value),
- })
- encValue, err := b.db.encrypt(value)
- if err != nil {
- return err
- }
- return b.Batch.Put(key, encValue)
-}
-
-func (b *batch) Delete(key []byte) error {
- b.ops = append(b.ops, database.BatchOp{
- Key: slices.Clone(key),
- Delete: true,
- })
- return b.Batch.Delete(key)
-}
-
-func (b *batch) Write() error {
- b.db.lock.Lock()
- defer b.db.lock.Unlock()
-
- if b.db.closed {
- return database.ErrClosed
- }
-
- return b.Batch.Write()
-}
-
-// Reset resets the batch for reuse.
-func (b *batch) Reset() {
- if cap(b.ops) > len(b.ops)*database.MaxExcessCapacityFactor {
- b.ops = make([]database.BatchOp, 0, cap(b.ops)/database.CapacityReductionFactor)
- } else {
- clear(b.ops)
- b.ops = b.ops[:0]
- }
- b.Batch.Reset()
-}
-
-// Replay replays the batch contents.
-func (b *batch) Replay(w database.KeyValueWriterDeleter) error {
- for _, op := range b.ops {
- if op.Delete {
- if err := w.Delete(op.Key); err != nil {
- return err
- }
- } else if err := w.Put(op.Key, op.Value); err != nil {
- return err
- }
- }
- return nil
-}
-
-type iterator struct {
- database.Iterator
- db *Database
-
- val, key []byte
- err error
-}
-
-func (it *iterator) Next() bool {
- // Short-circuit and set an error if the underlying database has been closed.
- if it.db.isClosed() {
- it.val = nil
- it.key = nil
- it.err = database.ErrClosed
- return false
- }
-
- next := it.Iterator.Next()
- if next {
- encVal := it.Iterator.Value()
- val, err := it.db.decrypt(encVal)
- if err != nil {
- it.err = err
- return false
- }
- it.val = val
- it.key = it.Iterator.Key()
- } else {
- it.val = nil
- it.key = nil
- }
- return next
-}
-
-func (it *iterator) Error() error {
- if it.err != nil {
- return it.err
- }
- return it.Iterator.Error()
-}
-
-func (it *iterator) Key() []byte {
- return it.key
-}
-
-func (it *iterator) Value() []byte {
- return it.val
-}
-
-type encryptedValue struct {
- Ciphertext []byte `serialize:"true"`
- Nonce []byte `serialize:"true"`
-}
-
-func (db *Database) encrypt(plaintext []byte) ([]byte, error) {
- nonce := make([]byte, chacha20poly1305.NonceSizeX)
- if _, err := rand.Read(nonce); err != nil {
- return nil, err
- }
- ciphertext := db.cipher.Seal(nil, nonce, plaintext, nil)
- return Codec.Marshal(CodecVersion, &encryptedValue{
- Ciphertext: ciphertext,
- Nonce: nonce,
- })
-}
-
-func (db *Database) decrypt(ciphertext []byte) ([]byte, error) {
- val := encryptedValue{}
- if _, err := Codec.Unmarshal(ciphertext, &val); err != nil {
- return nil, err
- }
- return db.cipher.Open(nil, val.Nonce, val.Ciphertext, nil)
-}
diff --git a/database/encdb/db_test.go b/database/encdb/db_test.go
deleted file mode 100644
index 54bae29385b8..000000000000
--- a/database/encdb/db_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package encdb
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/dbtest"
- "github.com/ava-labs/avalanchego/database/memdb"
-)
-
-const testPassword = "lol totally a secure password" //nolint:gosec
-
-func TestInterface(t *testing.T) {
- for name, test := range dbtest.Tests {
- t.Run(name, func(t *testing.T) {
- unencryptedDB := memdb.New()
- db, err := New([]byte(testPassword), unencryptedDB)
- require.NoError(t, err)
-
- test(t, db)
- })
- }
-}
-
-func newDB(t testing.TB) database.Database {
- unencryptedDB := memdb.New()
- db, err := New([]byte(testPassword), unencryptedDB)
- require.NoError(t, err)
- return db
-}
-
-func FuzzKeyValue(f *testing.F) {
- dbtest.FuzzKeyValue(f, newDB(f))
-}
-
-func FuzzNewIteratorWithPrefix(f *testing.F) {
- dbtest.FuzzNewIteratorWithPrefix(f, newDB(f))
-}
-
-func FuzzNewIteratorWithStartAndPrefix(f *testing.F) {
- dbtest.FuzzNewIteratorWithStartAndPrefix(f, newDB(f))
-}
-
-func BenchmarkInterface(b *testing.B) {
- for _, size := range dbtest.BenchmarkSizes {
- keys, values := dbtest.SetupBenchmark(b, size[0], size[1], size[2])
- for name, bench := range dbtest.Benchmarks {
- b.Run(fmt.Sprintf("encdb_%d_pairs_%d_keys_%d_values_%s", size[0], size[1], size[2], name), func(b *testing.B) {
- bench(b, newDB(b), keys, values)
- })
- }
- }
-}
diff --git a/go.mod b/go.mod
index d03653f13775..38fda6471f30 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
github.com/DataDog/zstd v1.5.2
github.com/NYTimes/gziphandler v1.1.1
github.com/antithesishq/antithesis-sdk-go v0.3.8
- github.com/ava-labs/coreth v0.14.1-0.20241230191223-351149733d35
+ github.com/ava-labs/coreth v0.14.1-rc.0
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593
diff --git a/go.sum b/go.sum
index c7216e28f9f7..089d790e9100 100644
--- a/go.sum
+++ b/go.sum
@@ -64,8 +64,8 @@ github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/ava-labs/coreth v0.14.1-0.20241230191223-351149733d35 h1:qBNnMleaJ7yWjNiDdV7wIf/e/PxubB+Ww7Mfx4QN4p8=
-github.com/ava-labs/coreth v0.14.1-0.20241230191223-351149733d35/go.mod h1:nvQqJem4MuE0pU93aqBPsaEZx9NnXT0lI8d6rrQS5uY=
+github.com/ava-labs/coreth v0.14.1-rc.0 h1:0SXifWbwzfkzPUioFt2nMNKwjbRiiH55dUkgK38O6NE=
+github.com/ava-labs/coreth v0.14.1-rc.0/go.mod h1:lxDSXLcrszMo0N/PVJzfZ//H+bRwXF/KQWtpEYgXZqM=
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60 h1:EL66gtXOAwR/4KYBjOV03LTWgkEXvLePribLlJNu4g0=
github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60/go.mod h1:/7qKobTfbzBu7eSTVaXMTr56yTYk4j2Px6/8G+idxHo=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
diff --git a/node/node.go b/node/node.go
index cf3e29d8746a..6aa9f47e409b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -28,7 +28,6 @@ import (
"github.com/ava-labs/avalanchego/api/admin"
"github.com/ava-labs/avalanchego/api/health"
"github.com/ava-labs/avalanchego/api/info"
- "github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/api/server"
"github.com/ava-labs/avalanchego/chains"
@@ -110,8 +109,7 @@ var (
genesisHashKey = []byte("genesisID")
ungracefulShutdown = []byte("ungracefulShutdown")
- indexerDBPrefix = []byte{0x00}
- keystoreDBPrefix = []byte("keystore")
+ indexerDBPrefix = []byte{0x00}
errInvalidTLSKey = errors.New("invalid TLS key")
errShuttingDown = errors.New("server shutting down")
@@ -192,10 +190,6 @@ func New(
return nil, fmt.Errorf("problem initializing database: %w", err)
}
- if err := n.initKeystoreAPI(); err != nil { // Start the Keystore API
- return nil, fmt.Errorf("couldn't initialize keystore API: %w", err)
- }
-
n.initSharedMemory() // Initialize shared memory
// message.Creator is shared between networking, chainManager and the engine.
@@ -306,9 +300,6 @@ type Node struct {
// Indexes blocks, transactions and blocks
indexer indexer.Indexer
- // Handles calls to Keystore API
- keystore keystore.Keystore
-
// Manages shared memory
sharedMemory *atomic.Memory
@@ -1155,7 +1146,6 @@ func (n *Node) initChainManager(avaxAssetID ids.ID) error {
NodeID: n.ID,
NetworkID: n.Config.NetworkID,
Server: n.APIServer,
- Keystore: n.keystore,
AtomicMemory: n.sharedMemory,
AVAXAssetID: avaxAssetID,
XChainID: xChainID,
@@ -1281,23 +1271,6 @@ func (n *Node) initSharedMemory() {
n.sharedMemory = atomic.NewMemory(sharedMemoryDB)
}
-// initKeystoreAPI initializes the keystore service, which is an on-node wallet.
-// Assumes n.APIServer is already set
-func (n *Node) initKeystoreAPI() error {
- n.Log.Info("initializing keystore")
- n.keystore = keystore.New(n.Log, prefixdb.New(keystoreDBPrefix, n.DB))
- handler, err := n.keystore.CreateHandler()
- if err != nil {
- return err
- }
- if !n.Config.KeystoreAPIEnabled {
- n.Log.Info("skipping keystore API initialization because it has been disabled")
- return nil
- }
- n.Log.Warn("initializing deprecated keystore API")
- return n.APIServer.AddRoute(handler, "keystore", "")
-}
-
// initMetricsAPI initializes the Metrics API
// Assumes n.APIServer is already set
func (n *Node) initMetricsAPI() error {
diff --git a/proto/keystore/keystore.proto b/proto/keystore/keystore.proto
deleted file mode 100644
index c59f1b4dc3dd..000000000000
--- a/proto/keystore/keystore.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-syntax = "proto3";
-
-package keystore;
-
-option go_package = "github.com/ava-labs/avalanchego/proto/pb/keystore";
-
-service Keystore {
- rpc GetDatabase(GetDatabaseRequest) returns (GetDatabaseResponse);
-}
-
-message GetDatabaseRequest {
- string username = 1;
- string password = 2;
-}
-
-message GetDatabaseResponse {
- // reserved for backward compatibility
- // avalanchego <=v1.7.9 used the field "1" as an id to identify the gRPC server
- // address which served the Database service via the now removed service broker
- reserved 1;
- // server_addr is the address of the gRPC server hosting the Database service
- string server_addr = 2;
-}
diff --git a/proto/pb/keystore/keystore.pb.go b/proto/pb/keystore/keystore.pb.go
deleted file mode 100644
index 97620355c820..000000000000
--- a/proto/pb/keystore/keystore.pb.go
+++ /dev/null
@@ -1,228 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.33.0
-// protoc (unknown)
-// source: keystore/keystore.proto
-
-package keystore
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type GetDatabaseRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
- Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
-}
-
-func (x *GetDatabaseRequest) Reset() {
- *x = GetDatabaseRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_keystore_keystore_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GetDatabaseRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GetDatabaseRequest) ProtoMessage() {}
-
-func (x *GetDatabaseRequest) ProtoReflect() protoreflect.Message {
- mi := &file_keystore_keystore_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GetDatabaseRequest.ProtoReflect.Descriptor instead.
-func (*GetDatabaseRequest) Descriptor() ([]byte, []int) {
- return file_keystore_keystore_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *GetDatabaseRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
-func (x *GetDatabaseRequest) GetPassword() string {
- if x != nil {
- return x.Password
- }
- return ""
-}
-
-type GetDatabaseResponse struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // server_addr is the address of the gRPC server hosting the Database service
- ServerAddr string `protobuf:"bytes,2,opt,name=server_addr,json=serverAddr,proto3" json:"server_addr,omitempty"`
-}
-
-func (x *GetDatabaseResponse) Reset() {
- *x = GetDatabaseResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_keystore_keystore_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GetDatabaseResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GetDatabaseResponse) ProtoMessage() {}
-
-func (x *GetDatabaseResponse) ProtoReflect() protoreflect.Message {
- mi := &file_keystore_keystore_proto_msgTypes[1]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GetDatabaseResponse.ProtoReflect.Descriptor instead.
-func (*GetDatabaseResponse) Descriptor() ([]byte, []int) {
- return file_keystore_keystore_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *GetDatabaseResponse) GetServerAddr() string {
- if x != nil {
- return x.ServerAddr
- }
- return ""
-}
-
-var File_keystore_keystore_proto protoreflect.FileDescriptor
-
-var file_keystore_keystore_proto_rawDesc = []byte{
- 0x0a, 0x17, 0x6b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x74,
- 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x74,
- 0x6f, 0x72, 0x65, 0x22, 0x4c, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
- 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65,
- 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65,
- 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
- 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
- 0x64, 0x22, 0x3c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76,
- 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
- 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x32,
- 0x56, 0x0a, 0x08, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x47,
- 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x1c, 0x2e, 0x6b, 0x65, 0x79,
- 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
- 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x74,
- 0x6f, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75,
- 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x76, 0x61, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x61,
- 0x76, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2f, 0x70, 0x62, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var (
- file_keystore_keystore_proto_rawDescOnce sync.Once
- file_keystore_keystore_proto_rawDescData = file_keystore_keystore_proto_rawDesc
-)
-
-func file_keystore_keystore_proto_rawDescGZIP() []byte {
- file_keystore_keystore_proto_rawDescOnce.Do(func() {
- file_keystore_keystore_proto_rawDescData = protoimpl.X.CompressGZIP(file_keystore_keystore_proto_rawDescData)
- })
- return file_keystore_keystore_proto_rawDescData
-}
-
-var file_keystore_keystore_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_keystore_keystore_proto_goTypes = []interface{}{
- (*GetDatabaseRequest)(nil), // 0: keystore.GetDatabaseRequest
- (*GetDatabaseResponse)(nil), // 1: keystore.GetDatabaseResponse
-}
-var file_keystore_keystore_proto_depIdxs = []int32{
- 0, // 0: keystore.Keystore.GetDatabase:input_type -> keystore.GetDatabaseRequest
- 1, // 1: keystore.Keystore.GetDatabase:output_type -> keystore.GetDatabaseResponse
- 1, // [1:2] is the sub-list for method output_type
- 0, // [0:1] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_keystore_keystore_proto_init() }
-func file_keystore_keystore_proto_init() {
- if File_keystore_keystore_proto != nil {
- return
- }
- if !protoimpl.UnsafeEnabled {
- file_keystore_keystore_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GetDatabaseRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_keystore_keystore_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GetDatabaseResponse); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_keystore_keystore_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 1,
- },
- GoTypes: file_keystore_keystore_proto_goTypes,
- DependencyIndexes: file_keystore_keystore_proto_depIdxs,
- MessageInfos: file_keystore_keystore_proto_msgTypes,
- }.Build()
- File_keystore_keystore_proto = out.File
- file_keystore_keystore_proto_rawDesc = nil
- file_keystore_keystore_proto_goTypes = nil
- file_keystore_keystore_proto_depIdxs = nil
-}
diff --git a/proto/pb/keystore/keystore_grpc.pb.go b/proto/pb/keystore/keystore_grpc.pb.go
deleted file mode 100644
index 728bf23c0420..000000000000
--- a/proto/pb/keystore/keystore_grpc.pb.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-// versions:
-// - protoc-gen-go-grpc v1.3.0
-// - protoc (unknown)
-// source: keystore/keystore.proto
-
-package keystore
-
-import (
- context "context"
- grpc "google.golang.org/grpc"
- codes "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-// Requires gRPC-Go v1.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
-
-const (
- Keystore_GetDatabase_FullMethodName = "/keystore.Keystore/GetDatabase"
-)
-
-// KeystoreClient is the client API for Keystore service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
-type KeystoreClient interface {
- GetDatabase(ctx context.Context, in *GetDatabaseRequest, opts ...grpc.CallOption) (*GetDatabaseResponse, error)
-}
-
-type keystoreClient struct {
- cc grpc.ClientConnInterface
-}
-
-func NewKeystoreClient(cc grpc.ClientConnInterface) KeystoreClient {
- return &keystoreClient{cc}
-}
-
-func (c *keystoreClient) GetDatabase(ctx context.Context, in *GetDatabaseRequest, opts ...grpc.CallOption) (*GetDatabaseResponse, error) {
- out := new(GetDatabaseResponse)
- err := c.cc.Invoke(ctx, Keystore_GetDatabase_FullMethodName, in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// KeystoreServer is the server API for Keystore service.
-// All implementations must embed UnimplementedKeystoreServer
-// for forward compatibility
-type KeystoreServer interface {
- GetDatabase(context.Context, *GetDatabaseRequest) (*GetDatabaseResponse, error)
- mustEmbedUnimplementedKeystoreServer()
-}
-
-// UnimplementedKeystoreServer must be embedded to have forward compatible implementations.
-type UnimplementedKeystoreServer struct {
-}
-
-func (UnimplementedKeystoreServer) GetDatabase(context.Context, *GetDatabaseRequest) (*GetDatabaseResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method GetDatabase not implemented")
-}
-func (UnimplementedKeystoreServer) mustEmbedUnimplementedKeystoreServer() {}
-
-// UnsafeKeystoreServer may be embedded to opt out of forward compatibility for this service.
-// Use of this interface is not recommended, as added methods to KeystoreServer will
-// result in compilation errors.
-type UnsafeKeystoreServer interface {
- mustEmbedUnimplementedKeystoreServer()
-}
-
-func RegisterKeystoreServer(s grpc.ServiceRegistrar, srv KeystoreServer) {
- s.RegisterService(&Keystore_ServiceDesc, srv)
-}
-
-func _Keystore_GetDatabase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(GetDatabaseRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(KeystoreServer).GetDatabase(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: Keystore_GetDatabase_FullMethodName,
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(KeystoreServer).GetDatabase(ctx, req.(*GetDatabaseRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-// Keystore_ServiceDesc is the grpc.ServiceDesc for Keystore service.
-// It's only intended for direct use with grpc.RegisterService,
-// and not to be introspected or modified (even as a copy)
-var Keystore_ServiceDesc = grpc.ServiceDesc{
- ServiceName: "keystore.Keystore",
- HandlerType: (*KeystoreServer)(nil),
- Methods: []grpc.MethodDesc{
- {
- MethodName: "GetDatabase",
- Handler: _Keystore_GetDatabase_Handler,
- },
- },
- Streams: []grpc.StreamDesc{},
- Metadata: "keystore/keystore.proto",
-}
diff --git a/proto/pb/vm/vm.pb.go b/proto/pb/vm/vm.pb.go
index 796dfb758ac8..07d9b70a35b0 100644
--- a/proto/pb/vm/vm.pb.go
+++ b/proto/pb/vm/vm.pb.go
@@ -200,9 +200,8 @@ type InitializeRequest struct {
UpgradeBytes []byte `protobuf:"bytes,11,opt,name=upgrade_bytes,json=upgradeBytes,proto3" json:"upgrade_bytes,omitempty"`
ConfigBytes []byte `protobuf:"bytes,12,opt,name=config_bytes,json=configBytes,proto3" json:"config_bytes,omitempty"`
DbServerAddr string `protobuf:"bytes,13,opt,name=db_server_addr,json=dbServerAddr,proto3" json:"db_server_addr,omitempty"`
- // server_addr is the address of the gRPC server which serves
- // the messenger, keystore, shared memory, blockchain alias,
- // subnet alias, and appSender services
+ // server_addr is the address of the gRPC server which serves the messenger,
+ // shared memory, blockchain alias, subnet alias, and appSender services
ServerAddr string `protobuf:"bytes,14,opt,name=server_addr,json=serverAddr,proto3" json:"server_addr,omitempty"`
// network_upgrades_bytes is the json encoded network upgrades
NetworkUpgrades *NetworkUpgrades `protobuf:"bytes,15,opt,name=network_upgrades,json=networkUpgrades,proto3" json:"network_upgrades,omitempty"`
diff --git a/proto/vm/vm.proto b/proto/vm/vm.proto
index 25d773fd1d40..a8b3980b5e13 100644
--- a/proto/vm/vm.proto
+++ b/proto/vm/vm.proto
@@ -108,9 +108,8 @@ message InitializeRequest {
bytes upgrade_bytes = 11;
bytes config_bytes = 12;
string db_server_addr = 13;
- // server_addr is the address of the gRPC server which serves
- // the messenger, keystore, shared memory, blockchain alias,
- // subnet alias, and appSender services
+ // server_addr is the address of the gRPC server which serves the messenger,
+ // shared memory, blockchain alias, subnet alias, and appSender services
string server_addr = 14;
// network_upgrades_bytes is the json encoded network upgrades
NetworkUpgrades network_upgrades = 15;
diff --git a/snow/context.go b/snow/context.go
index 2b0f896363c9..def77c754683 100644
--- a/snow/context.go
+++ b/snow/context.go
@@ -8,7 +8,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
- "github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/ids"
@@ -45,7 +44,6 @@ type Context struct {
Log logging.Logger
Lock sync.RWMutex
- Keystore keystore.BlockchainKeystore
SharedMemory atomic.SharedMemory
BCLookup ids.AliaserReader
Metrics metrics.MultiGatherer
diff --git a/vms/avm/client.go b/vms/avm/client.go
index f1f0e5d5e82b..ed308f4ece24 100644
--- a/vms/avm/client.go
+++ b/vms/avm/client.go
@@ -13,7 +13,6 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow/choices"
"github.com/ava-labs/avalanchego/utils/constants"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/json"
@@ -76,147 +75,6 @@ type Client interface {
// GetTxFee returns the cost to issue certain transactions
GetTxFee(context.Context, ...rpc.Option) (uint64, uint64, error)
-
- // CreateAsset creates a new asset and returns its assetID
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- CreateAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- holders []*ClientHolder,
- minters []ClientOwners,
- options ...rpc.Option,
- ) (ids.ID, error)
- // CreateFixedCapAsset creates a new fixed cap asset and returns its assetID
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- CreateFixedCapAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- holders []*ClientHolder,
- options ...rpc.Option,
- ) (ids.ID, error)
- // CreateVariableCapAsset creates a new variable cap asset and returns its assetID
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- CreateVariableCapAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- minters []ClientOwners,
- options ...rpc.Option,
- ) (ids.ID, error)
- // CreateNFTAsset creates a new NFT asset and returns its assetID
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- CreateNFTAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- minters []ClientOwners,
- options ...rpc.Option,
- ) (ids.ID, error)
- // CreateAddress creates a new address controlled by [user]
- //
- // Deprecated: Keys should no longer be stored on the node.
- CreateAddress(ctx context.Context, user api.UserPass, options ...rpc.Option) (ids.ShortID, error)
- // ListAddresses returns all addresses on this chain controlled by [user]
- //
- // Deprecated: Keys should no longer be stored on the node.
- ListAddresses(ctx context.Context, user api.UserPass, options ...rpc.Option) ([]ids.ShortID, error)
- // ExportKey returns the private key corresponding to [addr] controlled by [user]
- //
- // Deprecated: Keys should no longer be stored on the node.
- ExportKey(ctx context.Context, user api.UserPass, addr ids.ShortID, options ...rpc.Option) (*secp256k1.PrivateKey, error)
- // ImportKey imports [privateKey] to [user]
- //
- // Deprecated: Keys should no longer be stored on the node.
- ImportKey(ctx context.Context, user api.UserPass, privateKey *secp256k1.PrivateKey, options ...rpc.Option) (ids.ShortID, error)
- // Mint [amount] of [assetID] to be owned by [to]
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- Mint(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- assetID string,
- to ids.ShortID,
- options ...rpc.Option,
- ) (ids.ID, error)
- // SendNFT sends an NFT and returns the ID of the newly created transaction
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- SendNFT(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- assetID string,
- groupID uint32,
- to ids.ShortID,
- options ...rpc.Option,
- ) (ids.ID, error)
- // MintNFT issues a MintNFT transaction and returns the ID of the newly created transaction
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- MintNFT(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- assetID string,
- payload []byte,
- to ids.ShortID,
- options ...rpc.Option,
- ) (ids.ID, error)
- // Import sends an import transaction to import funds from [sourceChain] and
- // returns the ID of the newly created transaction
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- Import(ctx context.Context, user api.UserPass, to ids.ShortID, sourceChain string, options ...rpc.Option) (ids.ID, error) // Export sends an asset from this chain to the P/C-Chain.
- // After this tx is accepted, the AVAX must be imported to the P/C-chain with an importTx.
- // Returns the ID of the newly created atomic transaction
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- Export(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- to ids.ShortID,
- toChainIDAlias string,
- assetID string,
- options ...rpc.Option,
- ) (ids.ID, error)
}
// implementation for an AVM client for interacting with avm [chain]
@@ -395,367 +253,6 @@ func (c *client) GetTxFee(ctx context.Context, options ...rpc.Option) (uint64, u
return uint64(res.TxFee), uint64(res.CreateAssetTxFee), err
}
-// ClientHolder describes how much an address owns of an asset
-type ClientHolder struct {
- Amount uint64
- Address ids.ShortID
-}
-
-// ClientOwners describes who can perform an action
-type ClientOwners struct {
- Threshold uint32
- Minters []ids.ShortID
-}
-
-func (c *client) CreateAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- clientHolders []*ClientHolder,
- clientMinters []ClientOwners,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &FormattedAssetID{}
- holders := make([]*Holder, len(clientHolders))
- for i, clientHolder := range clientHolders {
- holders[i] = &Holder{
- Amount: json.Uint64(clientHolder.Amount),
- Address: clientHolder.Address.String(),
- }
- }
- minters := make([]Owners, len(clientMinters))
- for i, clientMinter := range clientMinters {
- minters[i] = Owners{
- Threshold: json.Uint32(clientMinter.Threshold),
- Minters: ids.ShortIDsToStrings(clientMinter.Minters),
- }
- }
- err := c.requester.SendRequest(ctx, "avm.createAsset", &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Name: name,
- Symbol: symbol,
- Denomination: denomination,
- InitialHolders: holders,
- MinterSets: minters,
- }, res, options...)
- return res.AssetID, err
-}
-
-func (c *client) CreateFixedCapAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- clientHolders []*ClientHolder,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &FormattedAssetID{}
- holders := make([]*Holder, len(clientHolders))
- for i, clientHolder := range clientHolders {
- holders[i] = &Holder{
- Amount: json.Uint64(clientHolder.Amount),
- Address: clientHolder.Address.String(),
- }
- }
- err := c.requester.SendRequest(ctx, "avm.createAsset", &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Name: name,
- Symbol: symbol,
- Denomination: denomination,
- InitialHolders: holders,
- }, res, options...)
- return res.AssetID, err
-}
-
-func (c *client) CreateVariableCapAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- denomination byte,
- clientMinters []ClientOwners,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &FormattedAssetID{}
- minters := make([]Owners, len(clientMinters))
- for i, clientMinter := range clientMinters {
- minters[i] = Owners{
- Threshold: json.Uint32(clientMinter.Threshold),
- Minters: ids.ShortIDsToStrings(clientMinter.Minters),
- }
- }
- err := c.requester.SendRequest(ctx, "avm.createAsset", &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Name: name,
- Symbol: symbol,
- Denomination: denomination,
- MinterSets: minters,
- }, res, options...)
- return res.AssetID, err
-}
-
-func (c *client) CreateNFTAsset(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- name string,
- symbol string,
- clientMinters []ClientOwners,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &FormattedAssetID{}
- minters := make([]Owners, len(clientMinters))
- for i, clientMinter := range clientMinters {
- minters[i] = Owners{
- Threshold: json.Uint32(clientMinter.Threshold),
- Minters: ids.ShortIDsToStrings(clientMinter.Minters),
- }
- }
- err := c.requester.SendRequest(ctx, "avm.createNFTAsset", &CreateNFTAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Name: name,
- Symbol: symbol,
- MinterSets: minters,
- }, res, options...)
- return res.AssetID, err
-}
-
-func (c *client) CreateAddress(ctx context.Context, user api.UserPass, options ...rpc.Option) (ids.ShortID, error) {
- res := &api.JSONAddress{}
- err := c.requester.SendRequest(ctx, "avm.createAddress", &user, res, options...)
- if err != nil {
- return ids.ShortID{}, err
- }
- return address.ParseToID(res.Address)
-}
-
-func (c *client) ListAddresses(ctx context.Context, user api.UserPass, options ...rpc.Option) ([]ids.ShortID, error) {
- res := &api.JSONAddresses{}
- err := c.requester.SendRequest(ctx, "avm.listAddresses", &user, res, options...)
- if err != nil {
- return nil, err
- }
- return address.ParseToIDs(res.Addresses)
-}
-
-func (c *client) ExportKey(ctx context.Context, user api.UserPass, addr ids.ShortID, options ...rpc.Option) (*secp256k1.PrivateKey, error) {
- res := &ExportKeyReply{}
- err := c.requester.SendRequest(ctx, "avm.exportKey", &ExportKeyArgs{
- UserPass: user,
- Address: addr.String(),
- }, res, options...)
- return res.PrivateKey, err
-}
-
-func (c *client) ImportKey(ctx context.Context, user api.UserPass, privateKey *secp256k1.PrivateKey, options ...rpc.Option) (ids.ShortID, error) {
- res := &api.JSONAddress{}
- err := c.requester.SendRequest(ctx, "avm.importKey", &ImportKeyArgs{
- UserPass: user,
- PrivateKey: privateKey,
- }, res, options...)
- if err != nil {
- return ids.ShortID{}, err
- }
- return address.ParseToID(res.Address)
-}
-
-func (c *client) Send(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- assetID string,
- to ids.ShortID,
- memo string,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "avm.send", &SendArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- SendOutput: SendOutput{
- Amount: json.Uint64(amount),
- AssetID: assetID,
- To: to.String(),
- },
- Memo: memo,
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) SendMultiple(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- clientOutputs []ClientSendOutput,
- memo string,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- outputs := make([]SendOutput, len(clientOutputs))
- for i, clientOutput := range clientOutputs {
- outputs[i] = SendOutput{
- Amount: json.Uint64(clientOutput.Amount),
- AssetID: clientOutput.AssetID,
- To: clientOutput.To.String(),
- }
- }
- err := c.requester.SendRequest(ctx, "avm.sendMultiple", &SendMultipleArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Outputs: outputs,
- Memo: memo,
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) Mint(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- assetID string,
- to ids.ShortID,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "avm.mint", &MintArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Amount: json.Uint64(amount),
- AssetID: assetID,
- To: to.String(),
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) SendNFT(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- assetID string,
- groupID uint32,
- to ids.ShortID,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "avm.sendNFT", &SendNFTArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- AssetID: assetID,
- GroupID: json.Uint32(groupID),
- To: to.String(),
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) MintNFT(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- assetID string,
- payload []byte,
- to ids.ShortID,
- options ...rpc.Option,
-) (ids.ID, error) {
- payloadStr, err := formatting.Encode(formatting.Hex, payload)
- if err != nil {
- return ids.Empty, err
- }
- res := &api.JSONTxID{}
- err = c.requester.SendRequest(ctx, "avm.mintNFT", &MintNFTArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- AssetID: assetID,
- Payload: payloadStr,
- To: to.String(),
- Encoding: formatting.Hex,
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) Import(ctx context.Context, user api.UserPass, to ids.ShortID, sourceChain string, options ...rpc.Option) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "avm.import", &ImportArgs{
- UserPass: user,
- To: to.String(),
- SourceChain: sourceChain,
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *client) Export(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- to ids.ShortID,
- targetChain string,
- assetID string,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "avm.export", &ExportArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Amount: json.Uint64(amount),
- TargetChain: targetChain,
- To: to.String(),
- AssetID: assetID,
- }, res, options...)
- return res.TxID, err
-}
-
func AwaitTxAccepted(
c Client,
ctx context.Context,
diff --git a/vms/avm/client_test.go b/vms/avm/client_test.go
deleted file mode 100644
index 23dd74ce3b81..000000000000
--- a/vms/avm/client_test.go
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package avm
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/json"
- "github.com/ava-labs/avalanchego/utils/rpc"
-)
-
-type mockClient struct {
- require *require.Assertions
- expectedInData interface{}
-}
-
-func (mc *mockClient) SendRequest(
- _ context.Context,
- _ string,
- inData interface{},
- _ interface{},
- _ ...rpc.Option,
-) error {
- mc.require.Equal(mc.expectedInData, inData)
- return nil
-}
-
-func TestClientCreateAsset(t *testing.T) {
- require := require.New(t)
- client := client{}
- {
- // empty slices
- clientHolders := []*ClientHolder{}
- clientMinters := []ClientOwners{}
- clientFrom := []ids.ShortID{}
- clientChangeAddr := ids.GenerateTestShortID()
- serviceHolders := []*Holder{}
- serviceMinters := []Owners{}
- serviceFrom := []string{}
- serviceChangeAddr := clientChangeAddr.String()
- expectedInData := &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- JSONFromAddrs: api.JSONFromAddrs{From: serviceFrom},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: serviceChangeAddr},
- },
- InitialHolders: serviceHolders,
- MinterSets: serviceMinters,
- }
- client.requester = &mockClient{
- require: require,
- expectedInData: expectedInData,
- }
- _, err := client.CreateAsset(
- context.Background(),
- api.UserPass{},
- clientFrom,
- clientChangeAddr,
- "",
- "",
- 0,
- clientHolders,
- clientMinters,
- )
- require.NoError(err)
- }
- {
- // non empty slices
- clientHolders := []*ClientHolder{
- {
- Amount: 11,
- Address: ids.GenerateTestShortID(),
- },
- }
- clientMinters := []ClientOwners{
- {
- Threshold: 22,
- Minters: []ids.ShortID{ids.GenerateTestShortID()},
- },
- }
- clientFrom := []ids.ShortID{ids.GenerateTestShortID()}
- clientChangeAddr := ids.GenerateTestShortID()
- serviceHolders := []*Holder{
- {
- Amount: json.Uint64(clientHolders[0].Amount),
- Address: clientHolders[0].Address.String(),
- },
- }
- serviceMinters := []Owners{
- {
- Threshold: json.Uint32(clientMinters[0].Threshold),
- Minters: []string{clientMinters[0].Minters[0].String()},
- },
- }
- serviceFrom := []string{clientFrom[0].String()}
- serviceChangeAddr := clientChangeAddr.String()
- expectedInData := &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- JSONFromAddrs: api.JSONFromAddrs{From: serviceFrom},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: serviceChangeAddr},
- },
- InitialHolders: serviceHolders,
- MinterSets: serviceMinters,
- }
- client.requester = &mockClient{
- require: require,
- expectedInData: expectedInData,
- }
- _, err := client.CreateAsset(
- context.Background(),
- api.UserPass{},
- clientFrom,
- clientChangeAddr,
- "",
- "",
- 0,
- clientHolders,
- clientMinters,
- )
- require.NoError(err)
- }
-}
-
-func TestClientCreateFixedCapAsset(t *testing.T) {
- require := require.New(t)
- client := client{}
- {
- // empty slices
- clientHolders := []*ClientHolder{}
- clientFrom := []ids.ShortID{}
- clientChangeAddr := ids.GenerateTestShortID()
- serviceHolders := []*Holder{}
- serviceFrom := []string{}
- serviceChangeAddr := clientChangeAddr.String()
- expectedInData := &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- JSONFromAddrs: api.JSONFromAddrs{From: serviceFrom},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: serviceChangeAddr},
- },
- InitialHolders: serviceHolders,
- }
- client.requester = &mockClient{
- require: require,
- expectedInData: expectedInData,
- }
- _, err := client.CreateFixedCapAsset(
- context.Background(),
- api.UserPass{},
- clientFrom,
- clientChangeAddr,
- "",
- "",
- 0,
- clientHolders,
- )
- require.NoError(err)
- }
- {
- // non empty slices
- clientHolders := []*ClientHolder{
- {
- Amount: 11,
- Address: ids.GenerateTestShortID(),
- },
- }
- clientFrom := []ids.ShortID{ids.GenerateTestShortID()}
- clientChangeAddr := ids.GenerateTestShortID()
- serviceHolders := []*Holder{
- {
- Amount: json.Uint64(clientHolders[0].Amount),
- Address: clientHolders[0].Address.String(),
- },
- }
- serviceFrom := []string{clientFrom[0].String()}
- serviceChangeAddr := clientChangeAddr.String()
- expectedInData := &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- JSONFromAddrs: api.JSONFromAddrs{From: serviceFrom},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: serviceChangeAddr},
- },
- InitialHolders: serviceHolders,
- }
- client.requester = &mockClient{
- require: require,
- expectedInData: expectedInData,
- }
- _, err := client.CreateFixedCapAsset(
- context.Background(),
- api.UserPass{},
- clientFrom,
- clientChangeAddr,
- "",
- "",
- 0,
- clientHolders,
- )
- require.NoError(err)
- }
-}
diff --git a/vms/avm/environment_test.go b/vms/avm/environment_test.go
index 2dcfd077f234..02282ca55484 100644
--- a/vms/avm/environment_test.go
+++ b/vms/avm/environment_test.go
@@ -6,12 +6,10 @@ package avm
import (
"context"
"encoding/json"
- "math/rand"
"testing"
"github.com/stretchr/testify/require"
- "github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/database/memdb"
"github.com/ava-labs/avalanchego/database/prefixdb"
@@ -25,8 +23,6 @@ import (
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/formatting/address"
- "github.com/ava-labs/avalanchego/utils/logging"
- "github.com/ava-labs/avalanchego/utils/sampler"
"github.com/ava-labs/avalanchego/vms/avm/block/executor"
"github.com/ava-labs/avalanchego/vms/avm/config"
"github.com/ava-labs/avalanchego/vms/avm/fxs"
@@ -37,35 +33,17 @@ import (
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
avajson "github.com/ava-labs/avalanchego/utils/json"
- keystoreutils "github.com/ava-labs/avalanchego/vms/components/keystore"
)
const (
testTxFee uint64 = 1000
startBalance uint64 = 50000
- username = "bobby"
- password = "StrnasfqewiurPasswdn56d" //#nosec G101
feeAssetName = "TEST"
otherAssetName = "OTHER"
)
var (
- testChangeAddr = ids.GenerateTestShortID()
- testCases = []struct {
- name string
- avaxAsset bool
- }{
- {
- name: "genesis asset is AVAX",
- avaxAsset: true,
- },
- {
- name: "genesis asset is TEST",
- avaxAsset: false,
- },
- }
-
assetID = ids.ID{1, 2, 3}
keys = secp256k1.TestKeys()[:3] // TODO: Remove [:3]
@@ -79,16 +57,9 @@ func init() {
}
}
-type user struct {
- username string
- password string
- initialKeys []*secp256k1.PrivateKey
-}
-
type envConfig struct {
fork upgradetest.Fork
isCustomFeeAsset bool
- keystoreUsers []*user
vmStaticConfig *config.Config
vmDynamicConfig *Config
additionalFxs []*common.Fx
@@ -132,20 +103,6 @@ func setup(tb testing.TB, c *envConfig) *environment {
// The caller of this function is responsible for unlocking.
ctx.Lock.Lock()
- userKeystore := keystore.New(logging.NoLog{}, memdb.New())
- ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID)
-
- for _, user := range c.keystoreUsers {
- require.NoError(userKeystore.CreateUser(user.username, user.password))
-
- // Import the initially funded private keys
- keystoreUser, err := keystoreutils.NewUserFromKeystore(ctx.Keystore, user.username, user.password)
- require.NoError(err)
-
- require.NoError(keystoreUser.PutKeys(user.initialKeys...))
- require.NoError(keystoreUser.Close())
- }
-
vmStaticConfig := config.Config{
Upgrades: upgradetest.GetConfig(c.fork),
TxFee: testTxFee,
@@ -310,32 +267,6 @@ func newTx(tb testing.TB, genesisBytes []byte, chainID ids.ID, parser txs.Parser
return tx
}
-// Sample from a set of addresses and return them raw and formatted as strings.
-// The size of the sample is between 1 and len(addrs)
-// If len(addrs) == 0, returns nil
-func sampleAddrs(tb testing.TB, addressFormatter avax.AddressManager, addrs []ids.ShortID) ([]ids.ShortID, []string) {
- require := require.New(tb)
-
- sampledAddrs := []ids.ShortID{}
- sampledAddrsStr := []string{}
-
- sampler := sampler.NewUniform()
- sampler.Initialize(uint64(len(addrs)))
-
- numAddrs := 1 + rand.Intn(len(addrs)) // #nosec G404
- indices, ok := sampler.Sample(numAddrs)
- require.True(ok)
- for _, index := range indices {
- addr := addrs[index]
- addrStr, err := addressFormatter.FormatLocalAddress(addr)
- require.NoError(err)
-
- sampledAddrs = append(sampledAddrs, addr)
- sampledAddrsStr = append(sampledAddrsStr, addrStr)
- }
- return sampledAddrs, sampledAddrsStr
-}
-
func makeDefaultGenesis(tb testing.TB) *BuildGenesisArgs {
require := require.New(tb)
diff --git a/vms/avm/service.go b/vms/avm/service.go
index 32587cba3415..cba32b43faac 100644
--- a/vms/avm/service.go
+++ b/vms/avm/service.go
@@ -16,16 +16,11 @@ import (
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow/choices"
- "github.com/ava-labs/avalanchego/utils"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/avm/txs"
"github.com/ava-labs/avalanchego/vms/components/avax"
- "github.com/ava-labs/avalanchego/vms/components/keystore"
- "github.com/ava-labs/avalanchego/vms/components/verify"
- "github.com/ava-labs/avalanchego/vms/nftfx"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
avajson "github.com/ava-labs/avalanchego/utils/json"
@@ -41,17 +36,10 @@ const (
)
var (
- errTxNotCreateAsset = errors.New("transaction doesn't create an asset")
- errNoMinters = errors.New("no minters provided")
- errNoHoldersOrMinters = errors.New("no minters or initialHolders provided")
- errZeroAmount = errors.New("amount must be positive")
- errNoOutputs = errors.New("no outputs to send")
- errInvalidMintAmount = errors.New("amount minted must be positive")
- errNilTxID = errors.New("nil transaction ID")
- errNoAddresses = errors.New("no addresses provided")
- errNoKeys = errors.New("from addresses have no keys or funds")
- errMissingPrivateKey = errors.New("argument 'privateKey' not given")
- errNotLinearized = errors.New("chain is not linearized")
+ errTxNotCreateAsset = errors.New("transaction doesn't create an asset")
+ errNilTxID = errors.New("nil transaction ID")
+ errNoAddresses = errors.New("no addresses provided")
+ errNotLinearized = errors.New("chain is not linearized")
)
// FormattedAssetID defines a JSON formatted struct containing an assetID as a string
@@ -687,1347 +675,3 @@ func (s *Service) GetTxFee(_ *http.Request, _ *struct{}, reply *GetTxFeeReply) e
reply.CreateAssetTxFee = avajson.Uint64(s.vm.CreateAssetTxFee)
return nil
}
-
-// Holder describes how much an address owns of an asset
-type Holder struct {
- Amount avajson.Uint64 `json:"amount"`
- Address string `json:"address"`
-}
-
-// Owners describes who can perform an action
-type Owners struct {
- Threshold avajson.Uint32 `json:"threshold"`
- Minters []string `json:"minters"`
-}
-
-// CreateAssetArgs are arguments for passing into CreateAsset
-type CreateAssetArgs struct {
- api.JSONSpendHeader // User, password, from addrs, change addr
- Name string `json:"name"`
- Symbol string `json:"symbol"`
- Denomination byte `json:"denomination"`
- InitialHolders []*Holder `json:"initialHolders"`
- MinterSets []Owners `json:"minterSets"`
-}
-
-// AssetIDChangeAddr is an asset ID and a change address
-type AssetIDChangeAddr struct {
- FormattedAssetID
- api.JSONChangeAddr
-}
-
-// CreateAsset returns ID of the newly created asset
-func (s *Service) CreateAsset(_ *http.Request, args *CreateAssetArgs, reply *AssetIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "createAsset"),
- logging.UserString("name", args.Name),
- logging.UserString("symbol", args.Symbol),
- zap.Int("numInitialHolders", len(args.InitialHolders)),
- zap.Int("numMinters", len(args.MinterSets)),
- )
-
- tx, changeAddr, err := s.buildCreateAssetTx(args)
- if err != nil {
- return err
- }
-
- assetID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.AssetID = assetID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildCreateAssetTx(args *CreateAssetArgs) (*txs.Tx, ids.ShortID, error) {
- if len(args.InitialHolders) == 0 && len(args.MinterSets) == 0 {
- return nil, ids.ShortEmpty, errNoHoldersOrMinters
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amountsSpent, ins, keys, err := s.vm.Spend(
- utxos,
- kc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.CreateAssetTxFee,
- },
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- outs := []*avax.TransferableOutput{}
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent > s.vm.CreateAssetTxFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: s.vm.feeAssetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - s.vm.CreateAssetTxFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
-
- initialState := &txs.InitialState{
- FxIndex: 0, // TODO: Should lookup secp256k1fx FxID
- Outs: make([]verify.State, 0, len(args.InitialHolders)+len(args.MinterSets)),
- }
- for _, holder := range args.InitialHolders {
- addr, err := avax.ParseServiceAddress(s.vm, holder.Address)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- initialState.Outs = append(initialState.Outs, &secp256k1fx.TransferOutput{
- Amt: uint64(holder.Amount),
- OutputOwners: secp256k1fx.OutputOwners{
- Threshold: 1,
- Addrs: []ids.ShortID{addr},
- },
- })
- }
- for _, owner := range args.MinterSets {
- minter := &secp256k1fx.MintOutput{
- OutputOwners: secp256k1fx.OutputOwners{
- Threshold: uint32(owner.Threshold),
- Addrs: make([]ids.ShortID, 0, len(owner.Minters)),
- },
- }
- minterAddrsSet, err := avax.ParseServiceAddresses(s.vm, owner.Minters)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- minter.Addrs = minterAddrsSet.List()
- utils.Sort(minter.Addrs)
- initialState.Outs = append(initialState.Outs, minter)
- }
-
- codec := s.vm.parser.Codec()
- initialState.Sort(codec)
-
- tx := &txs.Tx{Unsigned: &txs.CreateAssetTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- Name: args.Name,
- Symbol: args.Symbol,
- Denomination: args.Denomination,
- States: []*txs.InitialState{initialState},
- }}
- return tx, changeAddr, tx.SignSECP256K1Fx(codec, keys)
-}
-
-// CreateFixedCapAsset returns ID of the newly created asset
-func (s *Service) CreateFixedCapAsset(r *http.Request, args *CreateAssetArgs, reply *AssetIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "createFixedCapAsset"),
- logging.UserString("name", args.Name),
- logging.UserString("symbol", args.Symbol),
- zap.Int("numInitialHolders", len(args.InitialHolders)),
- )
-
- return s.CreateAsset(r, args, reply)
-}
-
-// CreateVariableCapAsset returns ID of the newly created asset
-func (s *Service) CreateVariableCapAsset(r *http.Request, args *CreateAssetArgs, reply *AssetIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "createVariableCapAsset"),
- logging.UserString("name", args.Name),
- logging.UserString("symbol", args.Symbol),
- zap.Int("numMinters", len(args.MinterSets)),
- )
-
- return s.CreateAsset(r, args, reply)
-}
-
-// CreateNFTAssetArgs are arguments for passing into CreateNFTAsset requests
-type CreateNFTAssetArgs struct {
- api.JSONSpendHeader // User, password, from addrs, change addr
- Name string `json:"name"`
- Symbol string `json:"symbol"`
- MinterSets []Owners `json:"minterSets"`
-}
-
-// CreateNFTAsset returns ID of the newly created asset
-func (s *Service) CreateNFTAsset(_ *http.Request, args *CreateNFTAssetArgs, reply *AssetIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "createNFTAsset"),
- logging.UserString("name", args.Name),
- logging.UserString("symbol", args.Symbol),
- zap.Int("numMinters", len(args.MinterSets)),
- )
-
- tx, changeAddr, err := s.buildCreateNFTAsset(args)
- if err != nil {
- return err
- }
-
- assetID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.AssetID = assetID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildCreateNFTAsset(args *CreateNFTAssetArgs) (*txs.Tx, ids.ShortID, error) {
- if len(args.MinterSets) == 0 {
- return nil, ids.ShortEmpty, errNoMinters
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amountsSpent, ins, keys, err := s.vm.Spend(
- utxos,
- kc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.CreateAssetTxFee,
- },
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- outs := []*avax.TransferableOutput{}
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent > s.vm.CreateAssetTxFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: s.vm.feeAssetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - s.vm.CreateAssetTxFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
-
- initialState := &txs.InitialState{
- FxIndex: 1, // TODO: Should lookup nftfx FxID
- Outs: make([]verify.State, 0, len(args.MinterSets)),
- }
- for i, owner := range args.MinterSets {
- minter := &nftfx.MintOutput{
- GroupID: uint32(i),
- OutputOwners: secp256k1fx.OutputOwners{
- Threshold: uint32(owner.Threshold),
- },
- }
- minterAddrsSet, err := avax.ParseServiceAddresses(s.vm, owner.Minters)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- minter.Addrs = minterAddrsSet.List()
- utils.Sort(minter.Addrs)
- initialState.Outs = append(initialState.Outs, minter)
- }
-
- codec := s.vm.parser.Codec()
- initialState.Sort(codec)
-
- tx := &txs.Tx{Unsigned: &txs.CreateAssetTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- Name: args.Name,
- Symbol: args.Symbol,
- Denomination: 0, // NFTs are non-fungible
- States: []*txs.InitialState{initialState},
- }}
- return tx, changeAddr, tx.SignSECP256K1Fx(codec, keys)
-}
-
-// CreateAddress creates an address for the user [args.Username]
-func (s *Service) CreateAddress(_ *http.Request, args *api.UserPass, reply *api.JSONAddress) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "createAddress"),
- logging.UserString("username", args.Username),
- )
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
- defer user.Close()
-
- sk, err := keystore.NewKey(user)
- if err != nil {
- return err
- }
-
- reply.Address, err = s.vm.FormatLocalAddress(sk.PublicKey().Address())
- if err != nil {
- return fmt.Errorf("problem formatting address: %w", err)
- }
-
- // Return an error if the DB can't close, this will execute before the above
- // db close.
- return user.Close()
-}
-
-// ListAddresses returns all of the addresses controlled by user [args.Username]
-func (s *Service) ListAddresses(_ *http.Request, args *api.UserPass, response *api.JSONAddresses) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "listAddresses"),
- logging.UserString("username", args.Username),
- )
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
-
- response.Addresses = []string{}
-
- addresses, err := user.GetAddresses()
- if err != nil {
- // An error fetching the addresses may just mean that the user has no
- // addresses.
- return user.Close()
- }
-
- for _, address := range addresses {
- addr, err := s.vm.FormatLocalAddress(address)
- if err != nil {
- // Drop any potential error closing the database to report the
- // original error
- _ = user.Close()
- return fmt.Errorf("problem formatting address: %w", err)
- }
- response.Addresses = append(response.Addresses, addr)
- }
- return user.Close()
-}
-
-// ExportKeyArgs are arguments for ExportKey
-type ExportKeyArgs struct {
- api.UserPass
- Address string `json:"address"`
-}
-
-// ExportKeyReply is the response for ExportKey
-type ExportKeyReply struct {
- // The decrypted PrivateKey for the Address provided in the arguments
- PrivateKey *secp256k1.PrivateKey `json:"privateKey"`
-}
-
-// ExportKey returns a private key from the provided user
-func (s *Service) ExportKey(_ *http.Request, args *ExportKeyArgs, reply *ExportKeyReply) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "exportKey"),
- logging.UserString("username", args.Username),
- )
-
- addr, err := avax.ParseServiceAddress(s.vm, args.Address)
- if err != nil {
- return fmt.Errorf("problem parsing address %q: %w", args.Address, err)
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
-
- reply.PrivateKey, err = user.GetKey(addr)
- if err != nil {
- // Drop any potential error closing the database to report the original
- // error
- _ = user.Close()
- return fmt.Errorf("problem retrieving private key: %w", err)
- }
- return user.Close()
-}
-
-// ImportKeyArgs are arguments for ImportKey
-type ImportKeyArgs struct {
- api.UserPass
- PrivateKey *secp256k1.PrivateKey `json:"privateKey"`
-}
-
-// ImportKeyReply is the response for ImportKey
-type ImportKeyReply struct {
- // The address controlled by the PrivateKey provided in the arguments
- Address string `json:"address"`
-}
-
-// ImportKey adds a private key to the provided user
-func (s *Service) ImportKey(_ *http.Request, args *ImportKeyArgs, reply *api.JSONAddress) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "importKey"),
- logging.UserString("username", args.Username),
- )
-
- if args.PrivateKey == nil {
- return errMissingPrivateKey
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
- defer user.Close()
-
- if err := user.PutKeys(args.PrivateKey); err != nil {
- return fmt.Errorf("problem saving key %w", err)
- }
-
- newAddress := args.PrivateKey.PublicKey().Address()
- reply.Address, err = s.vm.FormatLocalAddress(newAddress)
- if err != nil {
- return fmt.Errorf("problem formatting address: %w", err)
- }
-
- return user.Close()
-}
-
-// SendOutput specifies that [Amount] of asset [AssetID] be sent to [To]
-type SendOutput struct {
- // The amount of funds to send
- Amount avajson.Uint64 `json:"amount"`
-
- // ID of the asset being sent
- AssetID string `json:"assetID"`
-
- // Address of the recipient
- To string `json:"to"`
-}
-
-// SendArgs are arguments for passing into Send requests
-type SendArgs struct {
- // User, password, from addrs, change addr
- api.JSONSpendHeader
-
- // The amount, assetID, and destination to send funds to
- SendOutput
-
- // Memo field
- Memo string `json:"memo"`
-}
-
-// SendMultipleArgs are arguments for passing into SendMultiple requests
-type SendMultipleArgs struct {
- // User, password, from addrs, change addr
- api.JSONSpendHeader
-
- // The outputs of the transaction
- Outputs []SendOutput `json:"outputs"`
-
- // Memo field
- Memo string `json:"memo"`
-}
-
-// Send returns the ID of the newly created transaction
-func (s *Service) Send(r *http.Request, args *SendArgs, reply *api.JSONTxIDChangeAddr) error {
- return s.SendMultiple(r, &SendMultipleArgs{
- JSONSpendHeader: args.JSONSpendHeader,
- Outputs: []SendOutput{args.SendOutput},
- Memo: args.Memo,
- }, reply)
-}
-
-// SendMultiple sends a transaction with multiple outputs.
-func (s *Service) SendMultiple(_ *http.Request, args *SendMultipleArgs, reply *api.JSONTxIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "sendMultiple"),
- logging.UserString("username", args.Username),
- )
-
- tx, changeAddr, err := s.buildSendMultiple(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildSendMultiple(args *SendMultipleArgs) (*txs.Tx, ids.ShortID, error) {
- // Validate the memo field
- memoBytes := []byte(args.Memo)
- if l := len(memoBytes); l > avax.MaxMemoSize {
- return nil, ids.ShortEmpty, fmt.Errorf("max memo length is %d but provided memo field is length %d", avax.MaxMemoSize, l)
- } else if len(args.Outputs) == 0 {
- return nil, ids.ShortEmpty, errNoOutputs
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Load user's UTXOs/keys
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Calculate required input amounts and create the desired outputs
- // String repr. of asset ID --> asset ID
- assetIDs := make(map[string]ids.ID)
- // Asset ID --> amount of that asset being sent
- amounts := make(map[ids.ID]uint64)
- // Outputs of our tx
- outs := []*avax.TransferableOutput{}
- for _, output := range args.Outputs {
- if output.Amount == 0 {
- return nil, ids.ShortEmpty, errZeroAmount
- }
- assetID, ok := assetIDs[output.AssetID] // Asset ID of next output
- if !ok {
- assetID, err = s.vm.lookupAssetID(output.AssetID)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("couldn't find asset %s", output.AssetID)
- }
- assetIDs[output.AssetID] = assetID
- }
- currentAmount := amounts[assetID]
- newAmount, err := safemath.Add(currentAmount, uint64(output.Amount))
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amounts[assetID] = newAmount
-
- // Parse the to address
- to, err := avax.ParseServiceAddress(s.vm, output.To)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem parsing to address %q: %w", output.To, err)
- }
-
- // Create the Output
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: uint64(output.Amount),
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{to},
- },
- },
- })
- }
-
- amountsWithFee := make(map[ids.ID]uint64, len(amounts)+1)
- for assetID, amount := range amounts {
- amountsWithFee[assetID] = amount
- }
-
- amountWithFee, err := safemath.Add(amounts[s.vm.feeAssetID], s.vm.TxFee)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amountsWithFee[s.vm.feeAssetID] = amountWithFee
-
- amountsSpent, ins, keys, err := s.vm.Spend(
- utxos,
- kc,
- amountsWithFee,
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Add the required change outputs
- for assetID, amountWithFee := range amountsWithFee {
- amountSpent := amountsSpent[assetID]
-
- if amountSpent > amountWithFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - amountWithFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
- }
-
- codec := s.vm.parser.Codec()
- avax.SortTransferableOutputs(outs, codec)
-
- tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- Memo: memoBytes,
- }}}
- return tx, changeAddr, tx.SignSECP256K1Fx(codec, keys)
-}
-
-// MintArgs are arguments for passing into Mint requests
-type MintArgs struct {
- api.JSONSpendHeader // User, password, from addrs, change addr
- Amount avajson.Uint64 `json:"amount"`
- AssetID string `json:"assetID"`
- To string `json:"to"`
-}
-
-// Mint issues a transaction that mints more of the asset
-func (s *Service) Mint(_ *http.Request, args *MintArgs, reply *api.JSONTxIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "mint"),
- logging.UserString("username", args.Username),
- )
-
- tx, changeAddr, err := s.buildMint(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildMint(args *MintArgs) (*txs.Tx, ids.ShortID, error) {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "mint"),
- logging.UserString("username", args.Username),
- )
-
- if args.Amount == 0 {
- return nil, ids.ShortEmpty, errInvalidMintAmount
- }
-
- assetID, err := s.vm.lookupAssetID(args.AssetID)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- to, err := avax.ParseServiceAddress(s.vm, args.To)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem parsing to address %q: %w", args.To, err)
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- feeUTXOs, feeKc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(feeKc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(feeKc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amountsSpent, ins, keys, err := s.vm.Spend(
- feeUTXOs,
- feeKc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.TxFee,
- },
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- outs := []*avax.TransferableOutput{}
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent > s.vm.TxFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: s.vm.feeAssetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - s.vm.TxFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
-
- // Get all UTXOs/keys for the user
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, nil)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- ops, opKeys, err := s.vm.Mint(
- utxos,
- kc,
- map[ids.ID]uint64{
- assetID: uint64(args.Amount),
- },
- to,
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- keys = append(keys, opKeys...)
-
- tx := &txs.Tx{Unsigned: &txs.OperationTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- Ops: ops,
- }}
- return tx, changeAddr, tx.SignSECP256K1Fx(s.vm.parser.Codec(), keys)
-}
-
-// SendNFTArgs are arguments for passing into SendNFT requests
-type SendNFTArgs struct {
- api.JSONSpendHeader // User, password, from addrs, change addr
- AssetID string `json:"assetID"`
- GroupID avajson.Uint32 `json:"groupID"`
- To string `json:"to"`
-}
-
-// SendNFT sends an NFT
-func (s *Service) SendNFT(_ *http.Request, args *SendNFTArgs, reply *api.JSONTxIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "sendNFT"),
- logging.UserString("username", args.Username),
- )
-
- tx, changeAddr, err := s.buildSendNFT(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildSendNFT(args *SendNFTArgs) (*txs.Tx, ids.ShortID, error) {
- // Parse the asset ID
- assetID, err := s.vm.lookupAssetID(args.AssetID)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the to address
- to, err := avax.ParseServiceAddress(s.vm, args.To)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem parsing to address %q: %w", args.To, err)
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amountsSpent, ins, secpKeys, err := s.vm.Spend(
- utxos,
- kc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.TxFee,
- },
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- outs := []*avax.TransferableOutput{}
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent > s.vm.TxFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: s.vm.feeAssetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - s.vm.TxFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
-
- ops, nftKeys, err := s.vm.SpendNFT(
- utxos,
- kc,
- assetID,
- uint32(args.GroupID),
- to,
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- tx := &txs.Tx{Unsigned: &txs.OperationTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- Ops: ops,
- }}
-
- codec := s.vm.parser.Codec()
- if err := tx.SignSECP256K1Fx(codec, secpKeys); err != nil {
- return nil, ids.ShortEmpty, err
- }
- return tx, changeAddr, tx.SignNFTFx(codec, nftKeys)
-}
-
-// MintNFTArgs are arguments for passing into MintNFT requests
-type MintNFTArgs struct {
- api.JSONSpendHeader // User, password, from addrs, change addr
- AssetID string `json:"assetID"`
- Payload string `json:"payload"`
- To string `json:"to"`
- Encoding formatting.Encoding `json:"encoding"`
-}
-
-// MintNFT issues a MintNFT transaction and returns the ID of the newly created transaction
-func (s *Service) MintNFT(_ *http.Request, args *MintNFTArgs, reply *api.JSONTxIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "mintNFT"),
- logging.UserString("username", args.Username),
- )
-
- tx, changeAddr, err := s.buildMintNFT(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildMintNFT(args *MintNFTArgs) (*txs.Tx, ids.ShortID, error) {
- assetID, err := s.vm.lookupAssetID(args.AssetID)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- to, err := avax.ParseServiceAddress(s.vm, args.To)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem parsing to address %q: %w", args.To, err)
- }
-
- payloadBytes, err := formatting.Decode(args.Encoding, args.Payload)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem decoding payload bytes: %w", err)
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- feeUTXOs, feeKc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(feeKc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(feeKc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amountsSpent, ins, secpKeys, err := s.vm.Spend(
- feeUTXOs,
- feeKc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.TxFee,
- },
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- outs := []*avax.TransferableOutput{}
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent > s.vm.TxFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: s.vm.feeAssetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - s.vm.TxFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
-
- // Get all UTXOs/keys
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, nil)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- ops, nftKeys, err := s.vm.MintNFT(
- utxos,
- kc,
- assetID,
- payloadBytes,
- to,
- )
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- tx := &txs.Tx{Unsigned: &txs.OperationTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- Ops: ops,
- }}
-
- codec := s.vm.parser.Codec()
- if err := tx.SignSECP256K1Fx(codec, secpKeys); err != nil {
- return nil, ids.ShortEmpty, err
- }
- return tx, changeAddr, tx.SignNFTFx(codec, nftKeys)
-}
-
-// ImportArgs are arguments for passing into Import requests
-type ImportArgs struct {
- // User that controls To
- api.UserPass
-
- // Chain the funds are coming from
- SourceChain string `json:"sourceChain"`
-
- // Address receiving the imported AVAX
- To string `json:"to"`
-}
-
-// Import imports an asset to this chain from the P/C-Chain.
-// The AVAX must have already been exported from the P/C-Chain.
-// Returns the ID of the newly created atomic transaction
-func (s *Service) Import(_ *http.Request, args *ImportArgs, reply *api.JSONTxID) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "import"),
- logging.UserString("username", args.Username),
- )
-
- tx, err := s.buildImport(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- return nil
-}
-
-func (s *Service) buildImport(args *ImportArgs) (*txs.Tx, error) {
- chainID, err := s.vm.ctx.BCLookup.Lookup(args.SourceChain)
- if err != nil {
- return nil, fmt.Errorf("problem parsing chainID %q: %w", args.SourceChain, err)
- }
-
- to, err := avax.ParseServiceAddress(s.vm, args.To)
- if err != nil {
- return nil, fmt.Errorf("problem parsing to address %q: %w", args.To, err)
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, nil)
- if err != nil {
- return nil, err
- }
-
- atomicUTXOs, _, _, err := avax.GetAtomicUTXOs(
- s.vm.ctx.SharedMemory,
- s.vm.parser.Codec(),
- chainID,
- kc.Addrs,
- ids.ShortEmpty,
- ids.Empty,
- int(maxPageSize),
- )
- if err != nil {
- return nil, fmt.Errorf("problem retrieving user's atomic UTXOs: %w", err)
- }
-
- amountsSpent, importInputs, importKeys, err := s.vm.SpendAll(atomicUTXOs, kc)
- if err != nil {
- return nil, err
- }
-
- ins := []*avax.TransferableInput{}
- keys := [][]*secp256k1.PrivateKey{}
-
- if amountSpent := amountsSpent[s.vm.feeAssetID]; amountSpent < s.vm.TxFee {
- var localAmountsSpent map[ids.ID]uint64
- localAmountsSpent, ins, keys, err = s.vm.Spend(
- utxos,
- kc,
- map[ids.ID]uint64{
- s.vm.feeAssetID: s.vm.TxFee - amountSpent,
- },
- )
- if err != nil {
- return nil, err
- }
- for asset, amount := range localAmountsSpent {
- newAmount, err := safemath.Add(amountsSpent[asset], amount)
- if err != nil {
- return nil, fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amountsSpent[asset] = newAmount
- }
- }
-
- // Because we ensured that we had enough inputs for the fee, we can
- // safely just remove it without concern for underflow.
- amountsSpent[s.vm.feeAssetID] -= s.vm.TxFee
-
- keys = append(keys, importKeys...)
-
- outs := []*avax.TransferableOutput{}
- for assetID, amount := range amountsSpent {
- if amount > 0 {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amount,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{to},
- },
- },
- })
- }
- }
- avax.SortTransferableOutputs(outs, s.vm.parser.Codec())
-
- tx := &txs.Tx{Unsigned: &txs.ImportTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- SourceChain: chainID,
- ImportedIns: importInputs,
- }}
- return tx, tx.SignSECP256K1Fx(s.vm.parser.Codec(), keys)
-}
-
-// ExportArgs are arguments for passing into ExportAVA requests
-type ExportArgs struct {
- // User, password, from addrs, change addr
- api.JSONSpendHeader
- // Amount of nAVAX to send
- Amount avajson.Uint64 `json:"amount"`
-
- // Chain the funds are going to. Optional. Used if To address does not include the chainID.
- TargetChain string `json:"targetChain"`
-
- // ID of the address that will receive the AVAX. This address may include the
- // chainID, which is used to determine what the destination chain is.
- To string `json:"to"`
-
- AssetID string `json:"assetID"`
-}
-
-// Export sends an asset from this chain to the P/C-Chain.
-// After this tx is accepted, the AVAX must be imported to the P/C-chain with an importTx.
-// Returns the ID of the newly created atomic transaction
-func (s *Service) Export(_ *http.Request, args *ExportArgs, reply *api.JSONTxIDChangeAddr) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "avm"),
- zap.String("method", "export"),
- logging.UserString("username", args.Username),
- )
-
- tx, changeAddr, err := s.buildExport(args)
- if err != nil {
- return err
- }
-
- txID, err := s.vm.issueTxFromRPC(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = s.vm.FormatLocalAddress(changeAddr)
- return err
-}
-
-func (s *Service) buildExport(args *ExportArgs) (*txs.Tx, ids.ShortID, error) {
- // Parse the asset ID
- assetID, err := s.vm.lookupAssetID(args.AssetID)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Get the chainID and parse the to address
- chainID, to, err := s.vm.ParseAddress(args.To)
- if err != nil {
- chainID, err = s.vm.ctx.BCLookup.Lookup(args.TargetChain)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- to, err = ids.ShortFromString(args.To)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
- }
-
- if args.Amount == 0 {
- return nil, ids.ShortEmpty, errZeroAmount
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(s.vm, args.From)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- // Get the UTXOs/keys for the from addresses
- utxos, kc, err := s.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return nil, ids.ShortEmpty, errNoKeys
- }
- changeAddr, err := s.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- amounts := map[ids.ID]uint64{}
- if assetID == s.vm.feeAssetID {
- amountWithFee, err := safemath.Add(uint64(args.Amount), s.vm.TxFee)
- if err != nil {
- return nil, ids.ShortEmpty, fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amounts[s.vm.feeAssetID] = amountWithFee
- } else {
- amounts[s.vm.feeAssetID] = s.vm.TxFee
- amounts[assetID] = uint64(args.Amount)
- }
-
- amountsSpent, ins, keys, err := s.vm.Spend(utxos, kc, amounts)
- if err != nil {
- return nil, ids.ShortEmpty, err
- }
-
- exportOuts := []*avax.TransferableOutput{{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: uint64(args.Amount),
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{to},
- },
- },
- }}
-
- outs := []*avax.TransferableOutput{}
- for assetID, amountSpent := range amountsSpent {
- amountToSend := amounts[assetID]
- if amountSpent > amountToSend {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - amountToSend,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
- }
-
- codec := s.vm.parser.Codec()
- avax.SortTransferableOutputs(outs, codec)
-
- tx := &txs.Tx{Unsigned: &txs.ExportTx{
- BaseTx: txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: s.vm.ctx.NetworkID,
- BlockchainID: s.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- }},
- DestinationChain: chainID,
- ExportedOuts: exportOuts,
- }}
- return tx, changeAddr, tx.SignSECP256K1Fx(codec, keys)
-}
diff --git a/vms/avm/service.md b/vms/avm/service.md
index 11c7ec6f1f06..97290bc250b2 100644
--- a/vms/avm/service.md
+++ b/vms/avm/service.md
@@ -175,7 +175,7 @@ curl -X POST --data '{
}
```
-### `avm.createAddress`
+### `avm.getAddressTxs`
:::caution
@@ -183,32 +183,54 @@ Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/
:::
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+Returns all transactions that change the balance of the given address. A transaction is said to
+change an address's balance if either is true:
-Create a new address controlled by the given user.
+- A UTXO that the transaction consumes was at least partially owned by the address.
+- A UTXO that the transaction produces is at least partially owned by the address.
+
+:::tip
+Note: Indexing (`index-transactions`) must be enabled in the X-chain config.
+:::
**Signature:**
```sh
-avm.createAddress({
- username: string,
- password: string
-}) -> {address: string}
+avm.getAddressTxs({
+ address: string,
+ cursor: uint64, // optional, leave empty to get the first page
+ assetID: string,
+ pageSize: uint64 // optional, defaults to 1024
+}) -> {
+ txIDs: []string,
+ cursor: uint64,
+}
```
+**Request Parameters:**
+
+- `address`: The address for which we're fetching related transactions
+- `assetID`: Only return transactions that changed the balance of this asset. Must be an ID or an
+ alias for an asset.
+- `pageSize`: Number of items to return per page. Optional. Defaults to 1024.
+
+**Response Parameter:**
+
+- `txIDs`: List of transaction IDs that affected the balance of this address.
+- `cursor`: Page number or offset. Use this in request to get the next page.
+
**Example Call:**
```sh
curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "avm.createAddress",
- "params": {
- "username": "myUsername",
- "password": "myPassword"
- },
- "id": 1
+ "jsonrpc":"2.0",
+ "id" : 1,
+ "method" :"avm.getAddressTxs",
+ "params" :{
+ "address":"X-local1kpprmfpzzm5lxyene32f6lr7j0aj7gxsu6hp9y",
+ "assetID":"AVAX",
+ "pageSize":20
+ }
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -218,13 +240,14 @@ curl -X POST --data '{
{
"jsonrpc": "2.0",
"result": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
+ "txIDs": ["SsJF7KKwxiUJkczygwmgLqo3XVRotmpKP8rMp74cpLuNLfwf6"],
+ "cursor": "1"
},
"id": 1
}
```
-### `avm.createFixedCapAsset`
+### `avm.getAllBalances`
:::caution
@@ -232,75 +255,28 @@ Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/
:::
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Create a new fixed-cap, fungible asset. A quantity of it is created at initialization and then no
-more is ever created. The asset can be sent with `avm.send`.
+Get the balances of all assets controlled by a given address.
**Signature:**
```sh
-avm.createFixedCapAsset({
- name: string,
- symbol: string,
- denomination: int, //optional
- initialHolders: []{
- address: string,
- amount: int
- },
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) ->
-{
- assetID: string,
- changeAddr: string
+avm.getAllBalances({address:string}) -> {
+ balances: []{
+ asset: string,
+ balance: int
+ }
}
```
-- `name` is a human-readable name for the asset. Not necessarily unique.
-- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique.
- May be omitted.
-- `denomination` determines how balances of this asset are displayed by user interfaces. If
- `denomination` is 0, 100 units of this asset are displayed as 100. If `denomination` is 1, 100
- units of this asset are displayed as 10.0. If `denomination` is 2, 100 units of this asset are
- displayed as 1.00, etc. Defaults to 0.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- `username` and `password` denote the user paying the transaction fee.
-- Each element in `initialHolders` specifies that `address` holds `amount` units of the asset at
- genesis.
-- `assetID` is the ID of the new asset.
-
**Example Call:**
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
"id" : 1,
- "method" :"avm.createFixedCapAsset",
+ "method" :"avm.getAllBalances",
"params" :{
- "name": "myFixedCapAsset",
- "symbol":"MFCA",
- "initialHolders": [
- {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "amount": 10000
- },
- {
- "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "amount":50000
- }
- ],
- "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
+ "address":"X-avax1c79e0dd0susp7dc8udq34jgk2yvve7hapvdyht"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -310,85 +286,67 @@ curl -X POST --data '{
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "assetID": "ZiKfqRXCZgHLgZ4rxGU9Qbycdzuq5DRY4tdSNS9ku8kcNxNLD",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
- }
+ "balances": [
+ {
+ "asset": "AVAX",
+ "balance": "102"
+ },
+ {
+ "asset": "2sdnziCz37Jov3QSNMXcFRGFJ1tgauaj6L7qfk7yUcRPfQMC79",
+ "balance": "10000"
+ }
+ ]
+ },
+ "id": 1
}
```
-### `avm.createNFTAsset`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `avm.getAssetDescription`
-Create a new non-fungible asset. No units of the asset exist at initialization. Minters can mint
-units of this asset using `avm.mintNFT`.
+Get information about an asset.
**Signature:**
```sh
-avm.createNFTAsset({
+avm.getAssetDescription({assetID: string}) -> {
+ assetId: string,
name: string,
symbol: string,
- minterSets: []{
- minters: []string,
- threshold: int
- },
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) ->
- {
- assetID: string,
- changeAddr: string,
+ denomination: int
}
```
-- `name` is a human-readable name for the asset. Not necessarily unique.
-- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique.
- May be omitted.
-- `minterSets` is a list where each element specifies that `threshold` of the addresses in `minters`
- may together mint more of the asset by signing a minting transaction.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- `username` pays the transaction fee.
-- `assetID` is the ID of the new asset.
-- `changeAddr` in the result is the address where any change was sent.
+- `assetID` is the id of the asset for which the information is requested.
+- `name` is the asset’s human-readable, not necessarily unique name.
+- `symbol` is the asset’s symbol.
+- `denomination` determines how balances of this asset are displayed by user interfaces. If
+ denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units
+ of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as
+ .100, etc.
+
+:::note
+
+The AssetID for AVAX differs depending on the network you are on.
+
+Mainnet: FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z
+
+Testnet: U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK
+
+For finding the `assetID` of other assets, this [info] might be useful.
+Also, `avm.getUTXOs` returns the `assetID` in its output.
+
+:::
**Example Call:**
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.createNFTAsset",
+ "id" :1,
+ "method" :"avm.getAssetDescription",
"params" :{
- "name":"Coincert",
- "symbol":"TIXX",
- "minterSets":[
- {
- "minters":[
- "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
- ],
- "threshold": 1
- }
- ],
- "from": ["X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
+ "assetID" :"FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -397,16 +355,18 @@ curl -X POST --data '{
```json
{
- "jsonrpc": "2.0",
- "result": {
- "assetID": "2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
- },
- "id": 1
-}
+ "jsonrpc": "2.0",
+ "result": {
+ "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
+ "name": "Avalanche",
+ "symbol": "AVAX",
+ "denomination": "9"
+ },
+ "id": 1
+}`
```
-### `avm.createVariableCapAsset`
+### `avm.getBalance`
:::caution
@@ -414,83 +374,31 @@ Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/
:::
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Create a new variable-cap, fungible asset. No units of the asset exist at initialization. Minters
-can mint units of this asset using `avm.mint`.
+Get the balance of an asset controlled by a given address.
**Signature:**
```sh
-avm.createVariableCapAsset({
- name: string,
- symbol: string,
- denomination: int, //optional
- minterSets: []{
- minters: []string,
- threshold: int
- },
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) ->
-{
- assetID: string,
- changeAddr: string,
-}
+avm.getBalance({
+ address: string,
+ assetID: string
+}) -> {balance: int}
```
-- `name` is a human-readable name for the asset. Not necessarily unique.
-- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique.
- May be omitted.
-- `denomination` determines how balances of this asset are displayed by user interfaces. If
- denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units
- of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as
- .100, etc.
-- `minterSets` is a list where each element specifies that `threshold` of the addresses in `minters`
- may together mint more of the asset by signing a minting transaction.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- `username` pays the transaction fee.
-- `assetID` is the ID of the new asset.
-- `changeAddr` in the result is the address where any change was sent.
+- `address` owner of the asset
+- `assetID` id of the asset for which the balance is requested
**Example Call:**
```sh
curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.createVariableCapAsset",
- "params" :{
- "name":"myVariableCapAsset",
- "symbol":"MFCA",
- "minterSets":[
- {
- "minters":[
- "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
- ],
- "threshold": 1
- },
- {
- "minters": [
- "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
- ],
- "threshold": 2
- }
- ],
- "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
- }
+ "jsonrpc":"2.0",
+ "id" : 1,
+ "method" :"avm.getBalance",
+ "params" :{
+ "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
+ "assetID": "2pYGetDWyKdHxpFxh2LHeoLNCH6H5vxxCxHQtFnnFaYxLsqtHC"
+ }
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -501,73 +409,56 @@ curl -X POST --data '{
"jsonrpc": "2.0",
"id": 1,
"result": {
- "assetID": "2QbZFE7J4MAny9iXHUwq8Pz8SpFhWk3maCw4SkinVPv6wPmAbK",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "balance": "299999999999900",
+ "utxoIDs": [
+ {
+ "txID": "WPQdyLNqHfiEKp4zcCpayRHYDVYuh1hqs9c1RqgZXS4VPgdvo",
+ "outputIndex": 1
+ }
+ ]
}
}
```
-### `avm.export`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `avm.getBlock`
-Send an asset from the X-Chain to the P-Chain or C-Chain.
+Returns the block with the given id.
**Signature:**
```sh
-avm.export({
- to: string,
- amount: int,
- assetID: string,
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string,
-}) ->
-{
- txID: string,
- changeAddr: string,
+avm.getBlock({
+ blockID: string
+ encoding: string // optional
+}) -> {
+ block: string,
+ encoding: string
}
```
-- `to` is the P-Chain or C-Chain address the asset is sent to.
-- `amount` is the amount of the asset to send.
-- `assetID` is the asset id of the asset which is sent. Use `AVAX` for AVAX exports.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- The asset is sent from addresses controlled by `username`
-- `password` is `username`‘s password.
+**Request:**
+
+- `blockID` is the block ID. It should be in cb58 format.
+- `encoding` is the encoding format to use. Can be either `hex` or `json`. Defaults to `hex`.
+
+**Response:**
+
+- `block` is the transaction encoded to `encoding`.
+- `encoding` is the `encoding`.
-- `txID` is this transaction’s ID.
-- `changeAddr` in the result is the address where any change was sent.
+#### Hex Example
**Example Call:**
```sh
curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.export",
- "params" :{
- "to":"C-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "amount": 10,
- "assetID": "AVAX",
- "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
- }
+ "jsonrpc": "2.0",
+ "method": "avm.getBlock",
+ "params": {
+ "blockID": "tXJ4xwmR8soHE6DzRNMQPtiwQvuYsHn6eLLBzo2moDqBquqy6",
+ "encoding": "hex"
+ },
+ "id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -577,888 +468,52 @@ curl -X POST --data '{
{
"jsonrpc": "2.0",
"result": {
- "txID": "2Eu16yNaepP57XrrJgjKGpiEDandpiGWW8xbUm6wcTYny3fejj",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "block": "0x00000000002000000000641ad33ede17f652512193721df87994f783ec806bb5640c39ee73676caffcc3215e0651000000000049a80a000000010000000e0000000100000000000000000000000000000000000000000000000000000000000000000000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000002e1a2a3910000000000000000000000001000000015cf998275803a7277926912defdf177b2e97b0b400000001e0d825c5069a7336671dd27eaa5c7851d2cf449e7e1cdc469c5c9e5a953955950000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000008908223b680000000100000000000000005e45d02fcc9e585544008f1df7ae5c94bf7f0f2600000000641ad3b600000000642d48b60000005aedf802580000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000005aedf80258000000000000000000000001000000015cf998275803a7277926912defdf177b2e97b0b40000000b000000000000000000000001000000012892441ba9a160bcdc596dcd2cc3ad83c3493589000000010000000900000001adf2237a5fe2dfd906265e8e14274aa7a7b2ee60c66213110598ba34fb4824d74f7760321c0c8fb1e8d3c5e86909248e48a7ae02e641da5559351693a8a1939800286d4fa2",
+ "encoding": "hex"
},
"id": 1
}
```
-### `avm.exportKey`
+### `avm.getBlockByHeight`
-:::caution
+Returns block at the given height.
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
+**Signature:**
-:::
+```sh
+avm.getBlockByHeight({
+ height: string
+ encoding: string // optional
+}) -> {
+ block: string,
+ encoding: string
+}
+```
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+**Request:**
-Get the private key that controls a given address. The returned private key can be added to a user
-with [`avm.importKey`](/reference/avalanchego/x-chain/api.md#avmimportkey).
+- `blockHeight` is the block height. It should be in `string` format.
+- `encoding` is the encoding format to use. Can be either `hex` or `json`. Defaults to `hex`.
-**Signature:**
+**Response:**
-```sh
-avm.exportKey({
- username: string,
- password: string,
- address: string
-}) -> {privateKey: string}
-```
+- `block` is the transaction encoded to `encoding`.
+- `encoding` is the `encoding`.
-- `username` must control `address`.
-- `privateKey` is the string representation of the private key that controls `address`.
+#### Hex Example
**Example Call:**
```sh
curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.exportKey",
- "params" :{
- "username":"myUsername",
- "password":"myPassword",
- "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "privateKey": "PrivateKey-2w4XiXxPfQK4TypYqnohRL8DRNTz9cGiGmwQ1zmgEqD9c9KWLq"
- }
-}
-```
-
-### `avm.getAddressTxs`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-Returns all transactions that change the balance of the given address. A transaction is said to
-change an address's balance if either is true:
-
-- A UTXO that the transaction consumes was at least partially owned by the address.
-- A UTXO that the transaction produces is at least partially owned by the address.
-
-:::tip
-Note: Indexing (`index-transactions`) must be enabled in the X-chain config.
-:::
-
-**Signature:**
-
-```sh
-avm.getAddressTxs({
- address: string,
- cursor: uint64, // optional, leave empty to get the first page
- assetID: string,
- pageSize: uint64 // optional, defaults to 1024
-}) -> {
- txIDs: []string,
- cursor: uint64,
-}
-```
-
-**Request Parameters:**
-
-- `address`: The address for which we're fetching related transactions
-- `assetID`: Only return transactions that changed the balance of this asset. Must be an ID or an
- alias for an asset.
-- `pageSize`: Number of items to return per page. Optional. Defaults to 1024.
-
-**Response Parameter:**
-
-- `txIDs`: List of transaction IDs that affected the balance of this address.
-- `cursor`: Page number or offset. Use this in request to get the next page.
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.getAddressTxs",
- "params" :{
- "address":"X-local1kpprmfpzzm5lxyene32f6lr7j0aj7gxsu6hp9y",
- "assetID":"AVAX",
- "pageSize":20
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "txIDs": ["SsJF7KKwxiUJkczygwmgLqo3XVRotmpKP8rMp74cpLuNLfwf6"],
- "cursor": "1"
- },
- "id": 1
-}
-```
-
-### `avm.getAllBalances`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-Get the balances of all assets controlled by a given address.
-
-**Signature:**
-
-```sh
-avm.getAllBalances({address:string}) -> {
- balances: []{
- asset: string,
- balance: int
- }
-}
-```
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.getAllBalances",
- "params" :{
- "address":"X-avax1c79e0dd0susp7dc8udq34jgk2yvve7hapvdyht"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "balances": [
- {
- "asset": "AVAX",
- "balance": "102"
- },
- {
- "asset": "2sdnziCz37Jov3QSNMXcFRGFJ1tgauaj6L7qfk7yUcRPfQMC79",
- "balance": "10000"
- }
- ]
- },
- "id": 1
-}
-```
-
-### `avm.getAssetDescription`
-
-Get information about an asset.
-
-**Signature:**
-
-```sh
-avm.getAssetDescription({assetID: string}) -> {
- assetId: string,
- name: string,
- symbol: string,
- denomination: int
-}
-```
-
-- `assetID` is the id of the asset for which the information is requested.
-- `name` is the asset’s human-readable, not necessarily unique name.
-- `symbol` is the asset’s symbol.
-- `denomination` determines how balances of this asset are displayed by user interfaces. If
- denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units
- of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as
- .100, etc.
-
-:::note
-
-The AssetID for AVAX differs depending on the network you are on.
-
-Mainnet: FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z
-
-Testnet: U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK
-
-For finding the `assetID` of other assets, this [info] might be useful.
-Also, `avm.getUTXOs` returns the `assetID` in its output.
-
-:::
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.getAssetDescription",
- "params" :{
- "assetID" :"FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
- "name": "Avalanche",
- "symbol": "AVAX",
- "denomination": "9"
- },
- "id": 1
-}`
-```
-
-### `avm.getBalance`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-Get the balance of an asset controlled by a given address.
-
-**Signature:**
-
-```sh
-avm.getBalance({
- address: string,
- assetID: string
-}) -> {balance: int}
-```
-
-- `address` owner of the asset
-- `assetID` id of the asset for which the balance is requested
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.getBalance",
- "params" :{
- "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "assetID": "2pYGetDWyKdHxpFxh2LHeoLNCH6H5vxxCxHQtFnnFaYxLsqtHC"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "balance": "299999999999900",
- "utxoIDs": [
- {
- "txID": "WPQdyLNqHfiEKp4zcCpayRHYDVYuh1hqs9c1RqgZXS4VPgdvo",
- "outputIndex": 1
- }
- ]
- }
-}
-```
-
-### `avm.getBlock`
-
-Returns the block with the given id.
-
-**Signature:**
-
-```sh
-avm.getBlock({
- blockID: string
- encoding: string // optional
-}) -> {
- block: string,
- encoding: string
-}
-```
-
-**Request:**
-
-- `blockID` is the block ID. It should be in cb58 format.
-- `encoding` is the encoding format to use. Can be either `hex` or `json`. Defaults to `hex`.
-
-**Response:**
-
-- `block` is the transaction encoded to `encoding`.
-- `encoding` is the `encoding`.
-
-#### Hex Example
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "avm.getBlock",
- "params": {
- "blockID": "tXJ4xwmR8soHE6DzRNMQPtiwQvuYsHn6eLLBzo2moDqBquqy6",
- "encoding": "hex"
- },
- "id": 1
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "block": "0x00000000002000000000641ad33ede17f652512193721df87994f783ec806bb5640c39ee73676caffcc3215e0651000000000049a80a000000010000000e0000000100000000000000000000000000000000000000000000000000000000000000000000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000002e1a2a3910000000000000000000000001000000015cf998275803a7277926912defdf177b2e97b0b400000001e0d825c5069a7336671dd27eaa5c7851d2cf449e7e1cdc469c5c9e5a953955950000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000008908223b680000000100000000000000005e45d02fcc9e585544008f1df7ae5c94bf7f0f2600000000641ad3b600000000642d48b60000005aedf802580000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000005aedf80258000000000000000000000001000000015cf998275803a7277926912defdf177b2e97b0b40000000b000000000000000000000001000000012892441ba9a160bcdc596dcd2cc3ad83c3493589000000010000000900000001adf2237a5fe2dfd906265e8e14274aa7a7b2ee60c66213110598ba34fb4824d74f7760321c0c8fb1e8d3c5e86909248e48a7ae02e641da5559351693a8a1939800286d4fa2",
- "encoding": "hex"
- },
- "id": 1
-}
-```
-
-### `avm.getBlockByHeight`
-
-Returns block at the given height.
-
-**Signature:**
-
-```sh
-avm.getBlockByHeight({
- height: string
- encoding: string // optional
-}) -> {
- block: string,
- encoding: string
-}
-```
-
-**Request:**
-
-- `blockHeight` is the block height. It should be in `string` format.
-- `encoding` is the encoding format to use. Can be either `hex` or `json`. Defaults to `hex`.
-
-**Response:**
-
-- `block` is the transaction encoded to `encoding`.
-- `encoding` is the `encoding`.
-
-#### Hex Example
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "avm.getBlockByHeight",
- "params": {
- "height": "275686313486",
- "encoding": "hex"
- },
- "id": 1
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "block": "0x00000000002000000000642f6739d4efcdd07e4d4919a7fc2020b8a0f081dd64c262aaace5a6dad22be0b55fec0700000000004db9e100000001000000110000000100000000000000000000000000000000000000000000000000000000000000000000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000005c6ece390000000000000000000000000100000001930ab7bf5018bfc6f9435c8b15ba2fe1e619c0230000000000000000ed5f38341e436e5d46e2bb00b45d62ae97d1b050c64bc634ae10626739e35c4b00000001c6dda861341665c3b555b46227fb5e56dc0a870c5482809349f04b00348af2a80000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000005c6edd7b40000000010000000000000001000000090000000178688f4d5055bd8733801f9b52793da885bef424c90526c18e4dd97f7514bf6f0c3d2a0e9a5ea8b761bc41902eb4902c34ef034c4d18c3db7c83c64ffeadd93600731676de",
- "encoding": "hex"
- },
- "id": 1
-}
-```
-
-### `avm.getHeight`
-
-Returns the height of the last accepted block.
-
-**Signature:**
-
-```sh
-avm.getHeight() ->
-{
- height: uint64,
-}
-```
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "avm.getHeight",
- "params": {},
- "id": 1
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "height": "5094088"
- },
- "id": 1
-}
-```
-
-### `avm.getTx`
-
-Returns the specified transaction. The `encoding` parameter sets the format of the returned
-transaction. Can be either `"hex"` or `"json"`. Defaults to `"hex"`.
-
-**Signature:**
-
-```sh
-avm.getTx({
- txID: string,
- encoding: string, //optional
-}) -> {
- tx: string,
- encoding: string,
-}
-```
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.getTx",
- "params" :{
- "txID":"2oJCbb8pfdxEHAf9A8CdN4Afj9VSR3xzyzNkf8tDv7aM1sfNFL",
- "encoding": "json"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "tx": {
- "unsignedTx": {
- "networkID": 1,
- "blockchainID": "2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM",
- "outputs": [],
- "inputs": [
- {
- "txID": "2jbZUvi6nHy3Pgmk8xcMpSg5cW6epkPqdKkHSCweb4eRXtq4k9",
- "outputIndex": 1,
- "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
- "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
- "input": {
- "amount": 2570382395,
- "signatureIndices": [0]
- }
- }
- ],
- "memo": "0x",
- "destinationChain": "11111111111111111111111111111111LpoYY",
- "exportedOutputs": [
- {
- "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
- "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
- "output": {
- "addresses": ["X-avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy"],
- "amount": 2569382395,
- "locktime": 0,
- "threshold": 1
- }
- }
- ]
- },
- "credentials": [
- {
- "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
- "credential": {
- "signatures": [
- "0x46ebcbcfbee3ece1fd15015204045cf3cb77f42c48d0201fc150341f91f086f177cfca8894ca9b4a0c55d6950218e4ea8c01d5c4aefb85cd7264b47bd57d224400"
- ]
- }
- }
- ],
- "id": "2oJCbb8pfdxEHAf9A8CdN4Afj9VSR3xzyzNkf8tDv7aM1sfNFL"
- },
- "encoding": "json"
- },
- "id": 1
-}
-```
-
-Where:
-
-- `credentials` is a list of this transaction's credentials. Each credential proves that this
- transaction's creator is allowed to consume one of this transaction's inputs. Each credential is a
- list of signatures.
-- `unsignedTx` is the non-signature portion of the transaction.
-- `networkID` is the ID of the network this transaction happened on. (Avalanche Mainnet is `1`.)
-- `blockchainID` is the ID of the blockchain this transaction happened on. (Avalanche Mainnet
- X-Chain is `2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM`.)
-- Each element of `outputs` is an output (UTXO) of this transaction that is not being exported to
- another chain.
-- Each element of `inputs` is an input of this transaction which has not been imported from another
- chain.
-- Import Transactions have additional fields `sourceChain` and `importedInputs`, which specify the
- blockchain ID that assets are being imported from, and the inputs that are being imported.
-- Export Transactions have additional fields `destinationChain` and `exportedOutputs`, which specify
- the blockchain ID that assets are being exported to, and the UTXOs that are being exported.
-
-An output contains:
-
-- `assetID`: The ID of the asset being transferred. (The Mainnet Avax ID is
- `FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z`.)
-- `fxID`: The ID of the FX this output uses.
-- `output`: The FX-specific contents of this output.
-
-Most outputs use the secp256k1 FX, look like this:
-
-```json
-{
- "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
- "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
- "output": {
- "addresses": ["X-avax126rd3w35xwkmj8670zvf7y5r8k36qa9z9803wm"],
- "amount": 1530084210,
- "locktime": 0,
- "threshold": 1
- }
-}
-```
-
-The above output can be consumed after Unix time `locktime` by a transaction that has signatures
-from `threshold` of the addresses in `addresses`.
-
-### `avm.getTxFee`
-
-Get the fees of the network.
-
-**Signature**:
-
-```
-avm.getTxFee() ->
-{
- txFee: uint64,
- createAssetTxFee: uint64,
-}
-```
-
-- `txFee` is the default fee for making transactions.
-- `createAssetTxFee` is the fee for creating a new asset.
-
-All fees are denominated in nAVAX.
-
-**Example Call**:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.getTxFee",
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response**:
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "txFee": "1000000",
- "createAssetTxFee": "10000000"
- }
-}
-```
-
-### `avm.getTxStatus`
-
-:::caution
-Deprecated as of **v1.10.0**.
-:::
-
-Get the status of a transaction sent to the network.
-
-**Signature:**
-
-```sh
-avm.getTxStatus({txID: string}) -> {status: string}
-```
-
-`status` is one of:
-
-- `Accepted`: The transaction is (or will be) accepted by every node
-- `Processing`: The transaction is being voted on by this node
-- `Rejected`: The transaction will never be accepted by any node in the network
-- `Unknown`: The transaction hasn’t been seen by this node
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.getTxStatus",
- "params" :{
- "txID":"2QouvFWUbjuySRxeX5xMbNCuAaKWfbk5FeEa2JmoF85RKLk2dD"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "status": "Accepted"
- }
-}
-```
-
-### `avm.getUTXOs`
-
-Gets the UTXOs that reference a given address. If `sourceChain` is specified, then it will retrieve
-the atomic UTXOs exported from that chain to the X Chain.
-
-**Signature:**
-
-```sh
-avm.getUTXOs({
- addresses: []string,
- limit: int, //optional
- startIndex: { //optional
- address: string,
- utxo: string
- },
- sourceChain: string, //optional
- encoding: string //optional
-}) -> {
- numFetched: int,
- utxos: []string,
- endIndex: {
- address: string,
- utxo: string
- },
- sourceChain: string, //optional
- encoding: string
-}
-```
-
-- `utxos` is a list of UTXOs such that each UTXO references at least one address in `addresses`.
-- At most `limit` UTXOs are returned. If `limit` is omitted or greater than 1024, it is set to 1024.
-- This method supports pagination. `endIndex` denotes the last UTXO returned. To get the next set of
- UTXOs, use the value of `endIndex` as `startIndex` in the next call.
-- If `startIndex` is omitted, will fetch all UTXOs up to `limit`.
-- When using pagination (when `startIndex` is provided), UTXOs are not guaranteed to be unique
- across multiple calls. That is, a UTXO may appear in the result of the first call, and then again
- in the second call.
-- When using pagination, consistency is not guaranteed across multiple calls. That is, the UTXO set
- of the addresses may have changed between calls.
-- `encoding` sets the format for the returned UTXOs. Can only be `hex` when a value is provided.
-
-#### **Example**
-
-Suppose we want all UTXOs that reference at least one of
-`X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5` and `X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6`.
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.getUTXOs",
- "params" :{
- "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", "X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6"],
- "limit":5,
- "encoding": "hex"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-This gives response:
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "numFetched": "5",
- "utxos": [
- "0x0000a195046108a85e60f7a864bb567745a37f50c6af282103e47cc62f036cee404700000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216c1f01765",
- "0x0000ae8b1b94444eed8de9a81b1222f00f1b4133330add23d8ac288bffa98b85271100000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216473d042a",
- "0x0000731ce04b1feefa9f4291d869adc30a33463f315491e164d89be7d6d2d7890cfc00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21600dd3047",
- "0x0000b462030cc4734f24c0bc224cf0d16ee452ea6b67615517caffead123ab4fbf1500000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216c71b387e",
- "0x000054f6826c39bc957c0c6d44b70f961a994898999179cc32d21eb09c1908d7167b00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f2166290e79d"
- ],
- "endIndex": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "utxo": "kbUThAUfmBXUmRgTpgD6r3nLj7rJUGho6xyht5nouNNypH45j"
- },
- "encoding": "hex"
- },
- "id": 1
-}
-```
-
-Since `numFetched` is the same as `limit`, we can tell that there may be more UTXOs that were not
-fetched. We call the method again, this time with `startIndex`:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :2,
- "method" :"avm.getUTXOs",
- "params" :{
- "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "limit":5,
- "startIndex": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "utxo": "kbUThAUfmBXUmRgTpgD6r3nLj7rJUGho6xyht5nouNNypH45j"
- },
- "encoding": "hex"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-This gives response:
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "numFetched": "4",
- "utxos": [
- "0x000020e182dd51ee4dcd31909fddd75bb3438d9431f8e4efce86a88a684f5c7fa09300000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21662861d59",
- "0x0000a71ba36c475c18eb65dc90f6e85c4fd4a462d51c5de3ac2cbddf47db4d99284e00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21665f6f83f",
- "0x0000925424f61cb13e0fbdecc66e1270de68de9667b85baa3fdc84741d048daa69fa00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216afecf76a",
- "0x000082f30327514f819da6009fad92b5dba24d27db01e29ad7541aa8e6b6b554615c00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216779c2d59"
- ],
- "endIndex": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "utxo": "21jG2RfqyHUUgkTLe2tUp6ETGLriSDTW3th8JXFbPRNiSZ11jK"
- },
- "encoding": "hex"
- },
- "id": 1
-}
-```
-
-Since `numFetched` is less than `limit`, we know that we are done fetching UTXOs and don’t need to
-call this method again.
-
-Suppose we want to fetch the UTXOs exported from the P Chain to the X Chain in order to build an
-ImportTx. Then we need to call GetUTXOs with the `sourceChain` argument in order to retrieve the
-atomic UTXOs:
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.getUTXOs",
- "params" :{
- "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", "X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6"],
- "limit":5,
- "sourceChain": "P",
- "encoding": "hex"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-This gives response:
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "numFetched": "1",
- "utxos": [
- "0x00001f989ffaf18a18a59bdfbf209342aa61c6a62a67e8639d02bb3c8ddab315c6fa0000000039c33a499ce4c33a3b09cdd2cfa01ae70dbf2d18b2d7d168524440e55d550088000000070011c304cd7eb5c0000000000000000000000001000000013cb7d3842e8cee6a0ebd09f1fe884f6861e1b29c83497819"
- ],
- "endIndex": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "utxo": "2Sz2XwRYqUHwPeiKoRnZ6ht88YqzAF1SQjMYZQQaB5wBFkAqST"
+ "jsonrpc": "2.0",
+ "method": "avm.getBlockByHeight",
+ "params": {
+ "height": "275686313486",
+ "encoding": "hex"
},
- "encoding": "hex"
- },
- "id": 1
-}
-```
-
-### `avm.import`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Finalize a transfer of an asset from the P-Chain or C-Chain to the X-Chain.
-
-**Signature:**
-
-```sh
-avm.import({
- to: string,
- sourceChain: string,
- username: string,
- password: string,
-}) -> {txID: string}
-```
-
-- `to` is the address the AVAX is sent to. This must be the same as the `to` argument in the
- corresponding call to the P-Chain’s `exportAVAX` or C-Chain's `export`.
-- `sourceChain` is the ID or alias of the chain the AVAX is being imported from. To import funds
- from the C-Chain, use `"C"`.
-- `username` is the user that controls `to`.
-- `txID` is the ID of the newly created atomic transaction.
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.import",
- "params" :{
- "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "sourceChain":"C",
- "username":"myUsername",
- "password":"myPassword"
- }
+ "id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -1468,51 +523,34 @@ curl -X POST --data '{
{
"jsonrpc": "2.0",
"result": {
- "txID": "2gXpf4jFoMAWQ3rxBfavgFfSdLkL2eFUYprKsUQuEdB5H6Jo1H"
+ "block": "0x00000000002000000000642f6739d4efcdd07e4d4919a7fc2020b8a0f081dd64c262aaace5a6dad22be0b55fec0700000000004db9e100000001000000110000000100000000000000000000000000000000000000000000000000000000000000000000000121e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000070000005c6ece390000000000000000000000000100000001930ab7bf5018bfc6f9435c8b15ba2fe1e619c0230000000000000000ed5f38341e436e5d46e2bb00b45d62ae97d1b050c64bc634ae10626739e35c4b00000001c6dda861341665c3b555b46227fb5e56dc0a870c5482809349f04b00348af2a80000000021e67317cbc4be2aeb00677ad6462778a8f52274b9d605df2591b23027a87dff000000050000005c6edd7b40000000010000000000000001000000090000000178688f4d5055bd8733801f9b52793da885bef424c90526c18e4dd97f7514bf6f0c3d2a0e9a5ea8b761bc41902eb4902c34ef034c4d18c3db7c83c64ffeadd93600731676de",
+ "encoding": "hex"
},
"id": 1
}
```
-### `avm.importKey`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `avm.getHeight`
-Give a user control over an address by providing the private key that controls the address.
+Returns the height of the last accepted block.
**Signature:**
```sh
-avm.importKey({
- username: string,
- password: string,
- privateKey: string
-}) -> {address: string}
+avm.getHeight() ->
+{
+ height: uint64,
+}
```
-- Add `privateKey` to `username`‘s set of private keys. `address` is the address `username` now
- controls with the private key.
-
**Example Call:**
```sh
curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.importKey",
- "params" :{
- "username":"myUsername",
- "password":"myPassword",
- "privateKey":"PrivateKey-2w4XiXxPfQK4TypYqnohRL8DRNTz9cGiGmwQ1zmgEqD9c9KWLq"
- }
+ "jsonrpc": "2.0",
+ "method": "avm.getHeight",
+ "params": {},
+ "id": 1
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -1521,26 +559,27 @@ curl -X POST --data '{
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
- }
+ "height": "5094088"
+ },
+ "id": 1
}
```
-### `avm.issueTx`
+### `avm.getTx`
-Send a signed transaction to the network. `encoding` specifies the format of the signed transaction.
-Can only be `hex` when a value is provided.
+Returns the specified transaction. The `encoding` parameter sets the format of the returned
+transaction. Can be either `"hex"` or `"json"`. Defaults to `"hex"`.
**Signature:**
```sh
-avm.issueTx({
- tx: string,
+avm.getTx({
+ txID: string,
encoding: string, //optional
}) -> {
- txID: string
+ tx: string,
+ encoding: string,
}
```
@@ -1549,11 +588,11 @@ avm.issueTx({
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.issueTx",
+ "id" :1,
+ "method" :"avm.getTx",
"params" :{
- "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730",
- "encoding": "hex"
+ "txID":"2oJCbb8pfdxEHAf9A8CdN4Afj9VSR3xzyzNkf8tDv7aM1sfNFL",
+ "encoding": "json"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -1563,258 +602,161 @@ curl -X POST --data '{
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "txID": "NUPLwbt2hsYxpQg4H2o451hmTWQ4JZx2zMzM4SinwtHgAdX1JLPHXvWSXEnpecStLj"
- }
-}
-```
-
-### `avm.listAddresses`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-List addresses controlled by the given user.
-
-**Signature:**
-
-```sh
-avm.listAddresses({
- username: string,
- password: string
-}) -> {addresses: []string}
-```
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "avm.listAddresses",
- "params": {
- "username":"myUsername",
- "password":"myPassword"
+ "tx": {
+ "unsignedTx": {
+ "networkID": 1,
+ "blockchainID": "2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM",
+ "outputs": [],
+ "inputs": [
+ {
+ "txID": "2jbZUvi6nHy3Pgmk8xcMpSg5cW6epkPqdKkHSCweb4eRXtq4k9",
+ "outputIndex": 1,
+ "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
+ "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
+ "input": {
+ "amount": 2570382395,
+ "signatureIndices": [0]
+ }
+ }
+ ],
+ "memo": "0x",
+ "destinationChain": "11111111111111111111111111111111LpoYY",
+ "exportedOutputs": [
+ {
+ "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
+ "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
+ "output": {
+ "addresses": ["X-avax1tnuesf6cqwnjw7fxjyk7lhch0vhf0v95wj5jvy"],
+ "amount": 2569382395,
+ "locktime": 0,
+ "threshold": 1
+ }
+ }
+ ]
+ },
+ "credentials": [
+ {
+ "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
+ "credential": {
+ "signatures": [
+ "0x46ebcbcfbee3ece1fd15015204045cf3cb77f42c48d0201fc150341f91f086f177cfca8894ca9b4a0c55d6950218e4ea8c01d5c4aefb85cd7264b47bd57d224400"
+ ]
+ }
+ }
+ ],
+ "id": "2oJCbb8pfdxEHAf9A8CdN4Afj9VSR3xzyzNkf8tDv7aM1sfNFL"
},
- "id": 1
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "addresses": ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"]
+ "encoding": "json"
},
"id": 1
}
```
-### `avm.mint`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Mint units of a variable-cap asset created with
-[`avm.createVariableCapAsset`](/reference/avalanchego/x-chain/api.md#avmcreatevariablecapasset).
-
-**Signature:**
-
-```sh
-avm.mint({
- amount: int,
- assetID: string,
- to: string,
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) ->
-{
- txID: string,
- changeAddr: string,
-}
-```
+Where:
-- `amount` units of `assetID` will be created and controlled by address `to`.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- `username` is the user that pays the transaction fee. `username` must hold keys giving it
- permission to mint more of this asset. That is, it must control at least _threshold_ keys for one
- of the minter sets.
-- `txID` is this transaction’s ID.
-- `changeAddr` in the result is the address where any change was sent.
+- `credentials` is a list of this transaction's credentials. Each credential proves that this
+ transaction's creator is allowed to consume one of this transaction's inputs. Each credential is a
+ list of signatures.
+- `unsignedTx` is the non-signature portion of the transaction.
+- `networkID` is the ID of the network this transaction happened on. (Avalanche Mainnet is `1`.)
+- `blockchainID` is the ID of the blockchain this transaction happened on. (Avalanche Mainnet
+ X-Chain is `2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM`.)
+- Each element of `outputs` is an output (UTXO) of this transaction that is not being exported to
+ another chain.
+- Each element of `inputs` is an input of this transaction which has not been imported from another
+ chain.
+- Import Transactions have additional fields `sourceChain` and `importedInputs`, which specify the
+ blockchain ID that assets are being imported from, and the inputs that are being imported.
+- Export Transactions have additional fields `destinationChain` and `exportedOutputs`, which specify
+ the blockchain ID that assets are being exported to, and the UTXOs that are being exported.
-**Example Call:**
+An output contains:
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" : 1,
- "method" :"avm.mint",
- "params" :{
- "amount":10000000,
- "assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2",
- "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
-```
+- `assetID`: The ID of the asset being transferred. (The Mainnet Avax ID is
+ `FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z`.)
+- `fxID`: The ID of the FX this output uses.
+- `output`: The FX-specific contents of this output.
-**Example Response:**
+Most outputs use the secp256k1 FX, look like this:
```json
{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "txID": "2oGdPdfw2qcNUHeqjw8sU2hPVrFyNUTgn6A8HenDra7oLCDtja",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "assetID": "FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z",
+ "fxID": "spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ",
+ "output": {
+ "addresses": ["X-avax126rd3w35xwkmj8670zvf7y5r8k36qa9z9803wm"],
+ "amount": 1530084210,
+ "locktime": 0,
+ "threshold": 1
}
}
```
-### `avm.mintNFT`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
+The above output can be consumed after Unix time `locktime` by a transaction that has signatures
+from `threshold` of the addresses in `addresses`.
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `avm.getTxFee`
-Mint non-fungible tokens which were created with
-[`avm.createNFTAsset`](/reference/avalanchego/x-chain/api.md#avmcreatenftasset).
+Get the fees of the network.
-**Signature:**
+**Signature**:
-```sh
-avm.mintNFT({
- assetID: string,
- payload: string,
- to: string,
- encoding: string, //optional
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) ->
+```
+avm.getTxFee() ->
{
- txID: string,
- changeAddr: string,
+ txFee: uint64,
+ createAssetTxFee: uint64,
}
```
-- `assetID` is the assetID of the newly created NFT asset.
-- `payload` is an arbitrary payload of up to 1024 bytes. Its encoding format is specified by the
- `encoding` argument.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- `username` is the user that pays the transaction fee. `username` must hold keys giving it
- permission to mint more of this asset. That is, it must control at least _threshold_ keys for one
- of the minter sets.
-- `txID` is this transaction’s ID.
-- `changeAddr` in the result is the address where any change was sent.
-- `encoding` is the encoding format to use for the payload argument. Can only be `hex` when a value
- is provided.
+- `txFee` is the default fee for making transactions.
+- `createAssetTxFee` is the fee for creating a new asset.
+
+All fees are denominated in nAVAX.
-**Example Call:**
+**Example Call**:
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
"id" : 1,
- "method" :"avm.mintNFT",
- "params" :{
- "assetID":"2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP",
- "payload":"0x415641204c61627338259aed",
- "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username":"myUsername",
- "password":"myPassword"
- }
+ "method" :"avm.getTxFee",
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
-**Example Response:**
+**Example Response**:
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "txID": "2oGdPdfw2qcNUHeqjw8sU2hPVrFyNUTgn6A8HenDra7oLCDtja",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "txFee": "1000000",
+ "createAssetTxFee": "10000000"
}
}
```
-### `avm.send`
+### `avm.getTxStatus`
:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
+Deprecated as of **v1.10.0**.
:::
-Send a quantity of an asset to an address.
+Get the status of a transaction sent to the network.
**Signature:**
```sh
-avm.send({
- amount: int,
- assetID: string,
- to: string,
- memo: string, //optional
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) -> {txID: string, changeAddr: string}
+avm.getTxStatus({txID: string}) -> {status: string}
```
-- Sends `amount` units of asset with ID `assetID` to address `to`. `amount` is denominated in the
- smallest increment of the asset. For AVAX this is 1 nAVAX (one billionth of 1 AVAX.)
-- `to` is the X-Chain address the asset is sent to.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- You can attach a `memo`, whose length can be up to 256 bytes.
-- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to
- hold at least the balance of the asset being sent.)
+`status` is one of:
+
+- `Accepted`: The transaction is (or will be) accepted by every node
+- `Processing`: The transaction is being voted on by this node
+- `Rejected`: The transaction will never be accepted by any node in the network
+- `Unknown`: The transaction hasn’t been seen by this node
**Example Call:**
@@ -1822,16 +764,9 @@ avm.send({
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
- "method" :"avm.send",
+ "method" :"avm.getTxStatus",
"params" :{
- "assetID" : "AVAX",
- "amount" : 10000,
- "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "memo" : "hi, mom!",
- "username" : "userThatControlsAtLeast10000OfThisAsset",
- "password" : "myPassword"
+ "txID":"2QouvFWUbjuySRxeX5xMbNCuAaKWfbk5FeEa2JmoF85RKLk2dD"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
@@ -1843,280 +778,206 @@ curl -X POST --data '{
"jsonrpc": "2.0",
"id": 1,
"result": {
- "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "status": "Accepted"
}
}
```
-### `avm.sendMultiple`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `avm.getUTXOs`
-Sends multiple transfers of `amount` of `assetID`, to a specified address from a list of owned
-addresses.
+Gets the UTXOs that reference a given address. If `sourceChain` is specified, then it will retrieve
+the atomic UTXOs exported from that chain to the X Chain.
**Signature:**
```sh
-avm.sendMultiple({
- outputs: []{
- assetID: string,
- amount: int,
- to: string
+avm.getUTXOs({
+ addresses: []string,
+ limit: int, //optional
+ startIndex: { //optional
+ address: string,
+ utxo: string
},
- from: []string, //optional
- changeAddr: string, //optional
- memo: string, //optional
- username: string,
- password: string
-}) -> {txID: string, changeAddr: string}
+ sourceChain: string, //optional
+ encoding: string //optional
+}) -> {
+ numFetched: int,
+ utxos: []string,
+ endIndex: {
+ address: string,
+ utxo: string
+ },
+ sourceChain: string, //optional
+ encoding: string
+}
```
-- `outputs` is an array of object literals which each contain an `assetID`, `amount` and `to`.
-- `memo` is an optional message, whose length can be up to 256 bytes.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to
- hold at least the balance of the asset being sent.)
+- `utxos` is a list of UTXOs such that each UTXO references at least one address in `addresses`.
+- At most `limit` UTXOs are returned. If `limit` is omitted or greater than 1024, it is set to 1024.
+- This method supports pagination. `endIndex` denotes the last UTXO returned. To get the next set of
+ UTXOs, use the value of `endIndex` as `startIndex` in the next call.
+- If `startIndex` is omitted, will fetch all UTXOs up to `limit`.
+- When using pagination (when `startIndex` is provided), UTXOs are not guaranteed to be unique
+ across multiple calls. That is, a UTXO may appear in the result of the first call, and then again
+ in the second call.
+- When using pagination, consistency is not guaranteed across multiple calls. That is, the UTXO set
+ of the addresses may have changed between calls.
+- `encoding` sets the format for the returned UTXOs. Can only be `hex` when a value is provided.
+
+#### **Example**
-**Example Call:**
+Suppose we want all UTXOs that reference at least one of
+`X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5` and `X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6`.
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
- "method" :"avm.sendMultiple",
+ "method" :"avm.getUTXOs",
"params" :{
- "outputs": [
- {
- "assetID" : "AVAX",
- "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "amount" : 1000000000
- },
- {
- "assetID" : "26aqSTpZuWDAVtRmo44fjCx4zW6PDEx3zy9Qtp2ts1MuMFn9FB",
- "to" : "X-avax18knvhxx8uhc0mwlgrfyzjcm2wrd6e60w37xrjq",
- "amount" : 10
- }
- ],
- "memo" : "hi, mom!",
- "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username" : "username",
- "password" : "myPassword"
+ "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", "X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6"],
+ "limit":5,
+ "encoding": "hex"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
-**Example Response:**
+This gives response:
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
- }
+ "numFetched": "5",
+ "utxos": [
+ "0x0000a195046108a85e60f7a864bb567745a37f50c6af282103e47cc62f036cee404700000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216c1f01765",
+ "0x0000ae8b1b94444eed8de9a81b1222f00f1b4133330add23d8ac288bffa98b85271100000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216473d042a",
+ "0x0000731ce04b1feefa9f4291d869adc30a33463f315491e164d89be7d6d2d7890cfc00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21600dd3047",
+ "0x0000b462030cc4734f24c0bc224cf0d16ee452ea6b67615517caffead123ab4fbf1500000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216c71b387e",
+ "0x000054f6826c39bc957c0c6d44b70f961a994898999179cc32d21eb09c1908d7167b00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f2166290e79d"
+ ],
+ "endIndex": {
+ "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
+ "utxo": "kbUThAUfmBXUmRgTpgD6r3nLj7rJUGho6xyht5nouNNypH45j"
+ },
+ "encoding": "hex"
+ },
+ "id": 1
}
```
-### `avm.sendNFT`
-
-:::caution
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Send a non-fungible token.
-
-**Signature:**
-
-```sh
-avm.sendNFT({
- assetID: string,
- groupID: number,
- to: string,
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) -> {txID: string}
-```
-
-- `assetID` is the asset ID of the NFT being sent.
-- `groupID` is the NFT group from which to send the NFT. NFT creation allows multiple groups under
- each NFT ID. You can issue multiple NFTs to each group.
-- `to` is the X-Chain address the NFT is sent to.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed. `changeAddr` is the address any change will be sent to. If omitted, change is
- sent to one of the addresses controlled by the user.
-- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to
- hold at least the balance of the NFT being sent.)
-
-**Example Call:**
+Since `numFetched` is the same as `limit`, we can tell that there may be more UTXOs that were not
+fetched. We call the method again, this time with `startIndex`:
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" :1,
- "method" :"avm.sendNFT",
+ "id" :2,
+ "method" :"avm.getUTXOs",
"params" :{
- "assetID" : "2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP",
- "groupID" : 0,
- "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username" : "myUsername",
- "password" : "myPassword"
+ "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
+ "limit":5,
+ "startIndex": {
+ "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
+ "utxo": "kbUThAUfmBXUmRgTpgD6r3nLj7rJUGho6xyht5nouNNypH45j"
+ },
+ "encoding": "hex"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
-**Example Response:**
+This gives response:
```json
{
"jsonrpc": "2.0",
"result": {
- "txID": "DoR2UtG1Trd3Q8gWXVevNxD666Q3DPqSFmBSMPQ9dWTV8Qtuy",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "numFetched": "4",
+ "utxos": [
+ "0x000020e182dd51ee4dcd31909fddd75bb3438d9431f8e4efce86a88a684f5c7fa09300000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21662861d59",
+ "0x0000a71ba36c475c18eb65dc90f6e85c4fd4a462d51c5de3ac2cbddf47db4d99284e00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f21665f6f83f",
+ "0x0000925424f61cb13e0fbdecc66e1270de68de9667b85baa3fdc84741d048daa69fa00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216afecf76a",
+ "0x000082f30327514f819da6009fad92b5dba24d27db01e29ad7541aa8e6b6b554615c00000000345aa98e8a990f4101e2268fab4c4e1f731c8dfbcffa3a77978686e6390d624f000000070000000000000001000000000000000000000001000000018ba98dabaebcd83056799841cfbc567d8b10f216779c2d59"
+ ],
+ "endIndex": {
+ "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
+ "utxo": "21jG2RfqyHUUgkTLe2tUp6ETGLriSDTW3th8JXFbPRNiSZ11jK"
+ },
+ "encoding": "hex"
},
"id": 1
}
```
-### `wallet.issueTx`
-
-Send a signed transaction to the network and assume the TX will be accepted. `encoding` specifies
-the format of the signed transaction. Can only be `hex` when a value is provided.
-
-This call is made to the wallet API endpoint:
-
-`/ext/bc/X/wallet`
-
-:::caution
-
-Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-:::
-
-**Signature:**
-
-```sh
-wallet.issueTx({
- tx: string,
- encoding: string, //optional
-}) -> {
- txID: string
-}
-```
+Since `numFetched` is less than `limit`, we know that we are done fetching UTXOs and don’t need to
+call this method again.
-**Example Call:**
+Suppose we want to fetch the UTXOs exported from the P Chain to the X Chain in order to build an
+ImportTx. Then we need to call GetUTXOs with the `sourceChain` argument in order to retrieve the
+atomic UTXOs:
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" : 1,
- "method" :"wallet.issueTx",
+ "id" :1,
+ "method" :"avm.getUTXOs",
"params" :{
- "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730",
+ "addresses":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", "X-avax1d09qn852zcy03sfc9hay2llmn9hsgnw4tp3dv6"],
+ "limit":5,
+ "sourceChain": "P",
"encoding": "hex"
}
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X/wallet
+}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
-**Example Response:**
+This gives response:
```json
{
"jsonrpc": "2.0",
- "id": 1,
"result": {
- "txID": "NUPLwbt2hsYxpQg4H2o451hmTWQ4JZx2zMzM4SinwtHgAdX1JLPHXvWSXEnpecStLj"
- }
+ "numFetched": "1",
+ "utxos": [
+ "0x00001f989ffaf18a18a59bdfbf209342aa61c6a62a67e8639d02bb3c8ddab315c6fa0000000039c33a499ce4c33a3b09cdd2cfa01ae70dbf2d18b2d7d168524440e55d550088000000070011c304cd7eb5c0000000000000000000000001000000013cb7d3842e8cee6a0ebd09f1fe884f6861e1b29c83497819"
+ ],
+ "endIndex": {
+ "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
+ "utxo": "2Sz2XwRYqUHwPeiKoRnZ6ht88YqzAF1SQjMYZQQaB5wBFkAqST"
+ },
+ "encoding": "hex"
+ },
+ "id": 1
}
```
-### `wallet.send`
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
-
-Send a quantity of an asset to an address and assume the TX will be accepted so that future calls
-can use the modified UTXO set.
-
-This call is made to the wallet API endpoint:
-
-`/ext/bc/X/wallet`
-
-:::caution
-
-Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
+### `avm.issueTx`
-:::
+Send a signed transaction to the network. `encoding` specifies the format of the signed transaction.
+Can only be `hex` when a value is provided.
**Signature:**
```sh
-wallet.send({
- amount: int,
- assetID: string,
- to: string,
- memo: string, //optional
- from: []string, //optional
- changeAddr: string, //optional
- username: string,
- password: string
-}) -> {txID: string, changeAddr: string}
+avm.issueTx({
+ tx: string,
+ encoding: string, //optional
+}) -> {
+ txID: string
+}
```
-- Sends `amount` units of asset with ID `assetID` to address `to`. `amount` is denominated in the
- smallest increment of the asset. For AVAX this is 1 nAVAX (one billionth of 1 AVAX.)
-- `to` is the X-Chain address the asset is sent to.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- You can attach a `memo`, whose length can be up to 256 bytes.
-- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to
- hold at least the balance of the asset being sent.)
-
**Example Call:**
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" :1,
- "method" :"wallet.send",
+ "id" : 1,
+ "method" :"avm.issueTx",
"params" :{
- "assetID" : "AVAX",
- "amount" : 10000,
- "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "memo" : "hi, mom!",
- "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username" : "userThatControlsAtLeast10000OfThisAsset",
- "password" : "myPassword"
+ "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730",
+ "encoding": "hex"
}
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X/wallet
+}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
```
**Example Response:**
@@ -2126,20 +987,15 @@ curl -X POST --data '{
"jsonrpc": "2.0",
"id": 1,
"result": {
- "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "txID": "NUPLwbt2hsYxpQg4H2o451hmTWQ4JZx2zMzM4SinwtHgAdX1JLPHXvWSXEnpecStLj"
}
}
```
-### `wallet.sendMultiple`
-
-:::warning
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/reference/avalanchego/keystore-api.md).
-:::
+### `wallet.issueTx`
-Send multiple transfers of `amount` of `assetID`, to a specified address from a list of owned of
-addresses and assume the TX will be accepted so that future calls can use the modified UTXO set.
+Send a signed transaction to the network and assume the TX will be accepted. `encoding` specifies
+the format of the signed transaction. Can only be `hex` when a value is provided.
This call is made to the wallet API endpoint:
@@ -2154,54 +1010,24 @@ Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/
**Signature:**
```sh
-wallet.sendMultiple({
- outputs: []{
- assetID: string,
- amount: int,
- to: string
- },
- from: []string, //optional
- changeAddr: string, //optional
- memo: string, //optional
- username: string,
- password: string
-}) -> {txID: string, changeAddr: string}
+wallet.issueTx({
+ tx: string,
+ encoding: string, //optional
+}) -> {
+ txID: string
+}
```
-- `outputs` is an array of object literals which each contain an `assetID`, `amount` and `to`.
-- `from` are the addresses that you want to use for this operation. If omitted, uses any of your
- addresses as needed.
-- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the
- addresses controlled by the user.
-- You can attach a `memo`, whose length can be up to 256 bytes.
-- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to
- hold at least the balance of the asset being sent.)
-
**Example Call:**
```sh
curl -X POST --data '{
"jsonrpc":"2.0",
- "id" :1,
- "method" :"wallet.sendMultiple",
+ "id" : 1,
+ "method" :"wallet.issueTx",
"params" :{
- "outputs": [
- {
- "assetID" : "AVAX",
- "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5",
- "amount" : 1000000000
- },
- {
- "assetID" : "26aqSTpZuWDAVtRmo44fjCx4zW6PDEx3zy9Qtp2ts1MuMFn9FB",
- "to" : "X-avax18knvhxx8uhc0mwlgrfyzjcm2wrd6e60w37xrjq",
- "amount" : 10
- }
- ],
- "memo" : "hi, mom!",
- "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"],
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
- "username" : "username",
- "password" : "myPassword"
+ "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730",
+ "encoding": "hex"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X/wallet
```
@@ -2213,8 +1039,7 @@ curl -X POST --data '{
"jsonrpc": "2.0",
"id": 1,
"result": {
- "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1",
- "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
+ "txID": "NUPLwbt2hsYxpQg4H2o451hmTWQ4JZx2zMzM4SinwtHgAdX1JLPHXvWSXEnpecStLj"
}
}
```
diff --git a/vms/avm/service_test.go b/vms/avm/service_test.go
index 337956d48e5e..2873fa9ad67b 100644
--- a/vms/avm/service_test.go
+++ b/vms/avm/service_test.go
@@ -31,7 +31,6 @@ import (
"github.com/ava-labs/avalanchego/utils/units"
"github.com/ava-labs/avalanchego/vms/avm/block"
"github.com/ava-labs/avalanchego/vms/avm/block/executor/executormock"
- "github.com/ava-labs/avalanchego/vms/avm/config"
"github.com/ava-labs/avalanchego/vms/avm/state/statemock"
"github.com/ava-labs/avalanchego/vms/avm/txs"
"github.com/ava-labs/avalanchego/vms/components/avax"
@@ -2341,550 +2340,6 @@ func TestGetBalance(t *testing.T) {
require.Equal(startBalance, uint64(reply.Balance))
}
-func TestCreateFixedCapAsset(t *testing.T) {
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- reply := AssetIDChangeAddr{}
- addrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address())
- require.NoError(err)
-
- changeAddrStr, err := env.vm.FormatLocalAddress(testChangeAddr)
- require.NoError(err)
- _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
-
- require.NoError(service.CreateFixedCapAsset(nil, &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- Name: "testAsset",
- Symbol: "TEST",
- Denomination: 1,
- InitialHolders: []*Holder{{
- Amount: 123456789,
- Address: addrStr,
- }},
- }, &reply))
- require.Equal(changeAddrStr, reply.ChangeAddr)
- })
- }
-}
-
-func TestCreateVariableCapAsset(t *testing.T) {
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- reply := AssetIDChangeAddr{}
- minterAddrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address())
- require.NoError(err)
- _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
- changeAddrStr := fromAddrsStr[0]
-
- require.NoError(service.CreateVariableCapAsset(nil, &CreateAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- Name: "test asset",
- Symbol: "TEST",
- MinterSets: []Owners{
- {
- Threshold: 1,
- Minters: []string{
- minterAddrStr,
- },
- },
- },
- }, &reply))
- require.Equal(changeAddrStr, reply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, reply.AssetID)
-
- createdAssetID := reply.AssetID.String()
- // Test minting of the created variable cap asset
- mintArgs := &MintArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- Amount: 200,
- AssetID: createdAssetID,
- To: minterAddrStr, // Send newly minted tokens to this address
- }
- mintReply := &api.JSONTxIDChangeAddr{}
- require.NoError(service.Mint(nil, mintArgs, mintReply))
- require.Equal(changeAddrStr, mintReply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, mintReply.TxID)
-
- sendArgs := &SendArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: []string{minterAddrStr}},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- SendOutput: SendOutput{
- Amount: 200,
- AssetID: createdAssetID,
- To: fromAddrsStr[0],
- },
- }
- sendReply := &api.JSONTxIDChangeAddr{}
- require.NoError(service.Send(nil, sendArgs, sendReply))
- require.Equal(changeAddrStr, sendReply.ChangeAddr)
- })
- }
-}
-
-func TestNFTWorkflow(t *testing.T) {
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- fromAddrs, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
-
- // Test minting of the created variable cap asset
- addrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address())
- require.NoError(err)
-
- createArgs := &CreateNFTAssetArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: fromAddrsStr[0]},
- },
- Name: "BIG COIN",
- Symbol: "COIN",
- MinterSets: []Owners{
- {
- Threshold: 1,
- Minters: []string{
- addrStr,
- },
- },
- },
- }
- createReply := &AssetIDChangeAddr{}
- require.NoError(service.CreateNFTAsset(nil, createArgs, createReply))
- require.Equal(fromAddrsStr[0], createReply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, createReply.AssetID)
-
- // Key: Address
- // Value: AVAX balance
- balances := map[ids.ShortID]uint64{}
- for _, addr := range addrs { // get balances for all addresses
- addrStr, err := env.vm.FormatLocalAddress(addr)
- require.NoError(err)
-
- reply := &GetBalanceReply{}
- require.NoError(service.GetBalance(nil,
- &GetBalanceArgs{
- Address: addrStr,
- AssetID: env.vm.feeAssetID.String(),
- },
- reply,
- ))
-
- balances[addr] = uint64(reply.Balance)
- }
-
- fromAddrsTotalBalance := uint64(0)
- for _, addr := range fromAddrs {
- fromAddrsTotalBalance += balances[addr]
- }
-
- fromAddrsStartBalance := startBalance * uint64(len(fromAddrs))
- require.Equal(fromAddrsStartBalance-env.vm.TxFee, fromAddrsTotalBalance)
-
- assetID := createReply.AssetID
- payload, err := formatting.Encode(formatting.Hex, []byte{1, 2, 3, 4, 5})
- require.NoError(err)
- mintArgs := &MintNFTArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: fromAddrsStr[0]},
- },
- AssetID: assetID.String(),
- Payload: payload,
- To: addrStr,
- Encoding: formatting.Hex,
- }
- mintReply := &api.JSONTxIDChangeAddr{}
-
- require.NoError(service.MintNFT(nil, mintArgs, mintReply))
- require.Equal(fromAddrsStr[0], createReply.ChangeAddr)
-
- // Accept the transaction so that we can send the newly minted NFT
- buildAndAccept(require, env.vm, env.issuer, mintReply.TxID)
-
- sendArgs := &SendNFTArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: fromAddrsStr[0]},
- },
- AssetID: assetID.String(),
- GroupID: 0,
- To: addrStr,
- }
- sendReply := &api.JSONTxIDChangeAddr{}
- require.NoError(service.SendNFT(nil, sendArgs, sendReply))
- require.Equal(fromAddrsStr[0], sendReply.ChangeAddr)
- })
- }
-}
-
-func TestImportExportKey(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- sk, err := secp256k1.NewPrivateKey()
- require.NoError(err)
-
- importArgs := &ImportKeyArgs{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- PrivateKey: sk,
- }
- importReply := &api.JSONAddress{}
- require.NoError(service.ImportKey(nil, importArgs, importReply))
-
- addrStr, err := env.vm.FormatLocalAddress(sk.PublicKey().Address())
- require.NoError(err)
- exportArgs := &ExportKeyArgs{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- Address: addrStr,
- }
- exportReply := &ExportKeyReply{}
- require.NoError(service.ExportKey(nil, exportArgs, exportReply))
- require.Equal(sk.Bytes(), exportReply.PrivateKey.Bytes())
-}
-
-func TestImportAVMKeyNoDuplicates(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- sk, err := secp256k1.NewPrivateKey()
- require.NoError(err)
- args := ImportKeyArgs{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- PrivateKey: sk,
- }
- reply := api.JSONAddress{}
- require.NoError(service.ImportKey(nil, &args, &reply))
-
- expectedAddress, err := env.vm.FormatLocalAddress(sk.PublicKey().Address())
- require.NoError(err)
-
- require.Equal(expectedAddress, reply.Address)
-
- reply2 := api.JSONAddress{}
- require.NoError(service.ImportKey(nil, &args, &reply2))
-
- require.Equal(expectedAddress, reply2.Address)
-
- addrsArgs := api.UserPass{
- Username: username,
- Password: password,
- }
- addrsReply := api.JSONAddresses{}
- require.NoError(service.ListAddresses(nil, &addrsArgs, &addrsReply))
-
- require.Len(addrsReply.Addresses, 1)
- require.Equal(expectedAddress, addrsReply.Addresses[0])
-}
-
-func TestSend(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- assetID := env.genesisTx.ID()
- addr := keys[0].PublicKey().Address()
-
- addrStr, err := env.vm.FormatLocalAddress(addr)
- require.NoError(err)
- changeAddrStr, err := env.vm.FormatLocalAddress(testChangeAddr)
- require.NoError(err)
- _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
-
- args := &SendArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- SendOutput: SendOutput{
- Amount: 500,
- AssetID: assetID.String(),
- To: addrStr,
- },
- }
- reply := &api.JSONTxIDChangeAddr{}
- require.NoError(service.Send(nil, args, reply))
- require.Equal(changeAddrStr, reply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, reply.TxID)
-}
-
-func TestSendMultiple(t *testing.T) {
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- vmStaticConfig: &config.Config{
- Upgrades: upgradetest.GetConfig(upgradetest.Durango),
- },
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- assetID := env.genesisTx.ID()
- addr := keys[0].PublicKey().Address()
-
- addrStr, err := env.vm.FormatLocalAddress(addr)
- require.NoError(err)
- changeAddrStr, err := env.vm.FormatLocalAddress(testChangeAddr)
- require.NoError(err)
- _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
-
- args := &SendMultipleArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- Outputs: []SendOutput{
- {
- Amount: 500,
- AssetID: assetID.String(),
- To: addrStr,
- },
- {
- Amount: 1000,
- AssetID: assetID.String(),
- To: addrStr,
- },
- },
- }
- reply := &api.JSONTxIDChangeAddr{}
- require.NoError(service.SendMultiple(nil, args, reply))
- require.Equal(changeAddrStr, reply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, reply.TxID)
- })
- }
-}
-
-func TestCreateAndListAddresses(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- createArgs := &api.UserPass{
- Username: username,
- Password: password,
- }
- createReply := &api.JSONAddress{}
-
- require.NoError(service.CreateAddress(nil, createArgs, createReply))
-
- newAddr := createReply.Address
-
- listArgs := &api.UserPass{
- Username: username,
- Password: password,
- }
- listReply := &api.JSONAddresses{}
-
- require.NoError(service.ListAddresses(nil, listArgs, listReply))
- require.Contains(listReply.Addresses, newAddr)
-}
-
-func TestImport(t *testing.T) {
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- require := require.New(t)
-
- env := setup(t, &envConfig{
- fork: upgradetest.Durango,
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- service := &Service{vm: env.vm}
- env.vm.ctx.Lock.Unlock()
-
- assetID := env.genesisTx.ID()
- addr0 := keys[0].PublicKey().Address()
-
- utxo := &avax.UTXO{
- UTXOID: avax.UTXOID{TxID: ids.Empty},
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: 7,
- OutputOwners: secp256k1fx.OutputOwners{
- Threshold: 1,
- Addrs: []ids.ShortID{addr0},
- },
- },
- }
- utxoBytes, err := env.vm.parser.Codec().Marshal(txs.CodecVersion, utxo)
- require.NoError(err)
-
- peerSharedMemory := env.sharedMemory.NewSharedMemory(constants.PlatformChainID)
- utxoID := utxo.InputID()
- require.NoError(peerSharedMemory.Apply(map[ids.ID]*atomic.Requests{
- env.vm.ctx.ChainID: {
- PutRequests: []*atomic.Element{{
- Key: utxoID[:],
- Value: utxoBytes,
- Traits: [][]byte{
- addr0.Bytes(),
- },
- }},
- },
- }))
-
- addrStr, err := env.vm.FormatLocalAddress(keys[0].PublicKey().Address())
- require.NoError(err)
- args := &ImportArgs{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- SourceChain: "P",
- To: addrStr,
- }
- reply := &api.JSONTxID{}
- require.NoError(service.Import(nil, args, reply))
- })
- }
-}
-
func TestServiceGetBlock(t *testing.T) {
ctrl := gomock.NewController(t)
diff --git a/vms/avm/static_service.go b/vms/avm/static_service.go
index 35a3554ef1d6..02ac78f0795e 100644
--- a/vms/avm/static_service.go
+++ b/vms/avm/static_service.go
@@ -68,6 +68,18 @@ type AssetDefinition struct {
Memo string `json:"memo"`
}
+// Holder describes how much an address owns of an asset
+type Holder struct {
+ Amount avajson.Uint64 `json:"amount"`
+ Address string `json:"address"`
+}
+
+// Owners describes who can perform an action
+type Owners struct {
+ Threshold avajson.Uint32 `json:"threshold"`
+ Minters []string `json:"minters"`
+}
+
// BuildGenesisReply is the reply from BuildGenesis
type BuildGenesisReply struct {
Bytes string `json:"bytes"`
diff --git a/vms/avm/vm.go b/vms/avm/vm.go
index 1026ba7d3de7..00b1fd3a71c4 100644
--- a/vms/avm/vm.go
+++ b/vms/avm/vm.go
@@ -38,8 +38,6 @@ import (
"github.com/ava-labs/avalanchego/vms/avm/utxo"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/components/index"
- "github.com/ava-labs/avalanchego/vms/components/keystore"
- "github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/vms/txs/mempool"
blockbuilder "github.com/ava-labs/avalanchego/vms/avm/block/builder"
@@ -577,54 +575,6 @@ func (vm *VM) initState(tx *txs.Tx) {
}
}
-// LoadUser returns:
-// 1) The UTXOs that reference one or more addresses controlled by the given user
-// 2) A keychain that contains this user's keys
-// If [addrsToUse] has positive length, returns UTXOs that reference one or more
-// addresses controlled by the given user that are also in [addrsToUse].
-func (vm *VM) LoadUser(
- username string,
- password string,
- addrsToUse set.Set[ids.ShortID],
-) (
- []*avax.UTXO,
- *secp256k1fx.Keychain,
- error,
-) {
- user, err := keystore.NewUserFromKeystore(vm.ctx.Keystore, username, password)
- if err != nil {
- return nil, nil, err
- }
- // Drop any potential error closing the database to report the original
- // error
- defer user.Close()
-
- kc, err := keystore.GetKeychain(user, addrsToUse)
- if err != nil {
- return nil, nil, err
- }
-
- utxos, err := avax.GetAllUTXOs(vm.state, kc.Addresses())
- if err != nil {
- return nil, nil, fmt.Errorf("problem retrieving user's UTXOs: %w", err)
- }
-
- return utxos, kc, user.Close()
-}
-
-// selectChangeAddr returns the change address to be used for [kc] when [changeAddr] is given
-// as the optional change address argument
-func (vm *VM) selectChangeAddr(defaultAddr ids.ShortID, changeAddr string) (ids.ShortID, error) {
- if changeAddr == "" {
- return defaultAddr, nil
- }
- addr, err := avax.ParseServiceAddress(vm, changeAddr)
- if err != nil {
- return ids.ShortID{}, fmt.Errorf("couldn't parse changeAddr: %w", err)
- }
- return addr, nil
-}
-
// lookupAssetID looks for an ID aliased by [asset] and if it fails
// attempts to parse [asset] into an ID
func (vm *VM) lookupAssetID(asset string) (ids.ID, error) {
diff --git a/vms/avm/vm_benchmark_test.go b/vms/avm/vm_benchmark_test.go
index 48725d72da2a..976913997df1 100644
--- a/vms/avm/vm_benchmark_test.go
+++ b/vms/avm/vm_benchmark_test.go
@@ -4,7 +4,6 @@
package avm
import (
- "fmt"
"math/rand"
"testing"
@@ -14,53 +13,9 @@ import (
"github.com/ava-labs/avalanchego/upgrade/upgradetest"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/components/avax"
- "github.com/ava-labs/avalanchego/vms/components/keystore"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
)
-func BenchmarkLoadUser(b *testing.B) {
- runLoadUserBenchmark := func(b *testing.B, numKeys int) {
- require := require.New(b)
-
- env := setup(b, &envConfig{
- fork: upgradetest.Latest,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- }},
- })
- defer env.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(env.vm.ctx.Keystore, username, password)
- require.NoError(err)
-
- keys, err := keystore.NewKeys(user, numKeys)
- require.NoError(err)
-
- b.ResetTimer()
-
- fromAddrs := set.Set[ids.ShortID]{}
- for n := 0; n < b.N; n++ {
- addrIndex := n % numKeys
- fromAddrs.Clear()
- fromAddrs.Add(keys[addrIndex].PublicKey().Address())
- _, _, err := env.vm.LoadUser(username, password, fromAddrs)
- require.NoError(err)
- }
-
- b.StopTimer()
-
- require.NoError(user.Close())
- }
-
- benchmarkSize := []int{10, 100, 1000, 5000}
- for _, numKeys := range benchmarkSize {
- b.Run(fmt.Sprintf("NumKeys=%d", numKeys), func(b *testing.B) {
- runLoadUserBenchmark(b, numKeys)
- })
- }
-}
-
// getAllUTXOsBenchmark is a helper func to benchmark the GetAllUTXOs depending on the size
func getAllUTXOsBenchmark(b *testing.B, utxoCount int, randSrc rand.Source) {
require := require.New(b)
diff --git a/vms/avm/wallet_client.go b/vms/avm/wallet_client.go
index 7f805fd7ba23..5501be39347f 100644
--- a/vms/avm/wallet_client.go
+++ b/vms/avm/wallet_client.go
@@ -11,7 +11,6 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/formatting"
- "github.com/ava-labs/avalanchego/utils/json"
"github.com/ava-labs/avalanchego/utils/rpc"
)
@@ -21,34 +20,6 @@ var _ WalletClient = (*client)(nil)
type WalletClient interface {
// IssueTx issues a transaction to a node and returns the TxID
IssueTx(ctx context.Context, tx []byte, options ...rpc.Option) (ids.ID, error)
- // Send [amount] of [assetID] to address [to]
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- Send(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- assetID string,
- to ids.ShortID,
- memo string,
- options ...rpc.Option,
- ) (ids.ID, error)
- // SendMultiple sends a transaction from [user] funding all [outputs]
- //
- // Deprecated: Transactions should be issued using the
- // `avalanchego/wallet/chain/x.Wallet` utility.
- SendMultiple(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- outputs []ClientSendOutput,
- memo string,
- options ...rpc.Option,
- ) (ids.ID, error)
}
// implementation of an AVM wallet client for interacting with avm managed wallet on [chain]
@@ -84,71 +55,3 @@ func (c *walletClient) IssueTx(ctx context.Context, txBytes []byte, options ...r
}, res, options...)
return res.TxID, err
}
-
-// ClientSendOutput specifies that [Amount] of asset [AssetID] be sent to [To]
-type ClientSendOutput struct {
- // The amount of funds to send
- Amount uint64
-
- // ID of the asset being sent
- AssetID string
-
- // Address of the recipient
- To ids.ShortID
-}
-
-func (c *walletClient) Send(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- amount uint64,
- assetID string,
- to ids.ShortID,
- memo string,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- err := c.requester.SendRequest(ctx, "wallet.send", &SendArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- SendOutput: SendOutput{
- Amount: json.Uint64(amount),
- AssetID: assetID,
- To: to.String(),
- },
- Memo: memo,
- }, res, options...)
- return res.TxID, err
-}
-
-func (c *walletClient) SendMultiple(
- ctx context.Context,
- user api.UserPass,
- from []ids.ShortID,
- changeAddr ids.ShortID,
- outputs []ClientSendOutput,
- memo string,
- options ...rpc.Option,
-) (ids.ID, error) {
- res := &api.JSONTxID{}
- serviceOutputs := make([]SendOutput, len(outputs))
- for i, output := range outputs {
- serviceOutputs[i].Amount = json.Uint64(output.Amount)
- serviceOutputs[i].AssetID = output.AssetID
- serviceOutputs[i].To = output.To.String()
- }
- err := c.requester.SendRequest(ctx, "wallet.sendMultiple", &SendMultipleArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: user,
- JSONFromAddrs: api.JSONFromAddrs{From: ids.ShortIDsToStrings(from)},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddr.String()},
- },
- Outputs: serviceOutputs,
- Memo: memo,
- }, res, options...)
- return res.TxID, err
-}
diff --git a/vms/avm/wallet_service.go b/vms/avm/wallet_service.go
index c5bf0ab00ea6..0ba59ece12a4 100644
--- a/vms/avm/wallet_service.go
+++ b/vms/avm/wallet_service.go
@@ -9,22 +9,16 @@ import (
"net/http"
"go.uber.org/zap"
- "golang.org/x/exp/maps"
"github.com/ava-labs/avalanchego/api"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/linked"
"github.com/ava-labs/avalanchego/utils/logging"
- "github.com/ava-labs/avalanchego/utils/math"
"github.com/ava-labs/avalanchego/vms/avm/txs"
- "github.com/ava-labs/avalanchego/vms/components/avax"
- "github.com/ava-labs/avalanchego/vms/secp256k1fx"
"github.com/ava-labs/avalanchego/vms/txs/mempool"
)
-var errMissingUTXO = errors.New("missing utxo")
-
type WalletService struct {
vm *VM
pendingTxs *linked.Hashmap[ids.ID, *txs.Tx]
@@ -98,35 +92,6 @@ func (w *WalletService) issue(tx *txs.Tx) (ids.ID, error) {
return txID, nil
}
-func (w *WalletService) update(utxos []*avax.UTXO) ([]*avax.UTXO, error) {
- utxoMap := make(map[ids.ID]*avax.UTXO, len(utxos))
- for _, utxo := range utxos {
- utxoMap[utxo.InputID()] = utxo
- }
-
- iter := w.pendingTxs.NewIterator()
-
- for iter.Next() {
- tx := iter.Value()
- for _, inputUTXO := range tx.Unsigned.InputUTXOs() {
- if inputUTXO.Symbolic() {
- continue
- }
- utxoID := inputUTXO.InputID()
- if _, exists := utxoMap[utxoID]; !exists {
- return nil, errMissingUTXO
- }
- delete(utxoMap, utxoID)
- }
-
- for _, utxo := range tx.UTXOs() {
- utxoMap[utxo.InputID()] = utxo
- }
- }
-
- return maps.Values(utxoMap), nil
-}
-
// IssueTx attempts to issue a transaction into consensus
func (w *WalletService) IssueTx(_ *http.Request, args *api.FormattedTx, reply *api.JSONTxID) error {
w.vm.ctx.Log.Warn("deprecated API called",
@@ -152,165 +117,3 @@ func (w *WalletService) IssueTx(_ *http.Request, args *api.FormattedTx, reply *a
reply.TxID = txID
return err
}
-
-// Send returns the ID of the newly created transaction
-func (w *WalletService) Send(r *http.Request, args *SendArgs, reply *api.JSONTxIDChangeAddr) error {
- return w.SendMultiple(r, &SendMultipleArgs{
- JSONSpendHeader: args.JSONSpendHeader,
- Outputs: []SendOutput{args.SendOutput},
- Memo: args.Memo,
- }, reply)
-}
-
-// SendMultiple sends a transaction with multiple outputs.
-func (w *WalletService) SendMultiple(_ *http.Request, args *SendMultipleArgs, reply *api.JSONTxIDChangeAddr) error {
- w.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "wallet"),
- zap.String("method", "sendMultiple"),
- logging.UserString("username", args.Username),
- )
-
- // Validate the memo field
- memoBytes := []byte(args.Memo)
- if l := len(memoBytes); l > avax.MaxMemoSize {
- return fmt.Errorf("max memo length is %d but provided memo field is length %d",
- avax.MaxMemoSize,
- l)
- } else if len(args.Outputs) == 0 {
- return errNoOutputs
- }
-
- // Parse the from addresses
- fromAddrs, err := avax.ParseServiceAddresses(w.vm, args.From)
- if err != nil {
- return fmt.Errorf("couldn't parse 'From' addresses: %w", err)
- }
-
- w.vm.ctx.Lock.Lock()
- defer w.vm.ctx.Lock.Unlock()
-
- // Load user's UTXOs/keys
- utxos, kc, err := w.vm.LoadUser(args.Username, args.Password, fromAddrs)
- if err != nil {
- return err
- }
-
- utxos, err = w.update(utxos)
- if err != nil {
- return err
- }
-
- // Parse the change address.
- if len(kc.Keys) == 0 {
- return errNoKeys
- }
- changeAddr, err := w.vm.selectChangeAddr(kc.Keys[0].PublicKey().Address(), args.ChangeAddr)
- if err != nil {
- return err
- }
-
- // Calculate required input amounts and create the desired outputs
- // String repr. of asset ID --> asset ID
- assetIDs := make(map[string]ids.ID)
- // Asset ID --> amount of that asset being sent
- amounts := make(map[ids.ID]uint64)
- // Outputs of our tx
- outs := []*avax.TransferableOutput{}
- for _, output := range args.Outputs {
- if output.Amount == 0 {
- return errZeroAmount
- }
- assetID, ok := assetIDs[output.AssetID] // Asset ID of next output
- if !ok {
- assetID, err = w.vm.lookupAssetID(output.AssetID)
- if err != nil {
- return fmt.Errorf("couldn't find asset %s", output.AssetID)
- }
- assetIDs[output.AssetID] = assetID
- }
- currentAmount := amounts[assetID]
- newAmount, err := math.Add(currentAmount, uint64(output.Amount))
- if err != nil {
- return fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amounts[assetID] = newAmount
-
- // Parse the to address
- to, err := avax.ParseServiceAddress(w.vm, output.To)
- if err != nil {
- return fmt.Errorf("problem parsing to address %q: %w", output.To, err)
- }
-
- // Create the Output
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: uint64(output.Amount),
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{to},
- },
- },
- })
- }
-
- amountsWithFee := maps.Clone(amounts)
-
- amountWithFee, err := math.Add(amounts[w.vm.feeAssetID], w.vm.TxFee)
- if err != nil {
- return fmt.Errorf("problem calculating required spend amount: %w", err)
- }
- amountsWithFee[w.vm.feeAssetID] = amountWithFee
-
- amountsSpent, ins, keys, err := w.vm.Spend(
- utxos,
- kc,
- amountsWithFee,
- )
- if err != nil {
- return err
- }
-
- // Add the required change outputs
- for assetID, amountWithFee := range amountsWithFee {
- amountSpent := amountsSpent[assetID]
-
- if amountSpent > amountWithFee {
- outs = append(outs, &avax.TransferableOutput{
- Asset: avax.Asset{ID: assetID},
- Out: &secp256k1fx.TransferOutput{
- Amt: amountSpent - amountWithFee,
- OutputOwners: secp256k1fx.OutputOwners{
- Locktime: 0,
- Threshold: 1,
- Addrs: []ids.ShortID{changeAddr},
- },
- },
- })
- }
- }
-
- codec := w.vm.parser.Codec()
- avax.SortTransferableOutputs(outs, codec)
-
- tx := &txs.Tx{Unsigned: &txs.BaseTx{BaseTx: avax.BaseTx{
- NetworkID: w.vm.ctx.NetworkID,
- BlockchainID: w.vm.ctx.ChainID,
- Outs: outs,
- Ins: ins,
- Memo: memoBytes,
- }}}
- if err := tx.SignSECP256K1Fx(codec, keys); err != nil {
- return err
- }
-
- txID, err := w.issue(tx)
- if err != nil {
- return fmt.Errorf("problem issuing transaction: %w", err)
- }
-
- reply.TxID = txID
- reply.ChangeAddr, err = w.vm.FormatLocalAddress(changeAddr)
- return err
-}
diff --git a/vms/avm/wallet_service_test.go b/vms/avm/wallet_service_test.go
deleted file mode 100644
index 5bada667fb8c..000000000000
--- a/vms/avm/wallet_service_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package avm
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/upgrade/upgradetest"
- "github.com/ava-labs/avalanchego/utils/linked"
- "github.com/ava-labs/avalanchego/vms/avm/txs"
-)
-
-func TestWalletService_SendMultiple(t *testing.T) {
- require := require.New(t)
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- env := setup(t, &envConfig{
- fork: upgradetest.Latest,
- isCustomFeeAsset: !tc.avaxAsset,
- keystoreUsers: []*user{{
- username: username,
- password: password,
- initialKeys: keys,
- }},
- })
- env.vm.ctx.Lock.Unlock()
-
- walletService := &WalletService{
- vm: env.vm,
- pendingTxs: linked.NewHashmap[ids.ID, *txs.Tx](),
- }
-
- assetID := env.genesisTx.ID()
- addr := keys[0].PublicKey().Address()
-
- addrStr, err := env.vm.FormatLocalAddress(addr)
- require.NoError(err)
- changeAddrStr, err := env.vm.FormatLocalAddress(testChangeAddr)
- require.NoError(err)
- _, fromAddrsStr := sampleAddrs(t, env.vm.AddressManager, addrs)
-
- args := &SendMultipleArgs{
- JSONSpendHeader: api.JSONSpendHeader{
- UserPass: api.UserPass{
- Username: username,
- Password: password,
- },
- JSONFromAddrs: api.JSONFromAddrs{From: fromAddrsStr},
- JSONChangeAddr: api.JSONChangeAddr{ChangeAddr: changeAddrStr},
- },
- Outputs: []SendOutput{
- {
- Amount: 500,
- AssetID: assetID.String(),
- To: addrStr,
- },
- {
- Amount: 1000,
- AssetID: assetID.String(),
- To: addrStr,
- },
- },
- }
- reply := &api.JSONTxIDChangeAddr{}
- require.NoError(walletService.SendMultiple(nil, args, reply))
- require.Equal(changeAddrStr, reply.ChangeAddr)
-
- buildAndAccept(require, env.vm, env.issuer, reply.TxID)
-
- env.vm.ctx.Lock.Lock()
- _, err = env.vm.state.GetTx(reply.TxID)
- env.vm.ctx.Lock.Unlock()
- require.NoError(err)
- })
- }
-}
diff --git a/vms/components/keystore/codec.go b/vms/components/keystore/codec.go
deleted file mode 100644
index 1837cc576229..000000000000
--- a/vms/components/keystore/codec.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "errors"
- "math"
-
- "github.com/ava-labs/avalanchego/codec"
- "github.com/ava-labs/avalanchego/codec/linearcodec"
-)
-
-const CodecVersion = 0
-
-var (
- Codec codec.Manager
- LegacyCodec codec.Manager
-)
-
-func init() {
- c := linearcodec.NewDefault()
- Codec = codec.NewDefaultManager()
- lc := linearcodec.NewDefault()
- LegacyCodec = codec.NewManager(math.MaxInt32)
-
- err := errors.Join(
- Codec.RegisterCodec(CodecVersion, c),
- LegacyCodec.RegisterCodec(CodecVersion, lc),
- )
- if err != nil {
- panic(err)
- }
-}
diff --git a/vms/components/keystore/user.go b/vms/components/keystore/user.go
deleted file mode 100644
index 20749e5b48bf..000000000000
--- a/vms/components/keystore/user.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "fmt"
- "io"
-
- "github.com/ava-labs/avalanchego/api/keystore"
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/encdb"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
- "github.com/ava-labs/avalanchego/utils/set"
- "github.com/ava-labs/avalanchego/vms/secp256k1fx"
-)
-
-// Max number of addresses allowed for a single keystore user
-const maxKeystoreAddresses = 5000
-
-var (
- // Key in the database whose corresponding value is the list of addresses
- // this user controls
- addressesKey = ids.Empty[:]
-
- errMaxAddresses = fmt.Errorf("keystore user has reached its limit of %d addresses", maxKeystoreAddresses)
-
- _ User = (*user)(nil)
-)
-
-type User interface {
- io.Closer
-
- // Get the addresses controlled by this user
- GetAddresses() ([]ids.ShortID, error)
-
- // PutKeys persists [privKeys]
- PutKeys(privKeys ...*secp256k1.PrivateKey) error
-
- // GetKey returns the private key that controls the given address
- GetKey(address ids.ShortID) (*secp256k1.PrivateKey, error)
-}
-
-type user struct {
- db *encdb.Database
-}
-
-// NewUserFromKeystore tracks a keystore user from the provided keystore
-func NewUserFromKeystore(ks keystore.BlockchainKeystore, username, password string) (User, error) {
- db, err := ks.GetDatabase(username, password)
- if err != nil {
- return nil, fmt.Errorf("problem retrieving user %q: %w", username, err)
- }
- return NewUserFromDB(db), nil
-}
-
-// NewUserFromDB tracks a keystore user from a database
-func NewUserFromDB(db *encdb.Database) User {
- return &user{db: db}
-}
-
-func (u *user) GetAddresses() ([]ids.ShortID, error) {
- // Get user's addresses
- addressBytes, err := u.db.Get(addressesKey)
- if err == database.ErrNotFound {
- // If user has no addresses, return empty list
- return nil, nil
- }
- if err != nil {
- return nil, err
- }
-
- var addresses []ids.ShortID
- _, err = LegacyCodec.Unmarshal(addressBytes, &addresses)
- return addresses, err
-}
-
-func (u *user) PutKeys(privKeys ...*secp256k1.PrivateKey) error {
- toStore := make([]*secp256k1.PrivateKey, 0, len(privKeys))
- for _, privKey := range privKeys {
- address := privKey.PublicKey().Address() // address the privKey controls
- hasAddress, err := u.db.Has(address.Bytes())
- if err != nil {
- return err
- }
- if !hasAddress {
- toStore = append(toStore, privKey)
- }
- }
-
- // there's nothing to store
- if len(toStore) == 0 {
- return nil
- }
-
- addresses, err := u.GetAddresses()
- if err != nil {
- return err
- }
-
- if len(toStore) > maxKeystoreAddresses || len(addresses) > maxKeystoreAddresses-len(toStore) {
- return errMaxAddresses
- }
-
- for _, privKey := range toStore {
- address := privKey.PublicKey().Address() // address the privKey controls
- // Address --> private key
- if err := u.db.Put(address.Bytes(), privKey.Bytes()); err != nil {
- return err
- }
- addresses = append(addresses, address)
- }
-
- addressBytes, err := Codec.Marshal(CodecVersion, addresses)
- if err != nil {
- return err
- }
- return u.db.Put(addressesKey, addressBytes)
-}
-
-func (u *user) GetKey(address ids.ShortID) (*secp256k1.PrivateKey, error) {
- bytes, err := u.db.Get(address.Bytes())
- if err != nil {
- return nil, err
- }
- return secp256k1.ToPrivateKey(bytes)
-}
-
-func (u *user) Close() error {
- return u.db.Close()
-}
-
-// Create and store a new key that will be controlled by this user.
-func NewKey(u User) (*secp256k1.PrivateKey, error) {
- keys, err := NewKeys(u, 1)
- if err != nil {
- return nil, err
- }
- return keys[0], nil
-}
-
-// Create and store [numKeys] new keys that will be controlled by this user.
-func NewKeys(u User, numKeys int) ([]*secp256k1.PrivateKey, error) {
- keys := make([]*secp256k1.PrivateKey, numKeys)
- for i := range keys {
- sk, err := secp256k1.NewPrivateKey()
- if err != nil {
- return nil, err
- }
- keys[i] = sk
- }
- return keys, u.PutKeys(keys...)
-}
-
-// Keychain returns a new keychain from the [user].
-// If [addresses] is non-empty it fetches only the keys in addresses. If a key
-// is missing, it will be ignored.
-// If [addresses] is empty, then it will create a keychain using every address
-// in the provided [user].
-func GetKeychain(u User, addresses set.Set[ids.ShortID]) (*secp256k1fx.Keychain, error) {
- addrsList := addresses.List()
- if len(addrsList) == 0 {
- var err error
- addrsList, err = u.GetAddresses()
- if err != nil {
- return nil, err
- }
- }
-
- kc := secp256k1fx.NewKeychain()
- for _, addr := range addrsList {
- sk, err := u.GetKey(addr)
- if err == database.ErrNotFound {
- continue
- }
- if err != nil {
- return nil, fmt.Errorf("problem retrieving private key for address %s: %w", addr, err)
- }
- kc.Add(sk)
- }
- return kc, nil
-}
diff --git a/vms/components/keystore/user_test.go b/vms/components/keystore/user_test.go
deleted file mode 100644
index 66e331c2f655..000000000000
--- a/vms/components/keystore/user_test.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
-// See the file LICENSE for licensing terms.
-
-package keystore
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/encdb"
- "github.com/ava-labs/avalanchego/database/memdb"
- "github.com/ava-labs/avalanchego/ids"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
-)
-
-// Test user password, must meet minimum complexity/length requirements
-const testPassword = "ShaggyPassword1Zoinks!"
-
-func TestUserClosedDB(t *testing.T) {
- require := require.New(t)
-
- db, err := encdb.New([]byte(testPassword), memdb.New())
- require.NoError(err)
-
- require.NoError(db.Close())
-
- u := NewUserFromDB(db)
-
- _, err = u.GetAddresses()
- require.ErrorIs(err, database.ErrClosed)
-
- _, err = u.GetKey(ids.ShortEmpty)
- require.ErrorIs(err, database.ErrClosed)
-
- _, err = GetKeychain(u, nil)
- require.ErrorIs(err, database.ErrClosed)
-
- sk, err := secp256k1.NewPrivateKey()
- require.NoError(err)
-
- err = u.PutKeys(sk)
- require.ErrorIs(err, database.ErrClosed)
-}
-
-func TestUser(t *testing.T) {
- require := require.New(t)
-
- db, err := encdb.New([]byte(testPassword), memdb.New())
- require.NoError(err)
-
- u := NewUserFromDB(db)
-
- addresses, err := u.GetAddresses()
- require.NoError(err)
- require.Empty(addresses, "new user shouldn't have address")
-
- sk, err := secp256k1.NewPrivateKey()
- require.NoError(err)
-
- require.NoError(u.PutKeys(sk))
-
- // Putting the same key multiple times should be a noop
- require.NoError(u.PutKeys(sk))
-
- addr := sk.PublicKey().Address()
-
- savedSk, err := u.GetKey(addr)
- require.NoError(err)
- require.Equal(sk.Bytes(), savedSk.Bytes(), "wrong key returned")
-
- addresses, err = u.GetAddresses()
- require.NoError(err)
- require.Len(addresses, 1, "address should have been added")
-
- savedAddr := addresses[0]
- require.Equal(addr, savedAddr, "saved address should match provided address")
-
- savedKeychain, err := GetKeychain(u, nil)
- require.NoError(err)
- require.Len(savedKeychain.Keys, 1, "key should have been added")
- require.Equal(sk.Bytes(), savedKeychain.Keys[0].Bytes(), "wrong key returned")
-}
diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go
index e1304f83bbbc..d0ca1be19d13 100644
--- a/vms/platformvm/client.go
+++ b/vms/platformvm/client.go
@@ -12,7 +12,6 @@ import (
"github.com/ava-labs/avalanchego/snow/validators"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/formatting/address"
"github.com/ava-labs/avalanchego/utils/json"
@@ -34,18 +33,10 @@ type Client interface {
GetHeight(ctx context.Context, options ...rpc.Option) (uint64, error)
// GetProposedHeight returns the current height of this node's proposer VM.
GetProposedHeight(ctx context.Context, options ...rpc.Option) (uint64, error)
- // ExportKey returns the private key corresponding to [address] from [user]'s account
- //
- // Deprecated: Keys should no longer be stored on the node.
- ExportKey(ctx context.Context, user api.UserPass, address ids.ShortID, options ...rpc.Option) (*secp256k1.PrivateKey, error)
// GetBalance returns the balance of [addrs] on the P Chain
//
// Deprecated: GetUTXOs should be used instead.
GetBalance(ctx context.Context, addrs []ids.ShortID, options ...rpc.Option) (*GetBalanceResponse, error)
- // ListAddresses returns an array of platform addresses controlled by [user]
- //
- // Deprecated: Keys should no longer be stored on the node.
- ListAddresses(ctx context.Context, user api.UserPass, options ...rpc.Option) ([]ids.ShortID, error)
// GetUTXOs returns the byte representation of the UTXOs controlled by [addrs]
GetUTXOs(
ctx context.Context,
@@ -179,15 +170,6 @@ func (c *client) GetProposedHeight(ctx context.Context, options ...rpc.Option) (
return uint64(res.Height), err
}
-func (c *client) ExportKey(ctx context.Context, user api.UserPass, address ids.ShortID, options ...rpc.Option) (*secp256k1.PrivateKey, error) {
- res := &ExportKeyReply{}
- err := c.requester.SendRequest(ctx, "platform.exportKey", &ExportKeyArgs{
- UserPass: user,
- Address: address.String(),
- }, res, options...)
- return res.PrivateKey, err
-}
-
func (c *client) GetBalance(ctx context.Context, addrs []ids.ShortID, options ...rpc.Option) (*GetBalanceResponse, error) {
res := &GetBalanceResponse{}
err := c.requester.SendRequest(ctx, "platform.getBalance", &GetBalanceRequest{
@@ -196,15 +178,6 @@ func (c *client) GetBalance(ctx context.Context, addrs []ids.ShortID, options ..
return res, err
}
-func (c *client) ListAddresses(ctx context.Context, user api.UserPass, options ...rpc.Option) ([]ids.ShortID, error) {
- res := &api.JSONAddresses{}
- err := c.requester.SendRequest(ctx, "platform.listAddresses", &user, res, options...)
- if err != nil {
- return nil, err
- }
- return address.ParseToIDs(res.Addresses)
-}
-
func (c *client) GetUTXOs(
ctx context.Context,
addrs []ids.ShortID,
diff --git a/vms/platformvm/service.go b/vms/platformvm/service.go
index a5e87181393c..cdbc588fafde 100644
--- a/vms/platformvm/service.go
+++ b/vms/platformvm/service.go
@@ -23,13 +23,11 @@ import (
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
- "github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/components/gas"
- "github.com/ava-labs/avalanchego/vms/components/keystore"
"github.com/ava-labs/avalanchego/vms/platformvm/fx"
"github.com/ava-labs/avalanchego/vms/platformvm/reward"
"github.com/ava-labs/avalanchego/vms/platformvm/signer"
@@ -116,49 +114,6 @@ func (s *Service) GetProposedHeight(r *http.Request, _ *struct{}, reply *api.Get
return err
}
-// ExportKeyArgs are arguments for ExportKey
-type ExportKeyArgs struct {
- api.UserPass
- Address string `json:"address"`
-}
-
-// ExportKeyReply is the response for ExportKey
-type ExportKeyReply struct {
- // The decrypted PrivateKey for the Address provided in the arguments
- PrivateKey *secp256k1.PrivateKey `json:"privateKey"`
-}
-
-// ExportKey returns a private key from the provided user
-func (s *Service) ExportKey(_ *http.Request, args *ExportKeyArgs, reply *ExportKeyReply) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "platform"),
- zap.String("method", "exportKey"),
- logging.UserString("username", args.Username),
- )
-
- address, err := avax.ParseServiceAddress(s.addrManager, args.Address)
- if err != nil {
- return fmt.Errorf("couldn't parse %s to address: %w", args.Address, err)
- }
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
-
- reply.PrivateKey, err = user.GetKey(address)
- if err != nil {
- // Drop any potential error closing the user to report the original
- // error
- _ = user.Close()
- return fmt.Errorf("problem retrieving private key: %w", err)
- }
- return user.Close()
-}
-
type GetBalanceRequest struct {
Addresses []string `json:"addresses"`
}
@@ -299,37 +254,6 @@ func newJSONBalanceMap(balanceMap map[ids.ID]uint64) map[ids.ID]avajson.Uint64 {
return jsonBalanceMap
}
-// ListAddresses returns the addresses controlled by [args.Username]
-func (s *Service) ListAddresses(_ *http.Request, args *api.UserPass, response *api.JSONAddresses) error {
- s.vm.ctx.Log.Warn("deprecated API called",
- zap.String("service", "platform"),
- zap.String("method", "listAddresses"),
- logging.UserString("username", args.Username),
- )
-
- s.vm.ctx.Lock.Lock()
- defer s.vm.ctx.Lock.Unlock()
-
- user, err := keystore.NewUserFromKeystore(s.vm.ctx.Keystore, args.Username, args.Password)
- if err != nil {
- return err
- }
- defer user.Close()
-
- addresses, err := user.GetAddresses()
- if err != nil {
- return fmt.Errorf("couldn't get addresses: %w", err)
- }
- response.Addresses = make([]string, len(addresses))
- for i, addr := range addresses {
- response.Addresses[i], err = s.addrManager.FormatLocalAddress(addr)
- if err != nil {
- return fmt.Errorf("problem formatting address: %w", err)
- }
- }
- return user.Close()
-}
-
// Index is an address and an associated UTXO.
// Marks a starting or stopping point when fetching UTXOs. Used for pagination.
type Index struct {
diff --git a/vms/platformvm/service.md b/vms/platformvm/service.md
index 744349ff5405..992fec3304b1 100644
--- a/vms/platformvm/service.md
+++ b/vms/platformvm/service.md
@@ -12,63 +12,6 @@ This API uses the `json 2.0` RPC format.
## Methods
-### `platform.exportKey`
-
-
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-
-
-
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/api-reference/keystore-api).
-
-
-
-Get the private key that controls a given address.
-
-**Signature:**
-
-```
-platform.exportKey({
- username: string,
- password: string,
- address: string
-}) -> {privateKey: string}
-```
-
-- `username` is the user that controls `address`.
-- `password` is `username`‘s password.
-- `privateKey` is the string representation of the private key that controls `address`.
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc":"2.0",
- "id" :1,
- "method" :"platform.exportKey",
- "params" :{
- "username" :"myUsername",
- "password": "myPassword",
- "address": "P-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"
- }
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "privateKey": "PrivateKey-Lf49kAJw3CbaL783vmbeAJvhscJqC7vi5yBYLxw2XfbzNS5RS"
- }
-}
-```
-
### `platform.getBalance`
@@ -2143,57 +2086,6 @@ curl -X POST --data '{
}
```
-### `platform.listAddresses`
-
-
-
-Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12).
-
-
-
-
-
-Not recommended for use on Mainnet. See warning notice in [Keystore API](/api-reference/keystore-api).
-
-
-
-List addresses controlled by the given user.
-
-**Signature:**
-
-```
-platform.listAddresses({
- username: string,
- password: string
-}) -> { addresses: []string }
-```
-
-**Example Call:**
-
-```sh
-curl -X POST --data '{
- "jsonrpc": "2.0",
- "method": "platform.listAddresses",
- "params": {
- "username":"myUsername",
- "password":"myPassword"
- },
- "id": 1
-}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P
-```
-
-**Example Response:**
-
-```json
-{
- "jsonrpc": "2.0",
- "result": {
- "addresses": ["P-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"]
- },
- "id": 1
-}
-```
-
### `platform.sampleValidators`
Sample validators from the specified Subnet.
diff --git a/vms/platformvm/service_test.go b/vms/platformvm/service_test.go
index ebe9e833aa01..f5871335be74 100644
--- a/vms/platformvm/service_test.go
+++ b/vms/platformvm/service_test.go
@@ -18,11 +18,9 @@ import (
"go.uber.org/mock/gomock"
"github.com/ava-labs/avalanchego/api"
- "github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/cache"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/database"
- "github.com/ava-labs/avalanchego/database/memdb"
"github.com/ava-labs/avalanchego/database/prefixdb"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
@@ -51,36 +49,15 @@ import (
"github.com/ava-labs/avalanchego/wallet/subnet/primary/common"
avajson "github.com/ava-labs/avalanchego/utils/json"
- vmkeystore "github.com/ava-labs/avalanchego/vms/components/keystore"
pchainapi "github.com/ava-labs/avalanchego/vms/platformvm/api"
blockbuilder "github.com/ava-labs/avalanchego/vms/platformvm/block/builder"
blockexecutor "github.com/ava-labs/avalanchego/vms/platformvm/block/executor"
txexecutor "github.com/ava-labs/avalanchego/vms/platformvm/txs/executor"
)
-var (
- // Test user username
- testUsername = "ScoobyUser"
-
- // Test user password, must meet minimum complexity/length requirements
- testPassword = "ShaggyPassword1Zoinks!"
-
- // Bytes decoded from CB58 "ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN"
- testPrivateKey = []byte{
- 0x56, 0x28, 0x9e, 0x99, 0xc9, 0x4b, 0x69, 0x12,
- 0xbf, 0xc1, 0x2a, 0xdc, 0x09, 0x3c, 0x9b, 0x51,
- 0x12, 0x4f, 0x0d, 0xc5, 0x4a, 0xc7, 0xa7, 0x66,
- 0xb2, 0xbc, 0x5c, 0xcf, 0x55, 0x8d, 0x80, 0x27,
- }
-
- // 3cb7d3842e8cee6a0ebd09f1fe884f6861e1b29c
- // Platform address resulting from the above private key
- testAddress = "P-testing18jma8ppw3nhx5r4ap8clazz0dps7rv5umpc36y"
-
- encodings = []formatting.Encoding{
- formatting.JSON, formatting.Hex,
- }
-)
+var encodings = []formatting.Encoding{
+ formatting.JSON, formatting.Hex,
+}
func defaultService(t *testing.T) (*Service, *mutableSharedMemory) {
vm, _, mutableSharedMemory := defaultVM(t, upgradetest.Latest)
@@ -157,36 +134,6 @@ func TestGetProposedHeight(t *testing.T) {
require.Equal(latestBlock.Height(), uint64(reply.Height))
}
-func TestExportKey(t *testing.T) {
- require := require.New(t)
-
- service, _ := defaultService(t)
- service.vm.ctx.Lock.Lock()
-
- ks := keystore.New(logging.NoLog{}, memdb.New())
- require.NoError(ks.CreateUser(testUsername, testPassword))
- service.vm.ctx.Keystore = ks.NewBlockchainKeyStore(service.vm.ctx.ChainID)
-
- user, err := vmkeystore.NewUserFromKeystore(service.vm.ctx.Keystore, testUsername, testPassword)
- require.NoError(err)
-
- pk, err := secp256k1.ToPrivateKey(testPrivateKey)
- require.NoError(err)
-
- require.NoError(user.PutKeys(pk, genesistest.DefaultFundedKeys[0]))
-
- service.vm.ctx.Lock.Unlock()
-
- jsonString := `{"username":"` + testUsername + `","password":"` + testPassword + `","address":"` + testAddress + `"}`
- args := ExportKeyArgs{}
- require.NoError(json.Unmarshal([]byte(jsonString), &args))
-
- reply := ExportKeyReply{}
- require.NoError(service.ExportKey(nil, &args, &reply))
-
- require.Equal(testPrivateKey, reply.PrivateKey.Bytes())
-}
-
// Test issuing a tx and accepted
func TestGetTxStatus(t *testing.T) {
require := require.New(t)
diff --git a/vms/rpcchainvm/vm_client.go b/vms/rpcchainvm/vm_client.go
index 05add90700dc..8345c6c911c5 100644
--- a/vms/rpcchainvm/vm_client.go
+++ b/vms/rpcchainvm/vm_client.go
@@ -17,7 +17,6 @@ import (
"google.golang.org/grpc/health"
"google.golang.org/protobuf/types/known/emptypb"
- "github.com/ava-labs/avalanchego/api/keystore/gkeystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/chains/atomic/gsharedmemory"
"github.com/ava-labs/avalanchego/database"
@@ -45,7 +44,6 @@ import (
aliasreaderpb "github.com/ava-labs/avalanchego/proto/pb/aliasreader"
appsenderpb "github.com/ava-labs/avalanchego/proto/pb/appsender"
httppb "github.com/ava-labs/avalanchego/proto/pb/http"
- keystorepb "github.com/ava-labs/avalanchego/proto/pb/keystore"
messengerpb "github.com/ava-labs/avalanchego/proto/pb/messenger"
rpcdbpb "github.com/ava-labs/avalanchego/proto/pb/rpcdb"
sharedmemorypb "github.com/ava-labs/avalanchego/proto/pb/sharedmemory"
@@ -91,7 +89,6 @@ type VMClient struct {
metricsGatherer metrics.MultiGatherer
messenger *messenger.Server
- keystore *gkeystore.Server
sharedMemory *gsharedmemory.Server
bcLookup *galiasreader.Server
appSender *appsender.Server
@@ -169,7 +166,6 @@ func (vm *VMClient) Initialize(
)
vm.messenger = messenger.NewServer(toEngine)
- vm.keystore = gkeystore.NewServer(chainCtx.Keystore)
vm.sharedMemory = gsharedmemory.NewServer(chainCtx.SharedMemory, db)
vm.bcLookup = galiasreader.NewServer(chainCtx.BCLookup)
vm.appSender = appsender.NewServer(appSender)
@@ -308,7 +304,6 @@ func (vm *VMClient) newInitServer() *grpc.Server {
// Register services
messengerpb.RegisterMessengerServer(server, vm.messenger)
- keystorepb.RegisterKeystoreServer(server, vm.keystore)
sharedmemorypb.RegisterSharedMemoryServer(server, vm.sharedMemory)
aliasreaderpb.RegisterAliasReaderServer(server, vm.bcLookup)
appsenderpb.RegisterAppSenderServer(server, vm.appSender)
diff --git a/vms/rpcchainvm/vm_server.go b/vms/rpcchainvm/vm_server.go
index 30014909abbf..18540a7fac98 100644
--- a/vms/rpcchainvm/vm_server.go
+++ b/vms/rpcchainvm/vm_server.go
@@ -14,7 +14,6 @@ import (
"github.com/prometheus/client_golang/prometheus/collectors"
"google.golang.org/protobuf/types/known/emptypb"
- "github.com/ava-labs/avalanchego/api/keystore/gkeystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/chains/atomic/gsharedmemory"
"github.com/ava-labs/avalanchego/database"
@@ -42,7 +41,6 @@ import (
aliasreaderpb "github.com/ava-labs/avalanchego/proto/pb/aliasreader"
appsenderpb "github.com/ava-labs/avalanchego/proto/pb/appsender"
httppb "github.com/ava-labs/avalanchego/proto/pb/http"
- keystorepb "github.com/ava-labs/avalanchego/proto/pb/keystore"
messengerpb "github.com/ava-labs/avalanchego/proto/pb/messenger"
rpcdbpb "github.com/ava-labs/avalanchego/proto/pb/rpcdb"
sharedmemorypb "github.com/ava-labs/avalanchego/proto/pb/sharedmemory"
@@ -211,7 +209,6 @@ func (vm *VMServer) Initialize(ctx context.Context, req *vmpb.InitializeRequest)
vm.connCloser.Add(clientConn)
msgClient := messenger.NewClient(messengerpb.NewMessengerClient(clientConn))
- keystoreClient := gkeystore.NewClient(keystorepb.NewKeystoreClient(clientConn))
sharedMemoryClient := gsharedmemory.NewClient(sharedmemorypb.NewSharedMemoryClient(clientConn))
bcLookupClient := galiasreader.NewClient(aliasreaderpb.NewAliasReaderClient(clientConn))
appSenderClient := appsender.NewClient(appsenderpb.NewAppSenderClient(clientConn))
@@ -248,7 +245,6 @@ func (vm *VMServer) Initialize(ctx context.Context, req *vmpb.InitializeRequest)
AVAXAssetID: avaxAssetID,
Log: vm.log,
- Keystore: keystoreClient,
SharedMemory: sharedMemoryClient,
BCLookup: bcLookupClient,
Metrics: vmMetrics,