forked from TrueCloudLab/neoneo-go
5bf00db2c9
The logic here is that we'll have all binary encoding/decoding done via our io package, which simplifies error handling. This functionality doesn't belong to util, so it's moved. This also expands BufBinWriter with Reset() method to fit the needs of core package.
139 lines
3.7 KiB
Go
139 lines
3.7 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.
|
|
hash 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
|
|
}
|
|
|
|
// DecodeBinary implements the payload interface.
|
|
func (b *BlockBase) DecodeBinary(br *io.BinReader) error {
|
|
if err := b.decodeHashableFields(br); err != nil {
|
|
return err
|
|
}
|
|
|
|
var padding uint8
|
|
br.ReadLE(&padding)
|
|
if br.Err != nil {
|
|
return br.Err
|
|
}
|
|
if padding != 1 {
|
|
return fmt.Errorf("format error: padding must equal 1 got %d", padding)
|
|
}
|
|
|
|
b.Script = &transaction.Witness{}
|
|
return b.Script.DecodeBinary(br)
|
|
}
|
|
|
|
// EncodeBinary implements the Payload interface
|
|
func (b *BlockBase) EncodeBinary(bw *io.BinWriter) error {
|
|
if err := b.encodeHashableFields(bw); err != nil {
|
|
return err
|
|
}
|
|
bw.WriteLE(uint8(1))
|
|
if bw.Err != nil {
|
|
return bw.Err
|
|
}
|
|
return b.Script.EncodeBinary(bw)
|
|
}
|
|
|
|
// 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 {
|
|
buf := io.NewBufBinWriter()
|
|
if err := b.encodeHashableFields(buf.BinWriter); err != nil {
|
|
return err
|
|
}
|
|
b.hash = hash.DoubleSha256(buf.Bytes())
|
|
|
|
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) error {
|
|
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)
|
|
return bw.Err
|
|
}
|
|
|
|
// decodeHashableFields will only decode the fields used for hashing.
|
|
// see Hash() for more information about the fields.
|
|
func (b *BlockBase) decodeHashableFields(br *io.BinReader) error {
|
|
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)
|
|
|
|
if br.Err != nil {
|
|
return br.Err
|
|
}
|
|
|
|
// Make the hash of the block here so we dont need to do this
|
|
// again.
|
|
return b.createHash()
|
|
}
|