From 659876ec797398e97dc2fd16d7abfb2bb08d211b Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Fri, 13 Nov 2020 15:01:08 -0500 Subject: Add assetID parsing to export API --- plugin/evm/service.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'plugin') diff --git a/plugin/evm/service.go b/plugin/evm/service.go index 65ef3a2..fc7ed69 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -91,6 +91,17 @@ func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { return api.vm.tryBlockGen() } +// 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) + } +} + // ClientVersion returns the version of the vm running func (service *AvaxAPI) ClientVersion() string { return version } @@ -232,8 +243,6 @@ func (service *AvaxAPI) Import(_ *http.Request, args *ImportArgs, response *api. type ExportAVAXArgs struct { api.UserPass - // AssetID of the tokens - AssetID ids.ID `json:"assetID"` // Amount of asset to send Amount json.Uint64 `json:"amount"` @@ -247,7 +256,7 @@ type ExportAVAXArgs struct { func (service *AvaxAPI) ExportAVAX(_ *http.Request, args *ExportAVAXArgs, response *api.JSONTxID) error { return service.Export(nil, &ExportArgs{ ExportAVAXArgs: *args, - AssetID: service.vm.ctx.AVAXAssetID, + AssetID: service.vm.ctx.AVAXAssetID.String(), }, response) } @@ -255,15 +264,17 @@ func (service *AvaxAPI) ExportAVAX(_ *http.Request, args *ExportAVAXArgs, respon type ExportArgs struct { ExportAVAXArgs // AssetID of the tokens - AssetID ids.ID `json:"assetID"` + AssetID string `json:"assetID"` } // 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 *ExportArgs, response *api.JSONTxID) error { log.Info("EVM: Export called") - if args.AssetID == ids.Empty { - return fmt.Errorf("assetID is required") + + assetID, err := service.parseAssetID(args.AssetID) + if err != nil { + return err } if args.Amount == 0 { @@ -290,7 +301,7 @@ func (service *AvaxAPI) Export(_ *http.Request, args *ExportArgs, response *api. // Create the transaction tx, err := service.vm.newExportTx( - args.AssetID, // AssetID + assetID, // AssetID uint64(args.Amount), // Amount chainID, // ID of the chain to send the funds to to, // Address -- cgit v1.2.3-70-g09d2 From f7d86c70023b86801794f99ce15e39fe811aba66 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Fri, 20 Nov 2020 10:27:09 -0500 Subject: Bump version and updated hacked list --- notes/hacked-list.txt | 1 - plugin/evm/service.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'plugin') diff --git a/notes/hacked-list.txt b/notes/hacked-list.txt index 0ae1db0..f4545ba 100644 --- a/notes/hacked-list.txt +++ b/notes/hacked-list.txt @@ -31,7 +31,6 @@ ./eth/gen_config.go ./eth/tracers/internal/tracers/assets.go ./ethclient/ethclient.go -./ethclient/ethclient_test.go ./ethclient/signer.go ./internal/ethapi/api.go ./internal/ethapi/backend.go diff --git a/plugin/evm/service.go b/plugin/evm/service.go index fc7ed69..49bb862 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -24,7 +24,7 @@ import ( ) const ( - version = "coreth-v0.3.14" + version = "coreth-v0.3.15" ) // test constants -- cgit v1.2.3-70-g09d2 From 61479754d935e36993f7144d70d7c518cdb26a36 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Wed, 25 Nov 2020 11:20:36 -0500 Subject: Add avax API client and upgrade to avalanchego v1.0.5-client --- go.mod | 2 +- go.sum | 2 + plugin/evm/client.go | 174 +++++++++++++++++++++++++++++++++++++++++++ plugin/evm/export_tx.go | 2 +- plugin/evm/import_tx.go | 2 +- plugin/evm/import_tx_test.go | 4 +- plugin/evm/service.go | 78 +++++-------------- plugin/evm/static_service.go | 5 +- plugin/evm/tx.go | 6 +- plugin/evm/user.go | 4 +- plugin/evm/vm.go | 57 +++++++------- plugin/evm/vm_test.go | 17 +++-- 12 files changed, 247 insertions(+), 106 deletions(-) create mode 100644 plugin/evm/client.go (limited to 'plugin') diff --git a/go.mod b/go.mod index 7431960..fc27ba4 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/VictoriaMetrics/fastcache v1.5.7 - github.com/ava-labs/avalanchego v1.0.5 + github.com/ava-labs/avalanchego v1.0.5-client github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.7.1 github.com/edsrzf/mmap-go v1.0.0 diff --git a/go.sum b/go.sum index e8af04f..6232801 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1: github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/ava-labs/avalanchego v1.0.5-client h1:/tvPyl6T3Ujn8RHeQ83sezt944XZX6BMlKkp1J+I/ss= +github.com/ava-labs/avalanchego v1.0.5-client/go.mod h1:Q/I7LaMv2EYL8plNVRbcpBJsDk2py2XISfov0KK1MgU= github.com/ava-labs/avalanchego v1.0.5 h1:zjBaM/9l2VjnL7j6SEwmqKjPie1W9NSEDLrd2ZotMCA= github.com/ava-labs/avalanchego v1.0.5/go.mod h1:4GfedhY9S6k/SOUeMzDh6cuLoPAtnkFsL4R89xg5wf0= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= diff --git a/plugin/evm/client.go b/plugin/evm/client.go new file mode 100644 index 0000000..0817545 --- /dev/null +++ b/plugin/evm/client.go @@ -0,0 +1,174 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "fmt" + "time" + + "github.com/ava-labs/avalanchego/api" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/formatting" + cjson "github.com/ava-labs/avalanchego/utils/json" + "github.com/ava-labs/avalanchego/utils/rpc" +) + +// Client ... +type Client struct { + requester rpc.EndpointRequester +} + +// NewClient returns a Client for interacting with EVM [chain] +func NewClient(uri, chain string, requestTimeout time.Duration) *Client { + return &Client{ + requester: rpc.NewEndpointRequester(uri, fmt.Sprintf("/ext/bc/%s/avax", chain), "avax", requestTimeout), + } +} + +// NewCChainClient returns a Client for interacting with the C Chain +func NewCChainClient(uri string, requestTimeout time.Duration) *Client { + return NewClient(uri, "C", requestTimeout) +} + +// IssueTx issues a transaction to a node and returns the TxID +func (c *Client) IssueTx(txBytes []byte) (ids.ID, error) { + res := &api.JSONTxID{} + txStr, err := formatting.Encode(formatting.Hex, txBytes) + if err != nil { + return res.TxID, fmt.Errorf("problem hex encoding bytes: %w", err) + } + err = c.requester.SendRequest("issueTx", &api.FormattedTx{ + Tx: txStr, + Encoding: formatting.Hex, + }, res) + return res.TxID, err +} + +// GetTxStatus returns the status of [txID] +// func (c *Client) GetTxStatus(txID ids.ID) (choices.Status, error) { +// res := &GetTxStatusReply{} +// err := c.requester.SendRequest("getTxStatus", &api.JSONTxID{ +// TxID: txID, +// }, res) +// return res.Status, err +// } + +// GetTx returns the byte representation of [txID] +func (c *Client) GetTx(txID ids.ID) ([]byte, error) { + res := &api.FormattedTx{} + err := c.requester.SendRequest("getTx", &api.GetTxArgs{ + TxID: txID, + Encoding: formatting.Hex, + }, res) + if err != nil { + return nil, err + } + + return formatting.Decode(formatting.Hex, res.Tx) +} + +// GetUTXOs returns the byte representation of the UTXOs controlled by [addrs] +func (c *Client) GetUTXOs(addrs []string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error) { + res := &api.GetUTXOsReply{} + err := c.requester.SendRequest("getUTXOs", &api.GetUTXOsArgs{ + Addresses: addrs, + Limit: cjson.Uint32(limit), + StartIndex: api.Index{ + Address: startAddress, + UTXO: startUTXOID, + }, + Encoding: formatting.Hex, + }, res) + if err != nil { + return nil, api.Index{}, err + } + + utxos := make([][]byte, len(res.UTXOs)) + for i, utxo := range res.UTXOs { + b, err := formatting.Decode(formatting.Hex, utxo) + if err != nil { + return nil, api.Index{}, err + } + utxos[i] = b + } + return utxos, res.EndIndex, nil +} + +// CreateAddress creates a new address controlled by [user] +func (c *Client) CreateAddress(user api.UserPass) (string, error) { + res := &api.JSONAddress{} + err := c.requester.SendRequest("createAddress", &user, res) + return res.Address, err +} + +// ListAddresses returns all addresses on this chain controlled by [user] +func (c *Client) ListAddresses(user api.UserPass) ([]string, error) { + res := &api.JSONAddresses{} + err := c.requester.SendRequest("listAddresses", &user, res) + return res.Addresses, err +} + +// ExportKey returns the private key corresponding to [addr] controlled by [user] +// in both Avalanche standard format and hex format +func (c *Client) ExportKey(user api.UserPass, addr string) (string, string, error) { + res := &ExportKeyReply{} + err := c.requester.SendRequest("exportKey", &ExportKeyArgs{ + UserPass: user, + Address: addr, + }, res) + return res.PrivateKey, res.PrivateKeyHex, err +} + +// ImportKey imports [privateKey] to [user] +func (c *Client) ImportKey(user api.UserPass, privateKey string) (string, error) { + res := &api.JSONAddress{} + err := c.requester.SendRequest("importKey", &ImportKeyArgs{ + UserPass: user, + PrivateKey: privateKey, + }, res) + return res.Address, err +} + +// Import sends an import transaction to import funds from [sourceChain] and +// returns the ID of the newly created transaction +func (c *Client) Import(user api.UserPass, to, sourceChain string) (ids.ID, error) { + res := &api.JSONTxID{} + err := c.requester.SendRequest("import", &ImportArgs{ + UserPass: user, + To: to, + SourceChain: sourceChain, + }, res) + 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( + user api.UserPass, + amount uint64, + to string, +) (ids.ID, error) { + return c.Export(user, amount, to, "AVAX") +} + +// 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( + user api.UserPass, + amount uint64, + to string, + assetID string, +) (ids.ID, error) { + res := &api.JSONTxID{} + err := c.requester.SendRequest("export", &ExportArgs{ + ExportAVAXArgs: ExportAVAXArgs{ + UserPass: user, + Amount: cjson.Uint64(amount), + To: to, + }, + AssetID: assetID, + }, res) + return res.TxID, err +} diff --git a/plugin/evm/export_tx.go b/plugin/evm/export_tx.go index ed069d4..2735573 100644 --- a/plugin/evm/export_tx.go +++ b/plugin/evm/export_tx.go @@ -149,7 +149,7 @@ func (tx *UnsignedExportTx) Accept(ctx *snow.Context, _ database.Batch) error { Out: out.Out, } - utxoBytes, err := Codec.Marshal(utxo) + utxoBytes, err := Codec.Marshal(codecVersion, utxo) if err != nil { return err } diff --git a/plugin/evm/import_tx.go b/plugin/evm/import_tx.go index 23dbc5f..1ec394c 100644 --- a/plugin/evm/import_tx.go +++ b/plugin/evm/import_tx.go @@ -135,7 +135,7 @@ func (tx *UnsignedImportTx) SemanticVerify( utxoBytes := allUTXOBytes[i] utxo := &avax.UTXO{} - if err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil { + if _, err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil { return tempError{err} } diff --git a/plugin/evm/import_tx_test.go b/plugin/evm/import_tx_test.go index 53b9494..973802a 100644 --- a/plugin/evm/import_tx_test.go +++ b/plugin/evm/import_tx_test.go @@ -153,7 +153,7 @@ func TestImportTxSemanticVerify(t *testing.T) { }, }, } - utxoBytes, err := vm.codec.Marshal(utxo) + utxoBytes, err := vm.codec.Marshal(codecVersion, utxo) if err != nil { t.Fatal(err) } @@ -312,7 +312,7 @@ func TestNewImportTx(t *testing.T) { }, }, } - utxoBytes, err := vm.codec.Marshal(utxo) + utxoBytes, err := vm.codec.Marshal(codecVersion, utxo) if err != nil { t.Fatal(err) } diff --git a/plugin/evm/service.go b/plugin/evm/service.go index 49bb862..2bb06df 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -138,7 +138,11 @@ func (service *AvaxAPI) ExportKey(r *http.Request, args *ExportKeyArgs, reply *E if err != nil { return fmt.Errorf("problem retrieving private key: %w", err) } - reply.PrivateKey = constants.SecretKeyPrefix + formatting.CB58{Bytes: sk.Bytes()}.String() + encodedKey, err := formatting.Encode(formatting.CB58, sk.Bytes()) + if err != nil { + return fmt.Errorf("problem encoding bytes as cb58: %w", err) + } + reply.PrivateKey = constants.SecretKeyPrefix + encodedKey reply.PrivateKeyHex = hexutil.Encode(sk.Bytes()) return nil } @@ -158,13 +162,13 @@ func (service *AvaxAPI) ImportKey(r *http.Request, args *ImportKeyArgs, reply *a } trimmedPrivateKey := strings.TrimPrefix(args.PrivateKey, constants.SecretKeyPrefix) - formattedPrivateKey := formatting.CB58{} - if err := formattedPrivateKey.FromString(trimmedPrivateKey); err != nil { + pkBytes, err := formatting.Decode(formatting.CB58, trimmedPrivateKey) + if err != nil { return fmt.Errorf("problem parsing private key: %w", err) } factory := crypto.FactorySECP256K1R{} - skIntf, err := factory.ToPrivateKey(formattedPrivateKey.Bytes) + skIntf, err := factory.ToPrivateKey(pkBytes) if err != nil { return fmt.Errorf("problem parsing private key: %w", err) } @@ -315,49 +319,8 @@ func (service *AvaxAPI) Export(_ *http.Request, args *ExportArgs, response *api. return service.vm.issueTx(tx) } -// Index is an address and an associated UTXO. -// Marks a starting or stopping point when fetching UTXOs. Used for pagination. -type Index struct { - Address string `json:"address"` // The address as a string - UTXO string `json:"utxo"` // The UTXO ID as a string -} - -// GetUTXOsArgs are arguments for passing into GetUTXOs. -// Gets the UTXOs that reference at least one address in [Addresses]. -// Returns at most [limit] addresses. -// If specified, [SourceChain] is the chain where the atomic UTXOs were exported from. If not specified, -// then GetUTXOs returns an error since the C Chain only has atomic UTXOs. -// If [limit] == 0 or > [maxUTXOsToFetch], fetches up to [maxUTXOsToFetch]. -// [StartIndex] defines where to start fetching UTXOs (for pagination.) -// UTXOs fetched are from addresses equal to or greater than [StartIndex.Address] -// For address [StartIndex.Address], only UTXOs with IDs greater than [StartIndex.UTXO] will be returned. -// If [StartIndex] is omitted, gets all UTXOs. -// If GetUTXOs is called multiple times, with our without [StartIndex], it is not guaranteed -// that returned UTXOs are unique. That is, the same UTXO may appear in the response of multiple calls. -type GetUTXOsArgs struct { - Addresses []string `json:"addresses"` - SourceChain string `json:"sourceChain"` - Limit json.Uint32 `json:"limit"` - StartIndex Index `json:"startIndex"` - Encoding string `json:"encoding"` -} - -// GetUTXOsReply defines the GetUTXOs replies returned from the API -type GetUTXOsReply struct { - // Number of UTXOs returned - NumFetched json.Uint64 `json:"numFetched"` - // The UTXOs - UTXOs []string `json:"utxos"` - // The last UTXO that was returned, and the address it corresponds to. - // Used for pagination. To get the rest of the UTXOs, call GetUTXOs - // again and set [StartIndex] to this value. - EndIndex Index `json:"endIndex"` - // Encoding specifies the encoding format the UTXOs are returned in - Encoding string `json:"encoding"` -} - // GetUTXOs gets all utxos for passed in addresses -func (service *AvaxAPI) GetUTXOs(r *http.Request, args *GetUTXOsArgs, reply *GetUTXOsReply) error { +func (service *AvaxAPI) GetUTXOs(r *http.Request, args *api.GetUTXOsArgs, reply *api.GetUTXOsReply) error { service.vm.ctx.Log.Info("EVM: GetUTXOs called for with %s", args.Addresses) if len(args.Addresses) == 0 { @@ -367,11 +330,6 @@ func (service *AvaxAPI) GetUTXOs(r *http.Request, args *GetUTXOsArgs, reply *Get return fmt.Errorf("number of addresses given, %d, exceeds maximum, %d", len(args.Addresses), maxGetUTXOsAddrs) } - encoding, err := service.vm.encodingManager.GetEncoding(args.Encoding) - if err != nil { - return fmt.Errorf("problem getting encoding formatter for '%s': %w", args.Encoding, err) - } - sourceChain := ids.ID{} if args.SourceChain == "" { return errNoSourceChain @@ -418,11 +376,15 @@ func (service *AvaxAPI) GetUTXOs(r *http.Request, args *GetUTXOsArgs, reply *Get reply.UTXOs = make([]string, len(utxos)) for i, utxo := range utxos { - b, err := service.vm.codec.Marshal(utxo) + b, err := service.vm.codec.Marshal(codecVersion, utxo) if err != nil { return fmt.Errorf("problem marshalling UTXO: %w", err) } - reply.UTXOs[i] = encoding.ConvertBytes(b) + str, err := formatting.Encode(args.Encoding, b) + if err != nil { + return fmt.Errorf("problem encoding utxo: %w", err) + } + reply.UTXOs[i] = str } endAddress, err := service.vm.FormatLocalAddress(endAddr) @@ -433,7 +395,7 @@ func (service *AvaxAPI) GetUTXOs(r *http.Request, args *GetUTXOsArgs, reply *Get reply.EndIndex.Address = endAddress reply.EndIndex.UTXO = endUTXOID.String() reply.NumFetched = json.Uint64(len(utxos)) - reply.Encoding = encoding.Encoding() + reply.Encoding = args.Encoding return nil } @@ -441,17 +403,13 @@ func (service *AvaxAPI) GetUTXOs(r *http.Request, args *GetUTXOsArgs, reply *Get func (service *AvaxAPI) IssueTx(r *http.Request, args *api.FormattedTx, response *api.JSONTxID) error { log.Info("EVM: IssueTx called") - encoding, err := service.vm.encodingManager.GetEncoding(args.Encoding) - if err != nil { - return fmt.Errorf("problem getting encoding formatter for '%s': %w", args.Encoding, err) - } - txBytes, err := encoding.ConvertString(args.Tx) + txBytes, err := formatting.Decode(args.Encoding, args.Tx) if err != nil { return fmt.Errorf("problem decoding transaction: %w", err) } tx := &Tx{} - if err := service.vm.codec.Unmarshal(txBytes, tx); err != nil { + if _, err := service.vm.codec.Unmarshal(txBytes, tx); err != nil { return fmt.Errorf("problem parsing transaction: %w", err) } if err := tx.Sign(service.vm.codec, nil); err != nil { diff --git a/plugin/evm/static_service.go b/plugin/evm/static_service.go index 1e48734..1b45939 100644 --- a/plugin/evm/static_service.go +++ b/plugin/evm/static_service.go @@ -8,7 +8,6 @@ import ( "encoding/json" "github.com/ava-labs/coreth/core" - "github.com/ava-labs/avalanchego/utils/formatting" ) // StaticService defines the static API services exposed by the evm @@ -16,7 +15,7 @@ type StaticService struct{} // BuildGenesis returns the UTXOs such that at least one address in [args.Addresses] is // referenced in the UTXO. -func (*StaticService) BuildGenesis(_ context.Context, args *core.Genesis) (formatting.CB58, error) { +func (*StaticService) BuildGenesis(_ context.Context, args *core.Genesis) ([]byte, error) { bytes, err := json.Marshal(args) - return formatting.CB58{Bytes: bytes}, err + return bytes, err } diff --git a/plugin/evm/tx.go b/plugin/evm/tx.go index 82d4c10..1c0ce48 100644 --- a/plugin/evm/tx.go +++ b/plugin/evm/tx.go @@ -89,8 +89,8 @@ type Tx struct { // (*secp256k1fx.Credential) // Sign this transaction with the provided signers -func (tx *Tx) Sign(c codec.Codec, signers [][]*crypto.PrivateKeySECP256K1R) error { - unsignedBytes, err := c.Marshal(&tx.UnsignedTx) +func (tx *Tx) Sign(c codec.Manager, signers [][]*crypto.PrivateKeySECP256K1R) error { + unsignedBytes, err := c.Marshal(codecVersion, &tx.UnsignedTx) if err != nil { return fmt.Errorf("couldn't marshal UnsignedTx: %w", err) } @@ -111,7 +111,7 @@ func (tx *Tx) Sign(c codec.Codec, signers [][]*crypto.PrivateKeySECP256K1R) erro tx.Creds = append(tx.Creds, cred) // Attach credential } - signedBytes, err := c.Marshal(tx) + signedBytes, err := c.Marshal(codecVersion, tx) if err != nil { return fmt.Errorf("couldn't marshal Tx: %w", err) } diff --git a/plugin/evm/user.go b/plugin/evm/user.go index 0ab1863..fc4587e 100644 --- a/plugin/evm/user.go +++ b/plugin/evm/user.go @@ -48,7 +48,7 @@ func (u *user) getAddresses() ([]common.Address, error) { return nil, err } addresses := []common.Address{} - if err := Codec.Unmarshal(bytes, &addresses); err != nil { + if _, err := Codec.Unmarshal(bytes, &addresses); err != nil { return nil, err } return addresses, nil @@ -94,7 +94,7 @@ func (u *user) putAddress(privKey *crypto.PrivateKeySECP256K1R) error { } } addresses = append(addresses, address) - bytes, err := Codec.Marshal(addresses) + bytes, err := Codec.Marshal(codecVersion, addresses) if err != nil { return err } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 284a772..aaf7f10 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -70,6 +70,7 @@ const ( batchSize = 250 maxUTXOsToFetch = 1024 blockCacheSize = 1 << 10 // 1024 + codecVersion = uint16(0) ) const ( @@ -110,26 +111,29 @@ func maxDuration(x, y time.Duration) time.Duration { } // Codec does serialization and deserialization -var Codec codec.Codec +var Codec codec.Manager func init() { - Codec = codec.NewDefault() + Codec = codec.NewDefaultManager() + c := codec.NewDefault() errs := wrappers.Errs{} errs.Add( - Codec.RegisterType(&UnsignedImportTx{}), - Codec.RegisterType(&UnsignedExportTx{}), + c.RegisterType(&UnsignedImportTx{}), + c.RegisterType(&UnsignedExportTx{}), ) - Codec.Skip(3) + c.Skip(3) errs.Add( - Codec.RegisterType(&secp256k1fx.TransferInput{}), - Codec.RegisterType(&secp256k1fx.MintOutput{}), - Codec.RegisterType(&secp256k1fx.TransferOutput{}), - Codec.RegisterType(&secp256k1fx.MintOperation{}), - Codec.RegisterType(&secp256k1fx.Credential{}), - Codec.RegisterType(&secp256k1fx.Input{}), - Codec.RegisterType(&secp256k1fx.OutputOwners{}), + c.RegisterType(&secp256k1fx.TransferInput{}), + c.RegisterType(&secp256k1fx.MintOutput{}), + c.RegisterType(&secp256k1fx.TransferOutput{}), + c.RegisterType(&secp256k1fx.MintOperation{}), + c.RegisterType(&secp256k1fx.Credential{}), + c.RegisterType(&secp256k1fx.Input{}), + c.RegisterType(&secp256k1fx.OutputOwners{}), ) + + errs.Add(Codec.RegisterCodec(0, c)) if errs.Errored() { panic(errs.Err) } @@ -139,8 +143,7 @@ func init() { type VM struct { ctx *snow.Context - CLIConfig CommandLineConfig - encodingManager formatting.EncodingManager + CLIConfig CommandLineConfig chainID *big.Int networkID uint64 @@ -173,7 +176,8 @@ type VM struct { txSubmitChan <-chan struct{} atomicTxSubmitChan chan struct{} shutdownSubmitChan chan struct{} - codec codec.Codec + baseCodec codec.Codec + codec codec.Manager clock timer.Clock txFee uint64 pendingAtomicTxs chan *Tx @@ -187,7 +191,7 @@ type VM struct { func (vm *VM) getAtomicTx(block *types.Block) *Tx { extdata := block.ExtraData() atx := new(Tx) - if err := vm.codec.Unmarshal(extdata, atx); err != nil { + if _, err := vm.codec.Unmarshal(extdata, atx); err != nil { return nil } atx.Sign(vm.codec, nil) @@ -195,7 +199,10 @@ func (vm *VM) getAtomicTx(block *types.Block) *Tx { } // Codec implements the secp256k1fx interface -func (vm *VM) Codec() codec.Codec { return codec.NewDefault() } +func (vm *VM) Codec() codec.Manager { return vm.codec } + +// CodecRegistry implements the secp256k1fx interface +func (vm *VM) CodecRegistry() codec.Registry { return vm.baseCodec } // Clock implements the secp256k1fx interface func (vm *VM) Clock() *timer.Clock { return &vm.clock } @@ -221,12 +228,6 @@ func (vm *VM) Initialize( return vm.CLIConfig.ParsingError } - encodingManager, err := formatting.NewEncodingManager(formatting.CB58Encoding) - if err != nil { - return fmt.Errorf("problem creating encoding manager: %w", err) - } - vm.encodingManager = encodingManager - if len(fxs) > 0 { return errUnsupportedFXs } @@ -284,7 +285,7 @@ func (vm *VM) Initialize( vm.newBlockChan <- nil return nil, err } - raw, _ := vm.codec.Marshal(atx) + raw, _ := vm.codec.Marshal(codecVersion, atx) return raw, nil default: if len(txs) == 0 { @@ -382,10 +383,14 @@ func (vm *VM) Initialize( vm.genesisHash = chain.GetGenesisBlock().Hash() log.Info(fmt.Sprintf("lastAccepted = %s", vm.lastAccepted.ethBlock.Hash().Hex())) - // TODO: shutdown this go routine vm.shutdownWg.Add(1) go vm.ctx.Log.RecoverAndPanic(vm.awaitSubmittedTxs) vm.codec = Codec + // The Codec explicitly registers the types it requires from the secp256k1fx + // so [vm.baseCodec] is a dummy codec use to fulfill the secp256k1fx VM + // interface. The fx will register all of its types, which can be safely + // ignored by the VM's codec. + vm.baseCodec = codec.NewDefault() return vm.fx.Initialize(vm) } @@ -857,7 +862,7 @@ func (vm *VM) GetAtomicUTXOs( utxos := make([]*avax.UTXO, len(allUTXOBytes)) for i, utxoBytes := range allUTXOBytes { utxo := &avax.UTXO{} - if err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil { + if _, err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil { return nil, ids.ShortID{}, ids.ID{}, fmt.Errorf("error parsing UTXO: %w", err) } utxos[i] = utxo diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 020b663..1b894ce 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -36,7 +36,7 @@ var ( ) func init() { - cb58 := formatting.CB58{} + var b []byte factory := crypto.FactorySECP256K1R{} for _, key := range []string{ @@ -44,8 +44,8 @@ func init() { "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", } { - _ = cb58.FromString(key) - pk, _ := factory.ToPrivateKey(cb58.Bytes) + b, _ = formatting.Decode(formatting.CB58, key) + pk, _ := factory.ToPrivateKey(b) secpKey := pk.(*crypto.PrivateKeySECP256K1R) testKeys = append(testKeys, secpKey) testEthAddrs = append(testEthAddrs, GetEthAddress(secpKey)) @@ -63,11 +63,11 @@ func BuildGenesisTest(t *testing.T) []byte { if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil { t.Fatalf("Problem unmarshaling genesis JSON: %s", err) } - genesisReply, err := ss.BuildGenesis(nil, genesis) + genesisBytes, err := ss.BuildGenesis(nil, genesis) if err != nil { t.Fatalf("Failed to create test genesis") } - return genesisReply.Bytes + return genesisBytes } func NewContext() *snow.Context { @@ -102,7 +102,10 @@ func GenesisVM(t *testing.T, finishBootstrapping bool) (chan engCommon.Message, // The caller of this function is responsible for unlocking. ctx.Lock.Lock() - userKeystore := keystore.CreateTestKeystore() + userKeystore, err := keystore.CreateTestKeystore() + if err != nil { + t.Fatal(err) + } if err := userKeystore.AddUser(username, password); err != nil { t.Fatal(err) } @@ -112,7 +115,7 @@ func GenesisVM(t *testing.T, finishBootstrapping bool) (chan engCommon.Message, vm := &VM{ txFee: testTxFee, } - err := vm.Initialize( + err = vm.Initialize( ctx, prefixdb.New([]byte{1}, baseDB), genesisBytes, -- cgit v1.2.3-70-g09d2 From 627bc7f7fd75d385e623c3c5177c5aeb639a0e52 Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Sun, 29 Nov 2020 14:38:44 -0500 Subject: Address comments --- coreth.go | 5 +---- plugin/evm/static_service.go | 21 +++++++++++++++++++-- plugin/evm/vm.go | 2 +- plugin/evm/vm_test.go | 6 +++++- 4 files changed, 26 insertions(+), 8 deletions(-) (limited to 'plugin') diff --git a/coreth.go b/coreth.go index 01bc9af..351a14d 100644 --- a/coreth.go +++ b/coreth.go @@ -2,7 +2,6 @@ package coreth import ( "crypto/ecdsa" - //"fmt" "io" "os" @@ -18,10 +17,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/trie" - - //"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie" "github.com/mattn/go-isatty" ) diff --git a/plugin/evm/static_service.go b/plugin/evm/static_service.go index 1b45939..7b0fa8b 100644 --- a/plugin/evm/static_service.go +++ b/plugin/evm/static_service.go @@ -7,15 +7,32 @@ import ( "context" "encoding/json" + "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/coreth/core" ) // StaticService defines the static API services exposed by the evm type StaticService struct{} +// BuildGenesisReply is the reply from BuildGenesis +type BuildGenesisReply struct { + Bytes string `json:"bytes"` + Encoding formatting.Encoding `json:"encoding"` +} + // BuildGenesis returns the UTXOs such that at least one address in [args.Addresses] is // referenced in the UTXO. -func (*StaticService) BuildGenesis(_ context.Context, args *core.Genesis) ([]byte, error) { +func (*StaticService) BuildGenesis(_ context.Context, args *core.Genesis) (*BuildGenesisReply, error) { bytes, err := json.Marshal(args) - return bytes, err + if err != nil { + return nil, err + } + bytesStr, err := formatting.Encode(formatting.Hex, bytes) + if err != nil { + return nil, err + } + return &BuildGenesisReply{ + Bytes: bytesStr, + Encoding: formatting.Hex, + }, nil } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index aaf7f10..58ab600 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -131,9 +131,9 @@ func init() { c.RegisterType(&secp256k1fx.Credential{}), c.RegisterType(&secp256k1fx.Input{}), c.RegisterType(&secp256k1fx.OutputOwners{}), + Codec.RegisterCodec(codecVersion, c), ) - errs.Add(Codec.RegisterCodec(0, c)) if errs.Errored() { panic(errs.Err) } diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 1b894ce..2993b3b 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -63,10 +63,14 @@ func BuildGenesisTest(t *testing.T) []byte { if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil { t.Fatalf("Problem unmarshaling genesis JSON: %s", err) } - genesisBytes, err := ss.BuildGenesis(nil, genesis) + genesisReply, err := ss.BuildGenesis(nil, genesis) if err != nil { t.Fatalf("Failed to create test genesis") } + genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes) + if err != nil { + t.Fatalf("Failed to decode genesis bytes: %w", err) + } return genesisBytes } -- cgit v1.2.3-70-g09d2 From 415b1eb564efc70cf7e673358286e19de8551fbf Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Sun, 29 Nov 2020 15:23:59 -0500 Subject: Fix test formatting directive --- plugin/evm/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugin') diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 2993b3b..0e9c102 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -69,7 +69,7 @@ func BuildGenesisTest(t *testing.T) []byte { } genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes) if err != nil { - t.Fatalf("Failed to decode genesis bytes: %w", err) + t.Fatalf("Failed to decode genesis bytes: %s", err) } return genesisBytes } -- cgit v1.2.3-70-g09d2