github.com/MetalBlockchain/metalgo@v1.11.9/vms/proposervm/block/build.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package block
     5  
     6  import (
     7  	"crypto"
     8  	"crypto/rand"
     9  	"time"
    10  
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/staking"
    13  	"github.com/MetalBlockchain/metalgo/utils/hashing"
    14  	"github.com/MetalBlockchain/metalgo/utils/wrappers"
    15  )
    16  
    17  func BuildUnsigned(
    18  	parentID ids.ID,
    19  	timestamp time.Time,
    20  	pChainHeight uint64,
    21  	blockBytes []byte,
    22  ) (SignedBlock, error) {
    23  	var block SignedBlock = &statelessBlock{
    24  		StatelessBlock: statelessUnsignedBlock{
    25  			ParentID:     parentID,
    26  			Timestamp:    timestamp.Unix(),
    27  			PChainHeight: pChainHeight,
    28  			Certificate:  nil,
    29  			Block:        blockBytes,
    30  		},
    31  		timestamp: timestamp,
    32  	}
    33  
    34  	bytes, err := Codec.Marshal(CodecVersion, &block)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return block, block.initialize(bytes)
    40  }
    41  
    42  func Build(
    43  	parentID ids.ID,
    44  	timestamp time.Time,
    45  	pChainHeight uint64,
    46  	cert *staking.Certificate,
    47  	blockBytes []byte,
    48  	chainID ids.ID,
    49  	key crypto.Signer,
    50  ) (SignedBlock, error) {
    51  	block := &statelessBlock{
    52  		StatelessBlock: statelessUnsignedBlock{
    53  			ParentID:     parentID,
    54  			Timestamp:    timestamp.Unix(),
    55  			PChainHeight: pChainHeight,
    56  			Certificate:  cert.Raw,
    57  			Block:        blockBytes,
    58  		},
    59  		timestamp: timestamp,
    60  		cert:      cert,
    61  		proposer:  ids.NodeIDFromCert(cert),
    62  	}
    63  	var blockIntf SignedBlock = block
    64  
    65  	unsignedBytesWithEmptySignature, err := Codec.Marshal(CodecVersion, &blockIntf)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	// The serialized form of the block is the unsignedBytes followed by the
    71  	// signature, which is prefixed by a uint32. Because we are marshalling the
    72  	// block with an empty signature, we only need to strip off the length
    73  	// prefix to get the unsigned bytes.
    74  	lenUnsignedBytes := len(unsignedBytesWithEmptySignature) - wrappers.IntLen
    75  	unsignedBytes := unsignedBytesWithEmptySignature[:lenUnsignedBytes]
    76  	block.id = hashing.ComputeHash256Array(unsignedBytes)
    77  
    78  	header, err := BuildHeader(chainID, parentID, block.id)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	headerHash := hashing.ComputeHash256(header.Bytes())
    84  	block.Signature, err = key.Sign(rand.Reader, headerHash, crypto.SHA256)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	block.bytes, err = Codec.Marshal(CodecVersion, &blockIntf)
    90  	return block, err
    91  }
    92  
    93  func BuildHeader(
    94  	chainID ids.ID,
    95  	parentID ids.ID,
    96  	bodyID ids.ID,
    97  ) (Header, error) {
    98  	header := statelessHeader{
    99  		Chain:  chainID,
   100  		Parent: parentID,
   101  		Body:   bodyID,
   102  	}
   103  
   104  	bytes, err := Codec.Marshal(CodecVersion, &header)
   105  	header.bytes = bytes
   106  	return &header, err
   107  }
   108  
   109  // BuildOption the option block
   110  // [parentID] is the ID of this option's wrapper parent block
   111  // [innerBytes] is the byte representation of a child option block
   112  func BuildOption(
   113  	parentID ids.ID,
   114  	innerBytes []byte,
   115  ) (Block, error) {
   116  	var block Block = &option{
   117  		PrntID:     parentID,
   118  		InnerBytes: innerBytes,
   119  	}
   120  
   121  	bytes, err := Codec.Marshal(CodecVersion, &block)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	return block, block.initialize(bytes)
   127  }