package types import ( "bytes" "fmt" "math/big" "sort" "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/rlp" ) type Header struct { // Hash to the previous block ParentHash ethutil.Bytes // Uncles of this block UncleHash []byte // The coin base address Coinbase []byte // Block Trie state Root []byte // Tx sha TxHash []byte // Receipt sha ReceiptHash []byte // Bloom Bloom []byte // Difficulty for the current block Difficulty *big.Int // The block number Number *big.Int // Gas limit GasLimit *big.Int // Gas used GasUsed *big.Int // Creation time Time uint64 // Extra data Extra string // Block Nonce for verification Nonce ethutil.Bytes } func (self *Header) rlpData(withNonce bool) []interface{} { 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.Nonce) } return fields } func (self *Header) RlpData() interface{} { return self.rlpData(true) } func (self *Header) Hash() []byte { return crypto.Sha3(ethutil.Encode(self.rlpData(true))) } func (self *Header) HashNoNonce() []byte { return crypto.Sha3(ethutil.Encode(self.rlpData(false))) } type Block struct { // Preset Hash for mock HeaderHash []byte ParentHeaderHash []byte header *Header uncles []*Header transactions Transactions Td *big.Int receipts Receipts Reward *big.Int } func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block { header := &Header{ Root: root, ParentHash: parentHash, Coinbase: coinbase, Difficulty: difficulty, Nonce: nonce, Time: uint64(time.Now().Unix()), Extra: extra, GasUsed: new(big.Int), GasLimit: new(big.Int), } block := &Block{header: header, Reward: new(big.Int)} return block } func NewBlockWithHeader(header *Header) *Block { return &Block{header: header} } func (self *Block) DecodeRLP(s *rlp.Stream) error { var extblock struct { Header *Header Txs []*Transaction Uncles []*Header TD *big.Int // optional } if err := s.Decode(&extblock); err != nil { return err } self.header = extblock.Header self.uncles = extblock.Uncles self.transactions = extblock.Txs self.Td = extblock.TD return nil } func (self *Block) Header() *Header { return self.header } func (self *Block) Uncles() []*Header { return self.uncles } func (self *Block) SetUncles(uncleHeaders []*Header) { self.uncles = uncleHeaders self.header.UncleHash = crypto.Sha3(ethutil.Encode(uncleHeaders)) } func (self *Block) Transactions() Transactions { return self.transactions } func (self *Block) Transaction(hash []byte) *Transaction { for _, transaction := range self.transactions { if bytes.Equal(hash, transaction.Hash()) { return transaction } } return nil } func (self *Block) SetTransactions(transactions Transactions) { self.transactions = transactions self.header.TxHash = DeriveSha(transactions) } func (self *Block) AddTransaction(transaction *Transaction) { self.transactions = append(self.transactions, transaction) self.SetTransactions(self.transactions) } func (self *Block) Receipts() Receipts { return self.receipts } func (self *Block) SetReceipts(receipts Receipts) { self.receipts = receipts self.header.ReceiptHash = DeriveSha(receipts) self.header.Bloom = CreateBloom(receipts) } 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) func (self *Block) Number() *big.Int { return self.header.Number } func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } func (self *Block) Nonce() []byte { return self.header.Nonce } func (self *Block) Bloom() []byte { return self.header.Bloom } func (self *Block) Coinbase() []byte { return self.header.Coinbase } 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 } func (self *Block) Root() []byte { return self.header.Root } func (self *Block) SetRoot(root []byte) { self.header.Root = root } func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) } 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 } // Implement pow.Block func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } func (self *Block) N() []byte { return self.header.Nonce } func (self *Block) HashNoNonce() []byte { return self.header.HashNoNonce() } func (self *Block) Hash() []byte { if self.HeaderHash != nil { return self.HeaderHash } else { return self.header.Hash() } } func (self *Block) ParentHash() []byte { if self.ParentHeaderHash != nil { return self.ParentHeaderHash } else { return self.header.ParentHash } } func (self *Block) String() string { return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v { NoNonce: %x Header: [ %v ] Transactions: %v Uncles: %v } `, self.header.Hash(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) } func (self *Header) String() string { 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 Nonce: %x `, 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.Nonce) } type Blocks []*Block type BlockBy func(b1, b2 *Block) bool func (self BlockBy) Sort(blocks Blocks) { bs := blockSorter{ blocks: blocks, by: self, } sort.Sort(bs) } type blockSorter struct { blocks Blocks by func(b1, b2 *Block) bool } 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]) } func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 }