From fe99c39555746b433b9d879ec5dfd244b01fe8c5 Mon Sep 17 00:00:00 2001 From: nathan haim Date: Thu, 27 Jul 2023 01:20:11 +0200 Subject: [PATCH] create TypeID for Actions/Auths + delete reflection in Registry (#297) * create TypeID for Actions/Auths + delete reflection in Registry #228 * actions & auth: put ID values explicitly instead of using iota * function signature delete useless line * resolve last lint issues * reword Note * change register items limit --- chain/block.go | 12 ++--- chain/dependencies.go | 2 + chain/transaction.go | 43 +++++----------- codec/type_parser.go | 26 ++-------- codec/type_parser_test.go | 51 ++++++++----------- examples/morpheusvm/actions/common.go | 9 ++++ examples/morpheusvm/actions/transfer.go | 4 ++ examples/morpheusvm/auth/common.go | 9 ++++ examples/morpheusvm/auth/ed25519.go | 4 ++ examples/morpheusvm/registry/registry.go | 4 +- .../tests/integration/integration_test.go | 5 +- examples/tokenvm/actions/burn_asset.go | 4 ++ examples/tokenvm/actions/close_order.go | 4 ++ examples/tokenvm/actions/common.go | 18 +++++++ examples/tokenvm/actions/create_asset.go | 4 ++ examples/tokenvm/actions/create_order.go | 4 ++ examples/tokenvm/actions/export_asset.go | 4 ++ examples/tokenvm/actions/fill_order.go | 4 ++ examples/tokenvm/actions/import_asset.go | 4 ++ examples/tokenvm/actions/mint_asset.go | 4 ++ examples/tokenvm/actions/modify_asset.go | 4 ++ examples/tokenvm/actions/transfer.go | 4 ++ examples/tokenvm/auth/common.go | 9 ++++ examples/tokenvm/auth/ed25519.go | 4 ++ examples/tokenvm/registry/registry.go | 22 ++++---- .../tests/integration/integration_test.go | 40 ++++++--------- gossiper/manual.go | 3 +- gossiper/proposer.go | 6 +-- 28 files changed, 174 insertions(+), 137 deletions(-) create mode 100644 examples/morpheusvm/actions/common.go create mode 100644 examples/morpheusvm/auth/common.go create mode 100644 examples/tokenvm/actions/common.go create mode 100644 examples/tokenvm/auth/common.go diff --git a/chain/block.go b/chain/block.go index bd6d693725..417966b1e1 100644 --- a/chain/block.go +++ b/chain/block.go @@ -206,8 +206,7 @@ func ParseStatefulBlock( } if len(source) == 0 { - actionRegistry, authRegistry := vm.Registry() - nsource, err := blk.Marshal(actionRegistry, authRegistry) + nsource, err := blk.Marshal() if err != nil { return nil, err } @@ -242,7 +241,7 @@ func (b *StatelessBlock) initializeBuilt( _, span := b.vm.Tracer().Start(ctx, "StatelessBlock.initializeBuilt") defer span.End() - blk, err := b.StatefulBlock.Marshal(b.vm.Registry()) + blk, err := b.StatefulBlock.Marshal() if err != nil { return err } @@ -760,10 +759,7 @@ func (b *StatelessBlock) Results() []*Result { return b.results } -func (b *StatefulBlock) Marshal( - actionRegistry ActionRegistry, - authRegistry AuthRegistry, -) ([]byte, error) { +func (b *StatefulBlock) Marshal() ([]byte, error) { size := consts.IDLen + consts.Uint64Len + consts.Uint64Len + consts.Uint64Len + window.WindowSliceSize + consts.IntLen + codec.CummSize(b.Txs) + @@ -780,7 +776,7 @@ func (b *StatefulBlock) Marshal( p.PackInt(len(b.Txs)) for _, tx := range b.Txs { - if err := tx.Marshal(p, actionRegistry, authRegistry); err != nil { + if err := tx.Marshal(p); err != nil { return nil, err } } diff --git a/chain/dependencies.go b/chain/dependencies.go index e38fcd0339..7375dc459f 100644 --- a/chain/dependencies.go +++ b/chain/dependencies.go @@ -117,6 +117,7 @@ type StateManager interface { } type Action interface { + GetTypeID() uint8 // identify uniquely the action MaxUnits(Rules) uint64 // max units that could be charged via execute ValidRange(Rules) (start int64, end int64) // -1 means no start/end @@ -152,6 +153,7 @@ type Action interface { } type Auth interface { + GetTypeID() uint8 // identify uniquely the auth MaxUnits(Rules) uint64 ValidRange(Rules) (start int64, end int64) // -1 means no start/end diff --git a/chain/transaction.go b/chain/transaction.go index db99ed0f1c..b7da5aa210 100644 --- a/chain/transaction.go +++ b/chain/transaction.go @@ -58,16 +58,11 @@ func NewTx(base *Base, wm *warp.Message, act Action) *Transaction { } } -func (t *Transaction) Digest( - actionRegistry *codec.TypeParser[Action, *warp.Message, bool], -) ([]byte, error) { +func (t *Transaction) Digest() ([]byte, error) { if len(t.digest) > 0 { return t.digest, nil } - actionByte, _, _, ok := actionRegistry.LookupType(t.Action) - if !ok { - return nil, fmt.Errorf("unknown action type %T", t.Action) - } + actionID := t.Action.GetTypeID() var warpBytes []byte if t.WarpMessage != nil { warpBytes = t.WarpMessage.Bytes() @@ -78,7 +73,7 @@ func (t *Transaction) Digest( p := codec.NewWriter(size, consts.NetworkSizeLimit) t.Base.Marshal(p) p.PackBytes(warpBytes) - p.PackByte(actionByte) + p.PackByte(actionID) t.Action.Marshal(p) return p.Bytes(), p.Err() } @@ -89,7 +84,7 @@ func (t *Transaction) Sign( authRegistry AuthRegistry, ) (*Transaction, error) { // Generate auth - msg, err := t.Digest(actionRegistry) + msg, err := t.Digest() if err != nil { return nil, err } @@ -103,7 +98,7 @@ func (t *Transaction) Sign( // bytes size := len(msg) + consts.ByteLen + t.Auth.Size() p := codec.NewWriter(size, consts.NetworkSizeLimit) - if err := t.Marshal(p, actionRegistry, authRegistry); err != nil { + if err := t.Marshal(p); err != nil { return nil, err } if err := p.Err(); err != nil { @@ -332,24 +327,14 @@ func (t *Transaction) Payer() string { return string(t.Auth.Payer()) } -func (t *Transaction) Marshal( - p *codec.Packer, - actionRegistry *codec.TypeParser[Action, *warp.Message, bool], - authRegistry *codec.TypeParser[Auth, *warp.Message, bool], -) error { +func (t *Transaction) Marshal(p *codec.Packer) error { if len(t.bytes) > 0 { p.PackFixedBytes(t.bytes) return p.Err() } - actionByte, _, _, ok := actionRegistry.LookupType(t.Action) - if !ok { - return fmt.Errorf("unknown action type %T", t.Action) - } - authByte, _, _, ok := authRegistry.LookupType(t.Auth) - if !ok { - return fmt.Errorf("unknown auth type %T", t.Auth) - } + actionID := t.Action.GetTypeID() + authID := t.Auth.GetTypeID() t.Base.Marshal(p) var warpBytes []byte if t.WarpMessage != nil { @@ -359,18 +344,14 @@ func (t *Transaction) Marshal( } } p.PackBytes(warpBytes) - p.PackByte(actionByte) + p.PackByte(actionID) t.Action.Marshal(p) - p.PackByte(authByte) + p.PackByte(authID) t.Auth.Marshal(p) return p.Err() } -func MarshalTxs( - txs []*Transaction, - actionRegistry ActionRegistry, - authRegistry AuthRegistry, -) ([]byte, error) { +func MarshalTxs(txs []*Transaction) ([]byte, error) { if len(txs) == 0 { return nil, ErrNoTxs } @@ -378,7 +359,7 @@ func MarshalTxs( p := codec.NewWriter(size, consts.NetworkSizeLimit) p.PackInt(len(txs)) for _, tx := range txs { - if err := tx.Marshal(p, actionRegistry, authRegistry); err != nil { + if err := tx.Marshal(p); err != nil { return nil, err } } diff --git a/codec/type_parser.go b/codec/type_parser.go index 5453188ffc..0614c7b151 100644 --- a/codec/type_parser.go +++ b/codec/type_parser.go @@ -4,8 +4,6 @@ package codec import ( - "fmt" - "github.com/ava-labs/hypersdk/consts" ) @@ -18,8 +16,6 @@ type decoder[T any, X any, Y any] struct { type TypeParser[T any, X any, Y any] struct { typeToIndex map[string]uint8 indexToDecoder map[uint8]*decoder[T, X, Y] - - index uint8 } // NewTypeParser returns an instance of a Typeparser with generic type [T]. @@ -33,31 +29,17 @@ func NewTypeParser[T any, X any, Y bool]() *TypeParser[T, X, Y] { // Register registers a new type into TypeParser [p]. Registers the type by using // the string representation of [o], and sets the decoder of that index to [f]. // Returns an error if [o] has already been registered or the TypeParser is full. -func (p *TypeParser[T, X, Y]) Register(o T, f func(*Packer, X) (T, error), y Y) error { - if p.index == consts.MaxUint8 { +func (p *TypeParser[T, X, Y]) Register(id uint8, f func(*Packer, X) (T, error), y Y) error { + if len(p.indexToDecoder) == int(consts.MaxUint8)+1 { return ErrTooManyItems } - k := fmt.Sprintf("%T", o) - if _, ok := p.typeToIndex[k]; ok { + if _, ok := p.indexToDecoder[id]; ok { return ErrDuplicateItem } - p.typeToIndex[k] = p.index - p.indexToDecoder[p.index] = &decoder[T, X, Y]{f, y} - p.index++ + p.indexToDecoder[id] = &decoder[T, X, Y]{f, y} return nil } -// LookupType returns the index, decoder function and the success of lookup of -// type [o] from Typeparser [p]. -func (p *TypeParser[T, X, Y]) LookupType(o T) (uint8, func(*Packer, X) (T, error), Y, bool) { - index, ok := p.typeToIndex[fmt.Sprintf("%T", o)] - if !ok { - return 0, nil, *new(Y), false - } - d := p.indexToDecoder[index] - return index, d.f, d.y, true -} - // LookupIndex returns the decoder function and success of lookup of [index] // from Typeparser [p]. func (p *TypeParser[T, X, Y]) LookupIndex(index uint8) (func(*Packer, X) (T, error), Y, bool) { diff --git a/codec/type_parser_test.go b/codec/type_parser_test.go index 083655b37e..763032b747 100644 --- a/codec/type_parser_test.go +++ b/codec/type_parser_test.go @@ -18,14 +18,20 @@ type Blah1 struct{} func (*Blah1) Bark() string { return "blah1" } +func (*Blah1) GetTypeID() uint8 { return 0 } + type Blah2 struct{} func (*Blah2) Bark() string { return "blah2" } +func (*Blah2) GetTypeID() uint8 { return 1 } + type Blah3 struct{} func (*Blah3) Bark() string { return "blah3" } +func (*Blah3) GetTypeID() uint8 { return 2 } + func TestTypeParser(t *testing.T) { tp := NewTypeParser[Blah, any, bool]() @@ -35,58 +41,38 @@ func TestTypeParser(t *testing.T) { require.Nil(f) require.False(ok) require.False(b) - index, f, b, ok := tp.LookupType(&Blah1{}) - require.Equal(uint8(0), index) - require.Nil(f) - require.False(ok) - require.False(b) }) t.Run("populated parser", func(t *testing.T) { require := require.New(t) + + blah1 := &Blah1{} + blah2 := &Blah2{} require.NoError( tp.Register( - &Blah1{}, + blah1.GetTypeID(), func(p *Packer, a any) (Blah, error) { return nil, errors.New("blah1") }, true, ), ) - require.Equal(uint8(1), tp.index) require.NoError( tp.Register( - &Blah2{}, + blah2.GetTypeID(), func(p *Packer, a any) (Blah, error) { return nil, errors.New("blah2") }, false, ), ) - require.Equal(uint8(2), tp.index) - f, b, ok := tp.LookupIndex(0) + f, b, ok := tp.LookupIndex(blah1.GetTypeID()) require.True(ok) require.True(b) res, err := f(nil, nil) require.Nil(res) require.ErrorContains(err, "blah1") - index, f, b, ok := tp.LookupType(&Blah1{}) - require.True(ok) - require.True(b) - require.Equal(uint8(0), index) - res, err = f(nil, nil) - require.Nil(res) - require.ErrorContains(err, "blah1") - - f, b, ok = tp.LookupIndex(1) - require.True(ok) - require.False(b) - res, err = f(nil, nil) - require.Nil(res) - require.ErrorContains(err, "blah2") - - index, f, b, ok = tp.LookupType(&Blah2{}) + f, b, ok = tp.LookupIndex(blah2.GetTypeID()) require.True(ok) require.False(b) - require.Equal(uint8(1), index) res, err = f(nil, nil) require.Nil(res) require.ErrorContains(err, "blah2") @@ -94,12 +80,17 @@ func TestTypeParser(t *testing.T) { t.Run("duplicate item", func(t *testing.T) { require := require.New(t) - require.ErrorIs(tp.Register(&Blah1{}, nil, true), ErrDuplicateItem) + require.ErrorIs(tp.Register((&Blah1{}).GetTypeID(), nil, true), ErrDuplicateItem) }) t.Run("too many items", func(t *testing.T) { require := require.New(t) - tp.index = consts.MaxUint8 // force max - require.ErrorIs(tp.Register(&Blah3{}, nil, true), ErrTooManyItems) + arrayLength := int(consts.MaxUint8) + 1 - len(tp.indexToDecoder) + for index := range make([]struct{}, arrayLength) { + // 0 and 1 are already existing -> we use index + 2 + require.NoError(tp.Register(uint8(index+2), nil, true)) + } + // all possible uint8 value should already be store, using any return ErrTooManyItems + require.ErrorIs(tp.Register(uint8(4), nil, true), ErrTooManyItems) }) } diff --git a/examples/morpheusvm/actions/common.go b/examples/morpheusvm/actions/common.go new file mode 100644 index 0000000000..00856d0715 --- /dev/null +++ b/examples/morpheusvm/actions/common.go @@ -0,0 +1,9 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package actions + +// Note: Registry will error during initialization if a duplicate ID is assigned. We explicitly assign IDs to avoid accidental remapping. +const ( + transferID uint8 = 0 +) diff --git a/examples/morpheusvm/actions/transfer.go b/examples/morpheusvm/actions/transfer.go index e275c440d5..a8740d6d1b 100644 --- a/examples/morpheusvm/actions/transfer.go +++ b/examples/morpheusvm/actions/transfer.go @@ -27,6 +27,10 @@ type Transfer struct { Value uint64 `json:"value"` } +func (*Transfer) GetTypeID() uint8 { + return transferID +} + func (t *Transfer) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { return [][]byte{ storage.PrefixBalanceKey(auth.GetActor(rauth)), diff --git a/examples/morpheusvm/auth/common.go b/examples/morpheusvm/auth/common.go new file mode 100644 index 0000000000..cf838e454d --- /dev/null +++ b/examples/morpheusvm/auth/common.go @@ -0,0 +1,9 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package auth + +// Note: Registry will error during initialization if a duplicate ID is assigned. We explicitly assign IDs to avoid accidental remapping. +const ( + ed25519ID uint8 = 0 +) diff --git a/examples/morpheusvm/auth/ed25519.go b/examples/morpheusvm/auth/ed25519.go index 11d23041a4..1b9aa99f3a 100644 --- a/examples/morpheusvm/auth/ed25519.go +++ b/examples/morpheusvm/auth/ed25519.go @@ -20,6 +20,10 @@ type ED25519 struct { Signature crypto.Signature `json:"signature"` } +func (*ED25519) GetTypeID() uint8 { + return ed25519ID +} + func (*ED25519) MaxUnits( chain.Rules, ) uint64 { diff --git a/examples/morpheusvm/registry/registry.go b/examples/morpheusvm/registry/registry.go index 3bcc76eacf..1b91d68f68 100644 --- a/examples/morpheusvm/registry/registry.go +++ b/examples/morpheusvm/registry/registry.go @@ -22,10 +22,10 @@ func init() { errs := &wrappers.Errs{} errs.Add( // When registering new actions, ALWAYS make sure to append at the end. - consts.ActionRegistry.Register(&actions.Transfer{}, actions.UnmarshalTransfer, false), + consts.ActionRegistry.Register((&actions.Transfer{}).GetTypeID(), actions.UnmarshalTransfer, false), // When registering new auth, ALWAYS make sure to append at the end. - consts.AuthRegistry.Register(&auth.ED25519{}, auth.UnmarshalED25519, false), + consts.AuthRegistry.Register((&auth.ED25519{}).GetTypeID(), auth.UnmarshalED25519, false), ) if errs.Errored() { panic(errs.Err) diff --git a/examples/morpheusvm/tests/integration/integration_test.go b/examples/morpheusvm/tests/integration/integration_test.go index 8ca9d26ff2..5946fd0a07 100644 --- a/examples/morpheusvm/tests/integration/integration_test.go +++ b/examples/morpheusvm/tests/integration/integration_test.go @@ -357,7 +357,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { }) ginkgo.By("skip invalid time", func() { - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -372,13 +371,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // 0 timestamp) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), diff --git a/examples/tokenvm/actions/burn_asset.go b/examples/tokenvm/actions/burn_asset.go index e6d7f58f3d..2d52aa3512 100644 --- a/examples/tokenvm/actions/burn_asset.go +++ b/examples/tokenvm/actions/burn_asset.go @@ -28,6 +28,10 @@ type BurnAsset struct { Value uint64 `json:"value"` } +func (*BurnAsset) GetTypeID() uint8 { + return burnAssetID +} + func (b *BurnAsset) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { actor := auth.GetActor(rauth) return [][]byte{ diff --git a/examples/tokenvm/actions/close_order.go b/examples/tokenvm/actions/close_order.go index 79563969d2..676df8f0ff 100644 --- a/examples/tokenvm/actions/close_order.go +++ b/examples/tokenvm/actions/close_order.go @@ -27,6 +27,10 @@ type CloseOrder struct { Out ids.ID `json:"out"` } +func (*CloseOrder) GetTypeID() uint8 { + return closeOrderID +} + func (c *CloseOrder) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { actor := auth.GetActor(rauth) return [][]byte{ diff --git a/examples/tokenvm/actions/common.go b/examples/tokenvm/actions/common.go new file mode 100644 index 0000000000..8945fa242f --- /dev/null +++ b/examples/tokenvm/actions/common.go @@ -0,0 +1,18 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package actions + +// Note: Registry will error during initialization if a duplicate ID is assigned. We explicitly assign IDs to avoid accidental remapping. +const ( + burnAssetID uint8 = 0 + closeOrderID uint8 = 1 + createAssetID uint8 = 2 + exportAssetID uint8 = 3 + importAssetID uint8 = 4 + createOrderID uint8 = 5 + fillOrderID uint8 = 6 + mintAssetID uint8 = 7 + modifyAssetID uint8 = 8 + transferID uint8 = 9 +) diff --git a/examples/tokenvm/actions/create_asset.go b/examples/tokenvm/actions/create_asset.go index 2ee96ef1ec..35b937b3b2 100644 --- a/examples/tokenvm/actions/create_asset.go +++ b/examples/tokenvm/actions/create_asset.go @@ -27,6 +27,10 @@ func (*CreateAsset) StateKeys(_ chain.Auth, txID ids.ID) [][]byte { return [][]byte{storage.PrefixAssetKey(txID)} } +func (*CreateAsset) GetTypeID() uint8 { + return createAssetID +} + func (c *CreateAsset) Execute( ctx context.Context, r chain.Rules, diff --git a/examples/tokenvm/actions/create_order.go b/examples/tokenvm/actions/create_order.go index 8f6c491179..cf2ee05f19 100644 --- a/examples/tokenvm/actions/create_order.go +++ b/examples/tokenvm/actions/create_order.go @@ -47,6 +47,10 @@ type CreateOrder struct { // refunded any unused assets. } +func (*CreateOrder) GetTypeID() uint8 { + return createOrderID +} + func (c *CreateOrder) StateKeys(rauth chain.Auth, txID ids.ID) [][]byte { actor := auth.GetActor(rauth) return [][]byte{ diff --git a/examples/tokenvm/actions/export_asset.go b/examples/tokenvm/actions/export_asset.go index a88f59f3d3..dbda2e403f 100644 --- a/examples/tokenvm/actions/export_asset.go +++ b/examples/tokenvm/actions/export_asset.go @@ -40,6 +40,10 @@ type ExportAsset struct { Destination ids.ID `json:"destination"` } +func (*ExportAsset) GetTypeID() uint8 { + return exportAssetID +} + func (e *ExportAsset) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { var ( keys [][]byte diff --git a/examples/tokenvm/actions/fill_order.go b/examples/tokenvm/actions/fill_order.go index 6c7f15c49b..8e69e6fba6 100644 --- a/examples/tokenvm/actions/fill_order.go +++ b/examples/tokenvm/actions/fill_order.go @@ -46,6 +46,10 @@ type FillOrder struct { Value uint64 `json:"value"` } +func (*FillOrder) GetTypeID() uint8 { + return fillOrderID +} + func (f *FillOrder) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { actor := auth.GetActor(rauth) return [][]byte{ diff --git a/examples/tokenvm/actions/import_asset.go b/examples/tokenvm/actions/import_asset.go index ed83e98e69..adb65465b3 100644 --- a/examples/tokenvm/actions/import_asset.go +++ b/examples/tokenvm/actions/import_asset.go @@ -34,6 +34,10 @@ type ImportAsset struct { warpMessage *warp.Message } +func (*ImportAsset) GetTypeID() uint8 { + return importAssetID +} + func (i *ImportAsset) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { var ( keys [][]byte diff --git a/examples/tokenvm/actions/mint_asset.go b/examples/tokenvm/actions/mint_asset.go index 20bb44743e..e7cb70e9fe 100644 --- a/examples/tokenvm/actions/mint_asset.go +++ b/examples/tokenvm/actions/mint_asset.go @@ -32,6 +32,10 @@ type MintAsset struct { Value uint64 `json:"value"` } +func (*MintAsset) GetTypeID() uint8 { + return mintAssetID +} + func (m *MintAsset) StateKeys(chain.Auth, ids.ID) [][]byte { return [][]byte{ storage.PrefixAssetKey(m.Asset), diff --git a/examples/tokenvm/actions/modify_asset.go b/examples/tokenvm/actions/modify_asset.go index 1315f477ec..06f529c0d9 100644 --- a/examples/tokenvm/actions/modify_asset.go +++ b/examples/tokenvm/actions/modify_asset.go @@ -35,6 +35,10 @@ type ModifyAsset struct { Metadata []byte `json:"metadata"` } +func (*ModifyAsset) GetTypeID() uint8 { + return modifyAssetID +} + func (m *ModifyAsset) StateKeys(chain.Auth, ids.ID) [][]byte { return [][]byte{storage.PrefixAssetKey(m.Asset)} } diff --git a/examples/tokenvm/actions/transfer.go b/examples/tokenvm/actions/transfer.go index 922e5df67b..e587e35c1c 100644 --- a/examples/tokenvm/actions/transfer.go +++ b/examples/tokenvm/actions/transfer.go @@ -30,6 +30,10 @@ type Transfer struct { Value uint64 `json:"value"` } +func (*Transfer) GetTypeID() uint8 { + return transferID +} + func (t *Transfer) StateKeys(rauth chain.Auth, _ ids.ID) [][]byte { return [][]byte{ storage.PrefixBalanceKey(auth.GetActor(rauth), t.Asset), diff --git a/examples/tokenvm/auth/common.go b/examples/tokenvm/auth/common.go new file mode 100644 index 0000000000..cf838e454d --- /dev/null +++ b/examples/tokenvm/auth/common.go @@ -0,0 +1,9 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package auth + +// Note: Registry will error during initialization if a duplicate ID is assigned. We explicitly assign IDs to avoid accidental remapping. +const ( + ed25519ID uint8 = 0 +) diff --git a/examples/tokenvm/auth/ed25519.go b/examples/tokenvm/auth/ed25519.go index f5d4e30713..4a4dc44a12 100644 --- a/examples/tokenvm/auth/ed25519.go +++ b/examples/tokenvm/auth/ed25519.go @@ -21,6 +21,10 @@ type ED25519 struct { Signature crypto.Signature `json:"signature"` } +func (*ED25519) GetTypeID() uint8 { + return ed25519ID +} + func (*ED25519) MaxUnits( chain.Rules, ) uint64 { diff --git a/examples/tokenvm/registry/registry.go b/examples/tokenvm/registry/registry.go index 2be410f3b1..60bfa62c32 100644 --- a/examples/tokenvm/registry/registry.go +++ b/examples/tokenvm/registry/registry.go @@ -22,22 +22,22 @@ func init() { errs := &wrappers.Errs{} errs.Add( // When registering new actions, ALWAYS make sure to append at the end. - consts.ActionRegistry.Register(&actions.Transfer{}, actions.UnmarshalTransfer, false), + consts.ActionRegistry.Register((&actions.Transfer{}).GetTypeID(), actions.UnmarshalTransfer, false), - consts.ActionRegistry.Register(&actions.CreateAsset{}, actions.UnmarshalCreateAsset, false), - consts.ActionRegistry.Register(&actions.MintAsset{}, actions.UnmarshalMintAsset, false), - consts.ActionRegistry.Register(&actions.BurnAsset{}, actions.UnmarshalBurnAsset, false), - consts.ActionRegistry.Register(&actions.ModifyAsset{}, actions.UnmarshalModifyAsset, false), + consts.ActionRegistry.Register((&actions.CreateAsset{}).GetTypeID(), actions.UnmarshalCreateAsset, false), + consts.ActionRegistry.Register((&actions.MintAsset{}).GetTypeID(), actions.UnmarshalMintAsset, false), + consts.ActionRegistry.Register((&actions.BurnAsset{}).GetTypeID(), actions.UnmarshalBurnAsset, false), + consts.ActionRegistry.Register((&actions.ModifyAsset{}).GetTypeID(), actions.UnmarshalModifyAsset, false), - consts.ActionRegistry.Register(&actions.CreateOrder{}, actions.UnmarshalCreateOrder, false), - consts.ActionRegistry.Register(&actions.FillOrder{}, actions.UnmarshalFillOrder, false), - consts.ActionRegistry.Register(&actions.CloseOrder{}, actions.UnmarshalCloseOrder, false), + consts.ActionRegistry.Register((&actions.CreateOrder{}).GetTypeID(), actions.UnmarshalCreateOrder, false), + consts.ActionRegistry.Register((&actions.FillOrder{}).GetTypeID(), actions.UnmarshalFillOrder, false), + consts.ActionRegistry.Register((&actions.CloseOrder{}).GetTypeID(), actions.UnmarshalCloseOrder, false), - consts.ActionRegistry.Register(&actions.ImportAsset{}, actions.UnmarshalImportAsset, true), - consts.ActionRegistry.Register(&actions.ExportAsset{}, actions.UnmarshalExportAsset, false), + consts.ActionRegistry.Register((&actions.ImportAsset{}).GetTypeID(), actions.UnmarshalImportAsset, true), + consts.ActionRegistry.Register((&actions.ExportAsset{}).GetTypeID(), actions.UnmarshalExportAsset, false), // When registering new auth, ALWAYS make sure to append at the end. - consts.AuthRegistry.Register(&auth.ED25519{}, auth.UnmarshalED25519, false), + consts.AuthRegistry.Register((&auth.ED25519{}).GetTypeID(), auth.UnmarshalED25519, false), ) if errs.Errored() { panic(errs.Err) diff --git a/examples/tokenvm/tests/integration/integration_test.go b/examples/tokenvm/tests/integration/integration_test.go index 4a11a1e943..fe5b3f2371 100644 --- a/examples/tokenvm/tests/integration/integration_test.go +++ b/examples/tokenvm/tests/integration/integration_test.go @@ -359,7 +359,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { }) ginkgo.By("skip invalid time", func() { - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -374,13 +373,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // 0 timestamp) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -789,7 +788,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { }) ginkgo.It("create asset with too long of metadata", func() { - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -803,13 +801,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // too large) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1009,7 +1007,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ginkgo.It("rejects empty mint", func() { other, err := crypto.GeneratePrivateKey() gomega.Ω(err).Should(gomega.BeNil()) - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1024,13 +1021,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // bad codec) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1155,7 +1152,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ginkgo.It("rejects mint of native token", func() { other, err := crypto.GeneratePrivateKey() gomega.Ω(err).Should(gomega.BeNil()) - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1170,13 +1166,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // bad codec) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1679,7 +1675,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { }) ginkgo.It("import warp message with nil when expected", func() { - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1691,13 +1686,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // empty warp) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1709,7 +1704,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ginkgo.It("import warp message empty", func() { wm, err := warp.NewMessage(&warp.UnsignedMessage{}, &warp.BitSetSignature{}) gomega.Ω(err).Should(gomega.BeNil()) - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1721,13 +1715,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // empty warp) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1741,7 +1735,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { gomega.Ω(err).Should(gomega.BeNil()) wm, err := warp.NewMessage(uwm, &warp.BitSetSignature{}) gomega.Ω(err).Should(gomega.BeNil()) - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1753,13 +1746,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // invalid object) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), @@ -1776,7 +1769,6 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { gomega.Ω(err).Should(gomega.BeNil()) wm, err := warp.NewMessage(uwm, &warp.BitSetSignature{}) gomega.Ω(err).Should(gomega.BeNil()) - actionRegistry, authRegistry := instances[0].vm.Registry() tx := chain.NewTx( &chain.Base{ ChainID: instances[0].chainID, @@ -1788,13 +1780,13 @@ var _ = ginkgo.Describe("[Tx Processing]", func() { ) // Must do manual construction to avoid `tx.Sign` error (would fail with // invalid object) - msg, err := tx.Digest(actionRegistry) + msg, err := tx.Digest() gomega.Ω(err).To(gomega.BeNil()) auth, err := factory.Sign(msg, tx.Action) gomega.Ω(err).To(gomega.BeNil()) tx.Auth = auth p := codec.NewWriter(0, consts.MaxInt) // test codec growth - gomega.Ω(tx.Marshal(p, actionRegistry, authRegistry)).To(gomega.BeNil()) + gomega.Ω(tx.Marshal(p)).To(gomega.BeNil()) gomega.Ω(p.Err()).To(gomega.BeNil()) _, err = instances[0].cli.SubmitTx( context.Background(), diff --git a/gossiper/manual.go b/gossiper/manual.go index 304a24845b..0581fadf84 100644 --- a/gossiper/manual.go +++ b/gossiper/manual.go @@ -72,8 +72,7 @@ func (g *Manual) ForceGossip(ctx context.Context) error { if len(txs) == 0 { return nil } - actionRegistry, authRegistry := g.vm.Registry() - b, err := chain.MarshalTxs(txs, actionRegistry, authRegistry) + b, err := chain.MarshalTxs(txs) if err != nil { return err } diff --git a/gossiper/proposer.go b/gossiper/proposer.go index a1c5f7cd02..9c01d392e2 100644 --- a/gossiper/proposer.go +++ b/gossiper/proposer.go @@ -88,8 +88,7 @@ func (g *Proposer) sendTxs(ctx context.Context, txs []*chain.Transaction) error zap.Error(err), ) - actionRegistry, authRegistry := g.vm.Registry() - b, err := chain.MarshalTxs(txs, actionRegistry, authRegistry) + b, err := chain.MarshalTxs(txs) if err != nil { return err } @@ -131,8 +130,7 @@ func (g *Proposer) sendTxs(ctx context.Context, txs []*chain.Transaction) error } // TODO: cache marshalization - actionRegistry, authRegistry := g.vm.Registry() - b, err := chain.MarshalTxs(toGossip, actionRegistry, authRegistry) + b, err := chain.MarshalTxs(toGossip) if err != nil { return err }