forked from TrueCloudLab/neoneo-go
a6610ba082
This adds the following verifications: * merkleroot check * index check * timestamp check * witnesses verification VerifyWitnesses is also renamed to verifyTxWitnesses here to not confuse it with verifyBlockWitnesse and to hide it from external access (no users at the moment).
151 lines
4.1 KiB
Go
151 lines
4.1 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
|
"github.com/CityOfZion/neo-go/pkg/io"
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
)
|
|
|
|
// BlockBase holds the base info of a block
|
|
type BlockBase struct {
|
|
// Version of the block.
|
|
Version uint32 `json:"version"`
|
|
|
|
// hash of the previous block.
|
|
PrevHash util.Uint256 `json:"previousblockhash"`
|
|
|
|
// Root hash of a transaction list.
|
|
MerkleRoot util.Uint256 `json:"merkleroot"`
|
|
|
|
// The time stamp of each block must be later than previous block's time stamp.
|
|
// Generally the difference of two block's time stamp is about 15 seconds and imprecision is allowed.
|
|
// The height of the block must be exactly equal to the height of the previous block plus 1.
|
|
Timestamp uint32 `json:"time"`
|
|
|
|
// index/height of the block
|
|
Index uint32 `json:"height"`
|
|
|
|
// Random number also called nonce
|
|
ConsensusData uint64 `json:"nonce"`
|
|
|
|
// Contract address of the next miner
|
|
NextConsensus util.Uint160 `json:"next_consensus"`
|
|
|
|
// Padding that is fixed to 1
|
|
_ uint8
|
|
|
|
// Script used to validate the block
|
|
Script *transaction.Witness `json:"script"`
|
|
|
|
// Hash of this block, created when binary encoded (double SHA256).
|
|
hash util.Uint256
|
|
|
|
// Hash of the block used to verify it (single SHA256).
|
|
verificationHash util.Uint256
|
|
}
|
|
|
|
// Verify verifies the integrity of the BlockBase.
|
|
func (b *BlockBase) Verify() bool {
|
|
// TODO: Need a persisted blockchain for this.
|
|
return true
|
|
}
|
|
|
|
// Hash return the hash of the block.
|
|
func (b *BlockBase) Hash() util.Uint256 {
|
|
if b.hash.Equals(util.Uint256{}) {
|
|
b.createHash()
|
|
}
|
|
return b.hash
|
|
}
|
|
|
|
// VerificationHash returns the hash of the block used to verify it.
|
|
func (b *BlockBase) VerificationHash() util.Uint256 {
|
|
if b.verificationHash.Equals(util.Uint256{}) {
|
|
if b.createHash() != nil {
|
|
panic("failed to compute hash!")
|
|
}
|
|
}
|
|
return b.verificationHash
|
|
}
|
|
|
|
// DecodeBinary implements Serializable interface.
|
|
func (b *BlockBase) DecodeBinary(br *io.BinReader) {
|
|
b.decodeHashableFields(br)
|
|
|
|
var padding uint8
|
|
br.ReadLE(&padding)
|
|
if padding != 1 {
|
|
br.Err = fmt.Errorf("format error: padding must equal 1 got %d", padding)
|
|
return
|
|
}
|
|
|
|
b.Script = &transaction.Witness{}
|
|
b.Script.DecodeBinary(br)
|
|
}
|
|
|
|
// EncodeBinary implements Serializable interface
|
|
func (b *BlockBase) EncodeBinary(bw *io.BinWriter) {
|
|
b.encodeHashableFields(bw)
|
|
bw.WriteLE(uint8(1))
|
|
b.Script.EncodeBinary(bw)
|
|
}
|
|
|
|
// getHashableData returns serialized hashable data of the block.
|
|
func (b *BlockBase) getHashableData() ([]byte, error) {
|
|
buf := io.NewBufBinWriter()
|
|
b.encodeHashableFields(buf.BinWriter)
|
|
if buf.Err != nil {
|
|
return nil, buf.Err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// createHash creates the hash of the block.
|
|
// When calculating the hash value of the block, instead of calculating the entire block,
|
|
// only first seven fields in the block head will be calculated, which are
|
|
// version, PrevBlock, MerkleRoot, timestamp, and height, the nonce, NextMiner.
|
|
// Since MerkleRoot already contains the hash value of all transactions,
|
|
// the modification of transaction will influence the hash value of the block.
|
|
func (b *BlockBase) createHash() error {
|
|
bb, err := b.getHashableData()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.hash = hash.DoubleSha256(bb)
|
|
b.verificationHash = hash.Sha256(bb)
|
|
|
|
return nil
|
|
}
|
|
|
|
// encodeHashableFields will only encode the fields used for hashing.
|
|
// see Hash() for more information about the fields.
|
|
func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) {
|
|
bw.WriteLE(b.Version)
|
|
bw.WriteLE(b.PrevHash)
|
|
bw.WriteLE(b.MerkleRoot)
|
|
bw.WriteLE(b.Timestamp)
|
|
bw.WriteLE(b.Index)
|
|
bw.WriteLE(b.ConsensusData)
|
|
bw.WriteLE(b.NextConsensus)
|
|
}
|
|
|
|
// decodeHashableFields will only decode the fields used for hashing.
|
|
// see Hash() for more information about the fields.
|
|
func (b *BlockBase) decodeHashableFields(br *io.BinReader) {
|
|
br.ReadLE(&b.Version)
|
|
br.ReadLE(&b.PrevHash)
|
|
br.ReadLE(&b.MerkleRoot)
|
|
br.ReadLE(&b.Timestamp)
|
|
br.ReadLE(&b.Index)
|
|
br.ReadLE(&b.ConsensusData)
|
|
br.ReadLE(&b.NextConsensus)
|
|
|
|
// Make the hash of the block here so we dont need to do this
|
|
// again.
|
|
if br.Err == nil {
|
|
br.Err = b.createHash()
|
|
}
|
|
}
|