github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/state/genesis.go (about)

     1  package state
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  
     8  	"github.com/0xPolygon/supernets2-node/encoding"
     9  	"github.com/0xPolygon/supernets2-node/hex"
    10  	"github.com/0xPolygon/supernets2-node/log"
    11  	"github.com/0xPolygon/supernets2-node/merkletree"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/ethereum/go-ethereum/trie"
    15  	"github.com/jackc/pgx/v4"
    16  )
    17  
    18  // Genesis contains the information to populate state on creation
    19  type Genesis struct {
    20  	// GenesisBlockNum is the block number where the polygonZKEVM smc was deployed
    21  	GenesisBlockNum uint64
    22  	Root            common.Hash
    23  	GenesisActions  []*GenesisAction
    24  }
    25  
    26  // GenesisAction represents one of the values set on the SMT during genesis.
    27  type GenesisAction struct {
    28  	Address         string `json:"address"`
    29  	Type            int    `json:"type"`
    30  	StoragePosition string `json:"storagePosition"`
    31  	Bytecode        string `json:"bytecode"`
    32  	Key             string `json:"key"`
    33  	Value           string `json:"value"`
    34  	Root            string `json:"root"`
    35  }
    36  
    37  // SetGenesis populates state with genesis information
    38  func (s *State) SetGenesis(ctx context.Context, block Block, genesis Genesis, dbTx pgx.Tx) ([]byte, error) {
    39  	var (
    40  		root    common.Hash
    41  		newRoot []byte
    42  		err     error
    43  	)
    44  	if dbTx == nil {
    45  		return newRoot, ErrDBTxNil
    46  	}
    47  	if s.tree == nil {
    48  		return newRoot, ErrStateTreeNil
    49  	}
    50  
    51  	for _, action := range genesis.GenesisActions {
    52  		address := common.HexToAddress(action.Address)
    53  		switch action.Type {
    54  		case int(merkletree.LeafTypeBalance):
    55  			balance, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
    56  			if err != nil {
    57  				return newRoot, err
    58  			}
    59  			newRoot, _, err = s.tree.SetBalance(ctx, address, balance, newRoot)
    60  			if err != nil {
    61  				return newRoot, err
    62  			}
    63  		case int(merkletree.LeafTypeNonce):
    64  			nonce, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
    65  			if err != nil {
    66  				return newRoot, err
    67  			}
    68  			newRoot, _, err = s.tree.SetNonce(ctx, address, nonce, newRoot)
    69  			if err != nil {
    70  				return newRoot, err
    71  			}
    72  		case int(merkletree.LeafTypeCode):
    73  			code, err := hex.DecodeHex(action.Bytecode)
    74  			if err != nil {
    75  				return newRoot, fmt.Errorf("could not decode SC bytecode for address %q: %v", address, err)
    76  			}
    77  			newRoot, _, err = s.tree.SetCode(ctx, address, code, newRoot)
    78  			if err != nil {
    79  				return newRoot, err
    80  			}
    81  		case int(merkletree.LeafTypeStorage):
    82  			// Parse position and value
    83  			positionBI, err := encoding.DecodeBigIntHexOrDecimal(action.StoragePosition)
    84  			if err != nil {
    85  				return newRoot, err
    86  			}
    87  			valueBI, err := encoding.DecodeBigIntHexOrDecimal(action.Value)
    88  			if err != nil {
    89  				return newRoot, err
    90  			}
    91  			// Store
    92  			newRoot, _, err = s.tree.SetStorageAt(ctx, address, positionBI, valueBI, newRoot)
    93  			if err != nil {
    94  				return newRoot, err
    95  			}
    96  		case int(merkletree.LeafTypeSCLength):
    97  			log.Debug("Skipped genesis action of type merkletree.LeafTypeSCLength, these actions will be handled as part of merkletree.LeafTypeCode actions")
    98  		default:
    99  			return newRoot, fmt.Errorf("unknown genesis action type %q", action.Type)
   100  		}
   101  	}
   102  
   103  	root.SetBytes(newRoot)
   104  
   105  	// flush state db
   106  	err = s.tree.Flush(ctx)
   107  	if err != nil {
   108  		log.Errorf("error flushing state tree after genesis: %v", err)
   109  		return newRoot, err
   110  	}
   111  
   112  	// store L1 block related to genesis batch
   113  	err = s.AddBlock(ctx, &block, dbTx)
   114  	if err != nil {
   115  		return newRoot, err
   116  	}
   117  
   118  	// store genesis batch
   119  	batch := Batch{
   120  		BatchNumber:    0,
   121  		Coinbase:       ZeroAddress,
   122  		BatchL2Data:    nil,
   123  		StateRoot:      root,
   124  		LocalExitRoot:  ZeroHash,
   125  		Timestamp:      block.ReceivedAt,
   126  		Transactions:   []types.Transaction{},
   127  		GlobalExitRoot: ZeroHash,
   128  		ForcedBatchNum: nil,
   129  	}
   130  
   131  	err = s.storeGenesisBatch(ctx, batch, dbTx)
   132  	if err != nil {
   133  		return newRoot, err
   134  	}
   135  
   136  	// mark the genesis batch as virtualized
   137  	virtualBatch := &VirtualBatch{
   138  		BatchNumber: batch.BatchNumber,
   139  		TxHash:      ZeroHash,
   140  		Coinbase:    ZeroAddress,
   141  		BlockNumber: block.BlockNumber,
   142  	}
   143  	err = s.AddVirtualBatch(ctx, virtualBatch, dbTx)
   144  	if err != nil {
   145  		return newRoot, err
   146  	}
   147  
   148  	// mark the genesis batch as verified/consolidated
   149  	verifiedBatch := &VerifiedBatch{
   150  		BatchNumber: batch.BatchNumber,
   151  		TxHash:      ZeroHash,
   152  		Aggregator:  ZeroAddress,
   153  		BlockNumber: block.BlockNumber,
   154  	}
   155  	err = s.AddVerifiedBatch(ctx, verifiedBatch, dbTx)
   156  	if err != nil {
   157  		return newRoot, err
   158  	}
   159  
   160  	// store L2 genesis block
   161  	header := &types.Header{
   162  		Number:     big.NewInt(0),
   163  		ParentHash: ZeroHash,
   164  		Coinbase:   ZeroAddress,
   165  		Root:       root,
   166  		Time:       uint64(block.ReceivedAt.Unix()),
   167  	}
   168  	rootHex := root.Hex()
   169  	log.Info("Genesis root ", rootHex)
   170  
   171  	receipts := []*types.Receipt{}
   172  	l2Block := types.NewBlock(header, []*types.Transaction{}, []*types.Header{}, receipts, &trie.StackTrie{})
   173  	l2Block.ReceivedAt = block.ReceivedAt
   174  
   175  	return newRoot, s.AddL2Block(ctx, batch.BatchNumber, l2Block, receipts, dbTx)
   176  }