github.com/ava-labs/avalanchego@v1.11.11/vms/avm/txs/parser.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package txs 5 6 import ( 7 "errors" 8 "fmt" 9 "math" 10 "reflect" 11 12 "github.com/ava-labs/avalanchego/codec" 13 "github.com/ava-labs/avalanchego/codec/linearcodec" 14 "github.com/ava-labs/avalanchego/utils/logging" 15 "github.com/ava-labs/avalanchego/utils/timer/mockable" 16 "github.com/ava-labs/avalanchego/vms/avm/fxs" 17 ) 18 19 // CodecVersion is the current default codec version 20 const CodecVersion = 0 21 22 var _ Parser = (*parser)(nil) 23 24 type Parser interface { 25 Codec() codec.Manager 26 GenesisCodec() codec.Manager 27 28 CodecRegistry() codec.Registry 29 GenesisCodecRegistry() codec.Registry 30 31 ParseTx(bytes []byte) (*Tx, error) 32 ParseGenesisTx(bytes []byte) (*Tx, error) 33 } 34 35 type parser struct { 36 cm codec.Manager 37 gcm codec.Manager 38 c linearcodec.Codec 39 gc linearcodec.Codec 40 } 41 42 func NewParser(fxs []fxs.Fx) (Parser, error) { 43 return NewCustomParser( 44 make(map[reflect.Type]int), 45 &mockable.Clock{}, 46 logging.NoLog{}, 47 fxs, 48 ) 49 } 50 51 func NewCustomParser( 52 typeToFxIndex map[reflect.Type]int, 53 clock *mockable.Clock, 54 log logging.Logger, 55 fxs []fxs.Fx, 56 ) (Parser, error) { 57 gc := linearcodec.NewDefault() 58 c := linearcodec.NewDefault() 59 60 gcm := codec.NewManager(math.MaxInt32) 61 cm := codec.NewDefaultManager() 62 63 err := errors.Join( 64 c.RegisterType(&BaseTx{}), 65 c.RegisterType(&CreateAssetTx{}), 66 c.RegisterType(&OperationTx{}), 67 c.RegisterType(&ImportTx{}), 68 c.RegisterType(&ExportTx{}), 69 cm.RegisterCodec(CodecVersion, c), 70 71 gc.RegisterType(&BaseTx{}), 72 gc.RegisterType(&CreateAssetTx{}), 73 gc.RegisterType(&OperationTx{}), 74 gc.RegisterType(&ImportTx{}), 75 gc.RegisterType(&ExportTx{}), 76 gcm.RegisterCodec(CodecVersion, gc), 77 ) 78 if err != nil { 79 return nil, err 80 } 81 82 vm := &fxVM{ 83 typeToFxIndex: typeToFxIndex, 84 clock: clock, 85 log: log, 86 } 87 for i, fx := range fxs { 88 vm.codecRegistry = &codecRegistry{ 89 codecs: []codec.Registry{gc, c}, 90 index: i, 91 typeToIndex: vm.typeToFxIndex, 92 } 93 if err := fx.Initialize(vm); err != nil { 94 return nil, err 95 } 96 } 97 return &parser{ 98 cm: cm, 99 gcm: gcm, 100 c: c, 101 gc: gc, 102 }, nil 103 } 104 105 func (p *parser) Codec() codec.Manager { 106 return p.cm 107 } 108 109 func (p *parser) GenesisCodec() codec.Manager { 110 return p.gcm 111 } 112 113 func (p *parser) CodecRegistry() codec.Registry { 114 return p.c 115 } 116 117 func (p *parser) GenesisCodecRegistry() codec.Registry { 118 return p.gc 119 } 120 121 func (p *parser) ParseTx(bytes []byte) (*Tx, error) { 122 return parse(p.cm, bytes) 123 } 124 125 func (p *parser) ParseGenesisTx(bytes []byte) (*Tx, error) { 126 return parse(p.gcm, bytes) 127 } 128 129 func parse(cm codec.Manager, signedBytes []byte) (*Tx, error) { 130 tx := &Tx{} 131 parsedVersion, err := cm.Unmarshal(signedBytes, tx) 132 if err != nil { 133 return nil, err 134 } 135 if parsedVersion != CodecVersion { 136 return nil, fmt.Errorf("expected codec version %d but got %d", CodecVersion, parsedVersion) 137 } 138 139 unsignedBytesLen, err := cm.Size(CodecVersion, &tx.Unsigned) 140 if err != nil { 141 return nil, fmt.Errorf("couldn't calculate UnsignedTx marshal length: %w", err) 142 } 143 144 unsignedBytes := signedBytes[:unsignedBytesLen] 145 tx.SetBytes(unsignedBytes, signedBytes) 146 return tx, nil 147 }