From be859c90f068f8fddb34005ef59822212bbe71de Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 16 Jan 2025 11:20:29 +0300 Subject: [PATCH] remove keystore and related APIs (#748) --- RELEASES.md | 4 + plugin/evm/api.go | 211 +-------------------- plugin/evm/client/client.go | 141 -------------- plugin/evm/client/client_interface_test.go | 17 -- plugin/evm/user.go | 137 ------------- plugin/evm/vm.go | 17 -- plugin/evm/vm_test.go | 10 - 7 files changed, 7 insertions(+), 530 deletions(-) delete mode 100644 plugin/evm/client/client_interface_test.go delete mode 100644 plugin/evm/user.go diff --git a/RELEASES.md b/RELEASES.md index 4dd80d2d21..d2072b75b8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,9 @@ # Release Notes +## Pending Release + +- Removed deprecated `ExportKey`, `ExportAVAX`, `Export`, `ImportKey`, `ImportAVAX`, `Import` APIs + ## [v0.14.1](https://github.com/ava-labs/coreth/releases/tag/v0.14.1) - IMPORTANT: `eth_getProof` calls for historical state will be rejected by default. diff --git a/plugin/evm/api.go b/plugin/evm/api.go index 49ad2a895f..12791d4e08 100644 --- a/plugin/evm/api.go +++ b/plugin/evm/api.go @@ -19,7 +19,6 @@ import ( "github.com/ava-labs/coreth/plugin/evm/atomic" "github.com/ava-labs/coreth/plugin/evm/client" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/log" ) @@ -33,10 +32,9 @@ const ( ) var ( - errNoAddresses = errors.New("no addresses provided") - errNoSourceChain = errors.New("no source chain provided") - errNilTxID = errors.New("nil transaction ID") - errMissingPrivateKey = errors.New("argument 'privateKey' not given") + errNoAddresses = errors.New("no addresses provided") + errNoSourceChain = errors.New("no source chain provided") + errNilTxID = errors.New("nil transaction ID") initialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) ) @@ -71,17 +69,6 @@ func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { // AvaxAPI offers Avalanche network related API methods type AvaxAPI struct{ vm *VM } -// parseAssetID parses an assetID string into an ID -func (service *AvaxAPI) parseAssetID(assetID string) (ids.ID, error) { - if assetID == "" { - return ids.ID{}, fmt.Errorf("assetID is required") - } else if assetID == "AVAX" { - return service.vm.ctx.AVAXAssetID, nil - } else { - return ids.FromString(assetID) - } -} - type VersionReply struct { Version string `json:"version"` } @@ -92,198 +79,6 @@ func (service *AvaxAPI) Version(r *http.Request, _ *struct{}, reply *VersionRepl return nil } -// ExportKey returns a private key from the provided user -func (service *AvaxAPI) ExportKey(r *http.Request, args *client.ExportKeyArgs, reply *client.ExportKeyReply) error { - log.Info("EVM: ExportKey called") - - address, err := client.ParseEthAddress(args.Address) - if err != nil { - return fmt.Errorf("couldn't parse %s to address: %s", args.Address, err) - } - - service.vm.ctx.Lock.Lock() - defer service.vm.ctx.Lock.Unlock() - - db, err := service.vm.ctx.Keystore.GetDatabase(args.Username, args.Password) - if err != nil { - return fmt.Errorf("problem retrieving user '%s': %w", args.Username, err) - } - defer db.Close() - - user := user{db: db} - reply.PrivateKey, err = user.getKey(address) - if err != nil { - return fmt.Errorf("problem retrieving private key: %w", err) - } - reply.PrivateKeyHex = hexutil.Encode(reply.PrivateKey.Bytes()) - return nil -} - -// ImportKey adds a private key to the provided user -func (service *AvaxAPI) ImportKey(r *http.Request, args *client.ImportKeyArgs, reply *api.JSONAddress) error { - log.Info("EVM: ImportKey called", "username", args.Username) - - if args.PrivateKey == nil { - return errMissingPrivateKey - } - - reply.Address = args.PrivateKey.EthAddress().Hex() - - service.vm.ctx.Lock.Lock() - defer service.vm.ctx.Lock.Unlock() - - db, err := service.vm.ctx.Keystore.GetDatabase(args.Username, args.Password) - if err != nil { - return fmt.Errorf("problem retrieving data: %w", err) - } - defer db.Close() - - user := user{db: db} - if err := user.putAddress(args.PrivateKey); err != nil { - return fmt.Errorf("problem saving key %w", err) - } - return nil -} - -// ImportAVAX is a deprecated name for Import. -func (service *AvaxAPI) ImportAVAX(_ *http.Request, args *client.ImportArgs, response *api.JSONTxID) error { - return service.Import(nil, args, response) -} - -// Import issues a transaction to import AVAX from the X-chain. The AVAX -// must have already been exported from the X-Chain. -func (service *AvaxAPI) Import(_ *http.Request, args *client.ImportArgs, response *api.JSONTxID) error { - log.Info("EVM: ImportAVAX called") - - chainID, err := service.vm.ctx.BCLookup.Lookup(args.SourceChain) - if err != nil { - return fmt.Errorf("problem parsing chainID %q: %w", args.SourceChain, err) - } - - service.vm.ctx.Lock.Lock() - defer service.vm.ctx.Lock.Unlock() - - // Get the user's info - db, err := service.vm.ctx.Keystore.GetDatabase(args.Username, args.Password) - if err != nil { - return fmt.Errorf("couldn't get user '%s': %w", args.Username, err) - } - defer db.Close() - - user := user{db: db} - privKeys, err := user.getKeys() - if err != nil { // Get keys - return fmt.Errorf("couldn't get keys controlled by the user: %w", err) - } - - var baseFee *big.Int - if args.BaseFee == nil { - // Get the base fee to use - baseFee, err = service.vm.estimateBaseFee(context.Background()) - if err != nil { - return err - } - } else { - baseFee = args.BaseFee.ToInt() - } - - tx, err := service.vm.newImportTx(chainID, args.To, baseFee, privKeys) - if err != nil { - return err - } - - response.TxID = tx.ID() - if err := service.vm.mempool.AddLocalTx(tx); err != nil { - return err - } - service.vm.atomicTxPushGossiper.Add(&atomic.GossipAtomicTx{Tx: tx}) - return nil -} - -// ExportAVAX exports AVAX from the C-Chain to the X-Chain -// It must be imported on the X-Chain to complete the transfer -func (service *AvaxAPI) ExportAVAX(_ *http.Request, args *client.ExportAVAXArgs, response *api.JSONTxID) error { - return service.Export(nil, &client.ExportArgs{ - ExportAVAXArgs: *args, - AssetID: service.vm.ctx.AVAXAssetID.String(), - }, response) -} - -// Export exports an asset from the C-Chain to the X-Chain -// It must be imported on the X-Chain to complete the transfer -func (service *AvaxAPI) Export(_ *http.Request, args *client.ExportArgs, response *api.JSONTxID) error { - log.Info("EVM: Export called") - - assetID, err := service.parseAssetID(args.AssetID) - if err != nil { - return err - } - - if args.Amount == 0 { - return errors.New("argument 'amount' must be > 0") - } - - // Get the chainID and parse the to address - chainID, to, err := service.vm.ParseAddress(args.To) - if err != nil { - chainID, err = service.vm.ctx.BCLookup.Lookup(args.TargetChain) - if err != nil { - return err - } - to, err = ids.ShortFromString(args.To) - if err != nil { - return err - } - } - - service.vm.ctx.Lock.Lock() - defer service.vm.ctx.Lock.Unlock() - - // Get this user's data - db, err := service.vm.ctx.Keystore.GetDatabase(args.Username, args.Password) - if err != nil { - return fmt.Errorf("problem retrieving user '%s': %w", args.Username, err) - } - defer db.Close() - - user := user{db: db} - privKeys, err := user.getKeys() - if err != nil { - return fmt.Errorf("couldn't get addresses controlled by the user: %w", err) - } - - var baseFee *big.Int - if args.BaseFee == nil { - // Get the base fee to use - baseFee, err = service.vm.estimateBaseFee(context.Background()) - if err != nil { - return err - } - } else { - baseFee = args.BaseFee.ToInt() - } - - // Create the transaction - tx, err := service.vm.newExportTx( - assetID, // AssetID - uint64(args.Amount), // Amount - chainID, // ID of the chain to send the funds to - to, // Address - baseFee, - privKeys, // Private keys - ) - if err != nil { - return fmt.Errorf("couldn't create tx: %w", err) - } - - response.TxID = tx.ID() - if err := service.vm.mempool.AddLocalTx(tx); err != nil { - return err - } - service.vm.atomicTxPushGossiper.Add(&atomic.GossipAtomicTx{Tx: tx}) - return nil -} - // GetUTXOs gets all utxos for passed in addresses func (service *AvaxAPI) GetUTXOs(r *http.Request, args *api.GetUTXOsArgs, reply *api.GetUTXOsReply) error { log.Info("EVM: GetUTXOs called", "Addresses", args.Addresses) diff --git a/plugin/evm/client/client.go b/plugin/evm/client/client.go index a6716b4b27..b507342405 100644 --- a/plugin/evm/client/client.go +++ b/plugin/evm/client/client.go @@ -8,13 +8,10 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "golang.org/x/exp/slog" "github.com/ava-labs/avalanchego/api" "github.com/ava-labs/avalanchego/ids" - "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,11 +31,6 @@ type Client interface { GetAtomicTxStatus(ctx context.Context, txID ids.ID, options ...rpc.Option) (atomic.Status, error) GetAtomicTx(ctx context.Context, txID ids.ID, options ...rpc.Option) ([]byte, error) GetAtomicUTXOs(ctx context.Context, addrs []ids.ShortID, sourceChain string, limit uint32, startAddress ids.ShortID, startUTXOID ids.ID, options ...rpc.Option) ([][]byte, ids.ShortID, ids.ID, error) - ExportKey(ctx context.Context, userPass api.UserPass, addr common.Address, options ...rpc.Option) (*secp256k1.PrivateKey, string, error) - ImportKey(ctx context.Context, userPass api.UserPass, privateKey *secp256k1.PrivateKey, options ...rpc.Option) (common.Address, error) - Import(ctx context.Context, userPass api.UserPass, to common.Address, sourceChain string, options ...rpc.Option) (ids.ID, error) - ExportAVAX(ctx context.Context, userPass api.UserPass, amount uint64, to ids.ShortID, targetChain string, options ...rpc.Option) (ids.ID, error) - Export(ctx context.Context, userPass api.UserPass, amount uint64, to ids.ShortID, targetChain string, assetID string, options ...rpc.Option) (ids.ID, error) StartCPUProfiler(ctx context.Context, options ...rpc.Option) error StopCPUProfiler(ctx context.Context, options ...rpc.Option) error MemoryProfile(ctx context.Context, options ...rpc.Option) error @@ -143,139 +135,6 @@ func (c *client) GetAtomicUTXOs(ctx context.Context, addrs []ids.ShortID, source return utxos, endAddr, endUTXOID, 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"` - PrivateKeyHex string `json:"privateKeyHex"` -} - -// ExportKey returns the private key corresponding to [addr] controlled by [user] -// in both Avalanche standard format and hex format -func (c *client) ExportKey(ctx context.Context, user api.UserPass, addr common.Address, options ...rpc.Option) (*secp256k1.PrivateKey, string, error) { - res := &ExportKeyReply{} - err := c.requester.SendRequest(ctx, "avax.exportKey", &ExportKeyArgs{ - UserPass: user, - Address: addr.Hex(), - }, res, options...) - return res.PrivateKey, res.PrivateKeyHex, err -} - -// ImportKeyArgs are arguments for ImportKey -type ImportKeyArgs struct { - api.UserPass - PrivateKey *secp256k1.PrivateKey `json:"privateKey"` -} - -// ImportKey imports [privateKey] to [user] -func (c *client) ImportKey(ctx context.Context, user api.UserPass, privateKey *secp256k1.PrivateKey, options ...rpc.Option) (common.Address, error) { - res := &api.JSONAddress{} - err := c.requester.SendRequest(ctx, "avax.importKey", &ImportKeyArgs{ - UserPass: user, - PrivateKey: privateKey, - }, res, options...) - if err != nil { - return common.Address{}, err - } - return ParseEthAddress(res.Address) -} - -// ImportArgs are arguments for passing into Import requests -type ImportArgs struct { - api.UserPass - - // Fee that should be used when creating the tx - BaseFee *hexutil.Big `json:"baseFee"` - - // Chain the funds are coming from - SourceChain string `json:"sourceChain"` - - // The address that will receive the imported funds - To common.Address `json:"to"` -} - -// Import sends an import transaction to import funds from [sourceChain] and -// returns the ID of the newly created transaction -func (c *client) Import(ctx context.Context, user api.UserPass, to common.Address, sourceChain string, options ...rpc.Option) (ids.ID, error) { - res := &api.JSONTxID{} - err := c.requester.SendRequest(ctx, "avax.import", &ImportArgs{ - UserPass: user, - To: to, - SourceChain: sourceChain, - }, res, options...) - return res.TxID, err -} - -// ExportAVAX sends AVAX from this chain to the address specified by [to]. -// Returns the ID of the newly created atomic transaction -func (c *client) ExportAVAX( - ctx context.Context, - user api.UserPass, - amount uint64, - to ids.ShortID, - targetChain string, - options ...rpc.Option, -) (ids.ID, error) { - return c.Export(ctx, user, amount, to, targetChain, "AVAX", options...) -} - -// ExportAVAXArgs are the arguments to ExportAVAX -type ExportAVAXArgs struct { - api.UserPass - - // Fee that should be used when creating the tx - BaseFee *hexutil.Big `json:"baseFee"` - - // Amount of asset to send - Amount json.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"` -} - -// ExportArgs are the arguments to Export -type ExportArgs struct { - ExportAVAXArgs - // AssetID of the tokens - 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 (c *client) Export( - ctx context.Context, - user api.UserPass, - amount uint64, - to ids.ShortID, - targetChain string, - assetID string, - options ...rpc.Option, -) (ids.ID, error) { - res := &api.JSONTxID{} - err := c.requester.SendRequest(ctx, "avax.export", &ExportArgs{ - ExportAVAXArgs: ExportAVAXArgs{ - UserPass: user, - Amount: json.Uint64(amount), - TargetChain: targetChain, - To: to.String(), - }, - AssetID: assetID, - }, res, options...) - return res.TxID, err -} - func (c *client) StartCPUProfiler(ctx context.Context, options ...rpc.Option) error { return c.adminRequester.SendRequest(ctx, "admin.startCPUProfiler", struct{}{}, &api.EmptyReply{}, options...) } diff --git a/plugin/evm/client/client_interface_test.go b/plugin/evm/client/client_interface_test.go deleted file mode 100644 index 332bb8bcf4..0000000000 --- a/plugin/evm/client/client_interface_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package client - -import ( - "reflect" - "testing" -) - -func TestInterfaceStructOneToOne(t *testing.T) { - // checks struct provides at least the methods signatures in the interface - var _ Client = (*client)(nil) - // checks interface and struct have the same number of methods - clientType := reflect.TypeOf(&client{}) - ClientType := reflect.TypeOf((*Client)(nil)).Elem() - if clientType.NumMethod() != ClientType.NumMethod() { - t.Fatalf("no 1 to 1 compliance between struct methods (%v) and interface methods (%v)", clientType.NumMethod(), ClientType.NumMethod()) - } -} diff --git a/plugin/evm/user.go b/plugin/evm/user.go deleted file mode 100644 index 8cb3f73f34..0000000000 --- a/plugin/evm/user.go +++ /dev/null @@ -1,137 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "errors" - - "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/coreth/plugin/evm/atomic" - "github.com/ethereum/go-ethereum/common" -) - -// Key in the database whose corresponding value is the list of -// addresses this user controls -var addressesKey = ids.Empty[:] - -var ( - errDBNil = errors.New("db uninitialized") - errKeyNil = errors.New("key uninitialized") -) - -type user struct { - // This user's database, acquired from the keystore - db *encdb.Database -} - -// Get the addresses controlled by this user -func (u *user) getAddresses() ([]common.Address, error) { - if u.db == nil { - return nil, errDBNil - } - - // If user has no addresses, return empty list - hasAddresses, err := u.db.Has(addressesKey) - if err != nil { - return nil, err - } - if !hasAddresses { - return nil, nil - } - - // User has addresses. Get them. - bytes, err := u.db.Get(addressesKey) - if err != nil { - return nil, err - } - addresses := []common.Address{} - if _, err := atomic.Codec.Unmarshal(bytes, &addresses); err != nil { - return nil, err - } - return addresses, nil -} - -// controlsAddress returns true iff this user controls the given address -func (u *user) controlsAddress(address common.Address) (bool, error) { - if u.db == nil { - return false, errDBNil - //} else if address.IsZero() { - // return false, errEmptyAddress - } - return u.db.Has(address.Bytes()) -} - -// putAddress persists that this user controls address controlled by [privKey] -func (u *user) putAddress(privKey *secp256k1.PrivateKey) error { - if privKey == nil { - return errKeyNil - } - - address := privKey.EthAddress() // address the privKey controls - controlsAddress, err := u.controlsAddress(address) - if err != nil { - return err - } - if controlsAddress { // user already controls this address. Do nothing. - return nil - } - - if err := u.db.Put(address.Bytes(), privKey.Bytes()); err != nil { // Address --> private key - return err - } - - addresses := make([]common.Address, 0) // Add address to list of addresses user controls - userHasAddresses, err := u.db.Has(addressesKey) - if err != nil { - return err - } - if userHasAddresses { // Get addresses this user already controls, if they exist - if addresses, err = u.getAddresses(); err != nil { - return err - } - } - addresses = append(addresses, address) - bytes, err := atomic.Codec.Marshal(atomic.CodecVersion, addresses) - if err != nil { - return err - } - if err := u.db.Put(addressesKey, bytes); err != nil { - return err - } - return nil -} - -// Key returns the private key that controls the given address -func (u *user) getKey(address common.Address) (*secp256k1.PrivateKey, error) { - if u.db == nil { - return nil, errDBNil - //} else if address.IsZero() { - // return nil, errEmptyAddress - } - - bytes, err := u.db.Get(address.Bytes()) - if err != nil { - return nil, err - } - return secp256k1.ToPrivateKey(bytes) -} - -// Return all private keys controlled by this user -func (u *user) getKeys() ([]*secp256k1.PrivateKey, error) { - addrs, err := u.getAddresses() - if err != nil { - return nil, err - } - keys := make([]*secp256k1.PrivateKey, len(addrs)) - for i, addr := range addrs { - key, err := u.getKey(addr) - if err != nil { - return nil, err - } - keys[i] = key - } - return keys, nil -} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 879cb8988e..e85dad52d4 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -1731,23 +1731,6 @@ func (vm *VM) startContinuousProfiler() { <-vm.shutdownChan } -func (vm *VM) estimateBaseFee(ctx context.Context) (*big.Int, error) { - // Get the base fee to use - baseFee, err := vm.eth.APIBackend.EstimateBaseFee(ctx) - if err != nil { - return nil, err - } - if baseFee == nil { - baseFee = initialBaseFee - } else { - // give some breathing room - baseFee.Mul(baseFee, big.NewInt(11)) - baseFee.Div(baseFee, big.NewInt(10)) - } - - return baseFee, nil -} - // readLastAccepted reads the last accepted hash from [acceptedBlockDB] and returns the // last accepted block hash and height by reading directly from [vm.chaindb] instead of relying // on [chain]. diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 507c8d3a94..340b946896 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -32,7 +32,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/api/keystore" avalancheatomic "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/memdb" @@ -46,7 +45,6 @@ import ( "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/hashing" - "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" @@ -78,8 +76,6 @@ var ( testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] testShortIDAddrs []ids.ShortID testAvaxAssetID = ids.ID{1, 2, 3} - username = "Johns" - password = "CjasdjhiPeirbSenfeI13" // #nosec G101 genesisJSON = func(cfg *params.ChainConfig) string { g := new(core.Genesis) @@ -260,12 +256,6 @@ func setupGenesis( // The caller of this function is responsible for unlocking. ctx.Lock.Lock() - userKeystore := keystore.New(logging.NoLog{}, memdb.New()) - if err := userKeystore.CreateUser(username, password); err != nil { - t.Fatal(err) - } - ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID) - issuer := make(chan commonEng.Message, 1) prefixedDB := prefixdb.New([]byte{1}, baseDB) return ctx, prefixedDB, genesisBytes, issuer, atomicMemory