github.com/MetalBlockchain/metalgo@v1.11.9/vms/example/xsvm/chain/chain.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package chain
     5  
     6  import (
     7  	"github.com/MetalBlockchain/metalgo/database"
     8  	"github.com/MetalBlockchain/metalgo/ids"
     9  	"github.com/MetalBlockchain/metalgo/snow"
    10  	"github.com/MetalBlockchain/metalgo/snow/choices"
    11  	"github.com/MetalBlockchain/metalgo/vms/example/xsvm/state"
    12  
    13  	xsblock "github.com/MetalBlockchain/metalgo/vms/example/xsvm/block"
    14  )
    15  
    16  var _ Chain = (*chain)(nil)
    17  
    18  type Chain interface {
    19  	LastAccepted() ids.ID
    20  	SetChainState(state snow.State)
    21  	GetBlock(blkID ids.ID) (Block, error)
    22  
    23  	// Creates a fully verifiable and executable block, which can be processed
    24  	// by the consensus engine, from a stateless block.
    25  	NewBlock(blk *xsblock.Stateless) (Block, error)
    26  }
    27  
    28  type chain struct {
    29  	chainContext  *snow.Context
    30  	acceptedState database.Database
    31  
    32  	// chain state as driven by the consensus engine
    33  	chainState snow.State
    34  
    35  	lastAccepted   ids.ID
    36  	verifiedBlocks map[ids.ID]*block
    37  }
    38  
    39  func New(ctx *snow.Context, db database.Database) (Chain, error) {
    40  	// Load the last accepted block data. For a newly created VM, this will be
    41  	// the genesis. It is assumed the genesis was processed and stored
    42  	// previously during VM initialization.
    43  	lastAcceptedID, err := state.GetLastAccepted(db)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	c := &chain{
    49  		chainContext:  ctx,
    50  		acceptedState: db,
    51  		lastAccepted:  lastAcceptedID,
    52  	}
    53  
    54  	lastAccepted, err := c.getBlock(lastAcceptedID)
    55  	c.verifiedBlocks = map[ids.ID]*block{
    56  		lastAcceptedID: lastAccepted,
    57  	}
    58  	return c, err
    59  }
    60  
    61  func (c *chain) LastAccepted() ids.ID {
    62  	return c.lastAccepted
    63  }
    64  
    65  func (c *chain) SetChainState(state snow.State) {
    66  	c.chainState = state
    67  }
    68  
    69  func (c *chain) GetBlock(blkID ids.ID) (Block, error) {
    70  	return c.getBlock(blkID)
    71  }
    72  
    73  func (c *chain) NewBlock(blk *xsblock.Stateless) (Block, error) {
    74  	blkID, err := blk.ID()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	if blk, exists := c.verifiedBlocks[blkID]; exists {
    80  		return blk, nil
    81  	}
    82  
    83  	blkBytes, err := xsblock.Codec.Marshal(xsblock.CodecVersion, blk)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	return &block{
    89  		Stateless: blk,
    90  		chain:     c,
    91  		id:        blkID,
    92  		bytes:     blkBytes,
    93  	}, nil
    94  }
    95  
    96  func (c *chain) getBlock(blkID ids.ID) (*block, error) {
    97  	if blk, exists := c.verifiedBlocks[blkID]; exists {
    98  		return blk, nil
    99  	}
   100  
   101  	blkBytes, err := state.GetBlock(c.acceptedState, blkID)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	stateless, err := xsblock.Parse(blkBytes)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	return &block{
   111  		Stateless: stateless,
   112  		chain:     c,
   113  		id:        blkID,
   114  		status:    choices.Accepted,
   115  		bytes:     blkBytes,
   116  	}, nil
   117  }