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 }