quorum/core/types/block.go

363 lines
8.5 KiB
Go
Raw Normal View History

package types
2014-02-14 14:56:09 -08:00
import (
2015-03-03 12:48:05 -08:00
"encoding/binary"
2014-02-14 14:56:09 -08:00
"fmt"
"io"
2014-07-26 02:24:44 -07:00
"math/big"
2014-09-15 06:42:12 -07:00
"sort"
2014-07-26 02:24:44 -07:00
"time"
2015-02-13 09:15:23 -08:00
2015-03-16 03:27:38 -07:00
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
2014-02-14 14:56:09 -08:00
)
type Header struct {
2014-02-14 14:56:09 -08:00
// Hash to the previous block
2015-03-16 03:59:52 -07:00
ParentHash common.Hash
2014-02-14 14:56:09 -08:00
// Uncles of this block
2015-03-16 03:59:52 -07:00
UncleHash common.Hash
2014-02-14 14:56:09 -08:00
// The coin base address
2015-03-16 03:59:52 -07:00
Coinbase common.Address
2014-02-14 14:56:09 -08:00
// Block Trie state
2015-03-16 03:59:52 -07:00
Root common.Hash
// Tx sha
2015-03-16 03:59:52 -07:00
TxHash common.Hash
// Receipt sha
2015-03-16 03:59:52 -07:00
ReceiptHash common.Hash
// Bloom
2015-03-16 09:27:23 -07:00
Bloom Bloom
2014-02-14 14:56:09 -08:00
// Difficulty for the current block
Difficulty *big.Int
2014-05-20 05:29:52 -07:00
// The block number
Number *big.Int
// Gas limit
GasLimit *big.Int
// Gas used
GasUsed *big.Int
// Creation time
Time uint64
2014-02-14 14:56:09 -08:00
// Extra data
Extra string
// Mix digest for quick checking to prevent DOS
2015-03-16 03:59:52 -07:00
MixDigest common.Hash
// Nonce
2015-03-16 03:59:52 -07:00
Nonce [8]byte
2014-02-14 14:56:09 -08:00
}
func (self *Header) Hash() common.Hash {
return rlpHash(self.rlpData(true))
}
func (self *Header) HashNoNonce() common.Hash {
return rlpHash(self.rlpData(false))
}
func (self *Header) rlpData(withNonce bool) []interface{} {
2015-02-28 11:58:37 -08:00
fields := []interface{}{
self.ParentHash,
self.UncleHash,
self.Coinbase,
self.Root,
self.TxHash,
self.ReceiptHash,
self.Bloom,
self.Difficulty,
self.Number,
self.GasLimit,
self.GasUsed,
self.Time,
self.Extra,
}
if withNonce {
fields = append(fields, self.MixDigest, self.Nonce)
}
return fields
}
func (self *Header) RlpData() interface{} {
return self.rlpData(true)
2014-02-14 14:56:09 -08:00
}
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)
hw.Sum(h[:0])
return h
2014-02-14 14:56:09 -08:00
}
type Block struct {
2015-03-16 09:27:23 -07:00
// Preset Hash for mock (Tests)
HeaderHash common.Hash
ParentHeaderHash common.Hash
// ^^^^ ignore ^^^^
header *Header
uncles []*Header
transactions Transactions
Td *big.Int
receipts Receipts
}
// StorageBlock defines the RLP encoding of a Block stored in the
// state database. The StorageBlock encoding contains fields that
// would otherwise need to be recomputed.
type StorageBlock Block
// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
}
// "storage" block encoding. used for database.
type storageblock struct {
Header *Header
Txs []*Transaction
Uncles []*Header
TD *big.Int
}
2015-03-16 09:27:23 -07:00
func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra string) *Block {
header := &Header{
Root: root,
ParentHash: parentHash,
Coinbase: coinbase,
Difficulty: difficulty,
Time: uint64(time.Now().Unix()),
Extra: extra,
GasUsed: new(big.Int),
GasLimit: new(big.Int),
2014-02-14 14:56:09 -08:00
}
2015-03-16 15:10:26 -07:00
header.SetNonce(nonce)
2015-03-23 14:05:12 -07:00
block := &Block{header: header}
2014-02-14 14:56:09 -08:00
return block
}
2015-03-16 15:10:26 -07:00
func (self *Header) SetNonce(nonce uint64) {
2015-03-16 09:27:23 -07:00
binary.BigEndian.PutUint64(self.Nonce[:], nonce)
2015-03-03 12:48:05 -08:00
}
func NewBlockWithHeader(header *Header) *Block {
return &Block{header: header}
2014-02-14 14:56:09 -08:00
}
func (self *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock
if err := s.Decode(&eb); err != nil {
return err
2014-02-14 14:56:09 -08:00
}
self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs
return nil
}
func (self Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, extblock{
Header: self.header,
Txs: self.transactions,
Uncles: self.uncles,
})
}
func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error {
var sb storageblock
if err := s.Decode(&sb); err != nil {
return err
}
self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD
return nil
2014-10-29 06:20:42 -07:00
}
func (self StorageBlock) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, storageblock{
Header: self.header,
Txs: self.transactions,
Uncles: self.uncles,
TD: self.Td,
})
}
func (self *Block) Header() *Header {
return self.header
2014-02-14 14:56:09 -08:00
}
func (self *Block) Uncles() []*Header {
return self.uncles
2014-02-14 14:56:09 -08:00
}
func (self *Block) SetUncles(uncleHeaders []*Header) {
self.uncles = uncleHeaders
self.header.UncleHash = rlpHash(uncleHeaders)
2014-02-14 14:56:09 -08:00
}
func (self *Block) Transactions() Transactions {
return self.transactions
2014-02-14 14:56:09 -08:00
}
func (self *Block) Transaction(hash common.Hash) *Transaction {
for _, transaction := range self.transactions {
if transaction.Hash() == hash {
return transaction
2014-02-14 14:56:09 -08:00
}
}
return nil
2014-02-14 14:56:09 -08:00
}
func (self *Block) SetTransactions(transactions Transactions) {
self.transactions = transactions
self.header.TxHash = DeriveSha(transactions)
}
2015-02-04 05:52:59 -08:00
func (self *Block) AddTransaction(transaction *Transaction) {
self.transactions = append(self.transactions, transaction)
self.SetTransactions(self.transactions)
}
func (self *Block) Receipts() Receipts {
return self.receipts
2014-02-14 14:56:09 -08:00
}
func (self *Block) SetReceipts(receipts Receipts) {
self.receipts = receipts
self.header.ReceiptHash = DeriveSha(receipts)
self.header.Bloom = CreateBloom(receipts)
}
2015-02-04 05:52:59 -08:00
func (self *Block) AddReceipt(receipt *Receipt) {
self.receipts = append(self.receipts, receipt)
self.SetReceipts(self.receipts)
}
func (self *Block) RlpData() interface{} {
return []interface{}{self.header, self.transactions, self.uncles}
}
func (self *Block) RlpDataForStorage() interface{} {
return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
}
// Header accessors (add as you need them)
2015-03-16 09:27:23 -07:00
func (self *Block) Number() *big.Int { return self.header.Number }
func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
func (self *Block) MixDigest() common.Hash { return self.header.MixDigest }
2015-03-03 12:48:05 -08:00
func (self *Block) Nonce() uint64 {
2015-03-16 09:27:23 -07:00
return binary.BigEndian.Uint64(self.header.Nonce[:])
2015-03-03 12:48:05 -08:00
}
func (self *Block) SetNonce(nonce uint64) {
2015-03-16 15:10:26 -07:00
self.header.SetNonce(nonce)
2015-03-03 12:48:05 -08:00
}
2015-03-16 09:27:23 -07:00
func (self *Block) Bloom() Bloom { return self.header.Bloom }
func (self *Block) Coinbase() common.Address { return self.header.Coinbase }
2015-03-16 03:59:52 -07:00
func (self *Block) Time() int64 { return int64(self.header.Time) }
func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
2015-03-16 09:27:23 -07:00
func (self *Block) Root() common.Hash { return self.header.Root }
func (self *Block) SetRoot(root common.Hash) { self.header.Root = root }
2015-02-18 04:14:21 -08:00
func (self *Block) GetTransaction(i int) *Transaction {
if len(self.transactions) > i {
return self.transactions[i]
}
return nil
}
func (self *Block) GetUncle(i int) *Header {
if len(self.uncles) > i {
return self.uncles[i]
}
return nil
}
func (self *Block) Size() common.StorageSize {
c := writeCounter(0)
rlp.Encode(&c, self)
return common.StorageSize(c)
}
type writeCounter common.StorageSize
func (c *writeCounter) Write(b []byte) (int, error) {
*c += writeCounter(len(b))
return len(b), nil
}
2015-01-05 08:10:42 -08:00
// Implement pow.Block
2015-03-16 09:27:23 -07:00
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() }
2015-01-05 08:10:42 -08:00
2015-03-16 09:27:23 -07:00
func (self *Block) Hash() common.Hash {
if (self.HeaderHash != common.Hash{}) {
2015-01-05 08:10:42 -08:00
return self.HeaderHash
} else {
return self.header.Hash()
}
}
2015-03-16 09:27:23 -07:00
func (self *Block) ParentHash() common.Hash {
if (self.ParentHeaderHash != common.Hash{}) {
2015-01-05 08:10:42 -08:00
return self.ParentHeaderHash
} else {
return self.header.ParentHash
}
}
func (self *Block) String() string {
return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v {
2015-02-14 07:52:14 -08:00
NoNonce: %x
2014-12-23 05:33:15 -08:00
Header:
[
%v
2014-12-23 05:33:15 -08:00
]
Transactions:
%v
2014-12-23 05:33:15 -08:00
Uncles:
%v
}
2015-02-14 07:52:14 -08:00
`, self.header.Hash(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles)
}
func (self *Header) String() string {
2014-12-23 05:33:15 -08:00
return fmt.Sprintf(`
ParentHash: %x
UncleHash: %x
Coinbase: %x
Root: %x
TxSha %x
ReceiptSha: %x
Bloom: %x
Difficulty: %v
Number: %v
GasLimit: %v
GasUsed: %v
Time: %v
Extra: %v
2015-03-03 12:48:05 -08:00
MixDigest: %x
Nonce: %x`,
2015-03-14 08:37:57 -07:00
self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce)
2014-03-20 03:20:29 -07:00
}
2014-02-14 14:56:09 -08:00
type Blocks []*Block
type BlockBy func(b1, b2 *Block) bool
func (self BlockBy) Sort(blocks Blocks) {
bs := blockSorter{
blocks: blocks,
by: self,
2014-02-14 14:56:09 -08:00
}
sort.Sort(bs)
2014-02-14 14:56:09 -08:00
}
2014-05-20 06:02:46 -07:00
type blockSorter struct {
blocks Blocks
by func(b1, b2 *Block) bool
2014-08-25 03:53:06 -07:00
}
func (self blockSorter) Len() int { return len(self.blocks) }
func (self blockSorter) Swap(i, j int) {
self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i]
}
func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) }
2014-12-10 07:45:16 -08:00
func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 }