aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/evm/client.go174
-rw-r--r--plugin/evm/export_tx.go2
-rw-r--r--plugin/evm/import_tx.go2
-rw-r--r--plugin/evm/import_tx_test.go4
-rw-r--r--plugin/evm/service.go105
-rw-r--r--plugin/evm/static_service.go22
-rw-r--r--plugin/evm/tx.go6
-rw-r--r--plugin/evm/user.go4
-rw-r--r--plugin/evm/vm.go57
-rw-r--r--plugin/evm/vm_test.go19
10 files changed, 283 insertions, 112 deletions
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 65ef3a2..2bb06df 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
@@ -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 }
@@ -127,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
}
@@ -147,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)
}
@@ -232,8 +247,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 +260,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 +268,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 +305,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
@@ -304,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 {
@@ -356,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
@@ -407,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)
@@ -422,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
}
@@ -430,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..7b0fa8b 100644
--- a/plugin/evm/static_service.go
+++ b/plugin/evm/static_service.go
@@ -7,16 +7,32 @@ import (
"context"
"encoding/json"
- "github.com/ava-labs/coreth/core"
"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) (formatting.CB58, error) {
+func (*StaticService) BuildGenesis(_ context.Context, args *core.Genesis) (*BuildGenesisReply, error) {
bytes, err := json.Marshal(args)
- return formatting.CB58{Bytes: 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/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..58ab600 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{}),
+ Codec.RegisterCodec(codecVersion, 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..0e9c102 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))
@@ -67,7 +67,11 @@ func BuildGenesisTest(t *testing.T) []byte {
if err != nil {
t.Fatalf("Failed to create test genesis")
}
- return genesisReply.Bytes
+ genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to decode genesis bytes: %s", err)
+ }
+ return genesisBytes
}
func NewContext() *snow.Context {
@@ -102,7 +106,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 +119,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,