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  }