aboutsummaryrefslogblamecommitdiffstats
path: root/core/types/block.go
blob: cf2a7080efc7313c7efabfd205fb3ca268c1f484 (plain) (tree)
1
2
3
4
5
6
7
8
9
             

        
                         
             
            
                  
              
              
 
                                                
                                                     
                                             

 
                    
                                     
                              
                               
                             
                                
                               
                           
                        
                 
                          
                      
                               
                
                   

                                           

                           



                         

                        

                     
                                                       
                             
                
                     

 







                                               
                                                           












                                 
                           
         
                      
                                                                   
         




                                           

 




                                             

 
                   








                                       

                         

 



















                                                                 
                                                                                                                                          




                                       
                                                      
                                  

                                         
         
                              
                                       


                    
                                            
                                                        

 

                                                

 
                                                   


                                             
         














                                                                                  

                          
                                                                                                  
                  

 








                                                       

                                     

 

                                       

 

                                                      
                                                     

 

                                                

 
                                                               
                                                       
                                               
                                          

                 
                  

 


                                                               
 



                                                                  
 

                                        

 



                                                     
 



                                                      
 








                                                                                                      


                                                                                 
                                   
                                                            

                                           
                                   

 

                                                                            


                                                                               

                                                                        











                                                       
 












                                                     
                      

                                                                                 
 

                                               





                                         

                                                     



                                             

 
















                                                                                                                              
                                    
                                                        
           

       
  

             
  
       

  
                                                                                                                    


                                     













                              

                                
                                                                                                                                                                                                                                   
 
 
                    
 
                                     
 



                                         
         
                     
 
 


                                       
 
 


                                                                       
 
                                                                                              
 
                                                                                         
package types

import (
    "encoding/binary"
    "fmt"
    "io"
    "math/big"
    "sort"
    "time"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/crypto/sha3"
    "github.com/ethereum/go-ethereum/rlp"
)

type Header struct {
    // Hash to the previous block
    ParentHash common.Hash
    // Uncles of this block
    UncleHash common.Hash
    // The coin base address
    Coinbase common.Address
    // Block Trie state
    Root common.Hash
    // Tx sha
    TxHash common.Hash
    // Receipt sha
    ReceiptHash common.Hash
    // Bloom
    Bloom Bloom
    // 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
    // Mix digest for quick checking to prevent DOS
    MixDigest common.Hash
    // Nonce
    Nonce [8]byte
}

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{} {
    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)
}

func rlpHash(x interface{}) (h common.Hash) {
    hw := sha3.NewKeccak256()
    rlp.Encode(hw, x)
    hw.Sum(h[:0])
    return h
}

type Block struct {
    // 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
}

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),
    }
    header.SetNonce(nonce)
    block := &Block{header: header}
    return block
}

func (self *Header) SetNonce(nonce uint64) {
    binary.BigEndian.PutUint64(self.Nonce[:], nonce)
}

func NewBlockWithHeader(header *Header) *Block {
    return &Block{header: header}
}

func (self *Block) DecodeRLP(s *rlp.Stream) error {
    var eb extblock
    if err := s.Decode(&eb); err != nil {
        return err
    }
    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
}

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
}

func (self *Block) Uncles() []*Header {
    return self.uncles
}

func (self *Block) SetUncles(uncleHeaders []*Header) {
    self.uncles = uncleHeaders
    self.header.UncleHash = rlpHash(uncleHeaders)
}

func (self *Block) Transactions() Transactions {
    return self.transactions
}

func (self *Block) Transaction(hash common.Hash) *Transaction {
    for _, transaction := range self.transactions {
        if transaction.Hash() == 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) MixDigest() common.Hash { return self.header.MixDigest }
func (self *Block) Nonce() uint64 {
    return binary.BigEndian.Uint64(self.header.Nonce[:])
}
func (self *Block) SetNonce(nonce uint64) {
    self.header.SetNonce(nonce)
}

func (self *Block) Bloom() Bloom             { return self.header.Bloom }
func (self *Block) Coinbase() common.Address { 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() common.Hash        { return self.header.Root }
func (self *Block) SetRoot(root common.Hash) { self.header.Root = root }
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
}

// Implement pow.Block
func (self *Block) Difficulty() *big.Int     { return self.header.Difficulty }
func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() }

func (self *Block) Hash() common.Hash {
    if (self.HeaderHash != common.Hash{}) {
        return self.HeaderHash
    } else {
        return self.header.Hash()
    }
}

func (self *Block) ParentHash() common.Hash {
    if (self.ParentHeaderHash != common.Hash{}) {
        return self.ParentHeaderHash
    } else {
        return self.header.ParentHash
    }
}

func (self *Block) Copy() *Block {
    block := NewBlock(self.ParentHash(), self.Coinbase(), self.Root(), self.Difficulty(), self.Nonce(), self.header.Extra)
    block.header.Bloom = self.header.Bloom
    block.header.TxHash = self.header.TxHash
    block.transactions = self.transactions
    block.header.UncleHash = self.header.UncleHash
    block.uncles = self.uncles
    block.header.GasLimit.Set(self.header.GasLimit)
    block.header.GasUsed.Set(self.header.GasUsed)
    block.header.ReceiptHash = self.header.ReceiptHash
    block.header.Difficulty.Set(self.header.Difficulty)
    block.header.Number = self.header.Number
    block.header.Time = self.header.Time
    block.header.MixDigest = self.header.MixDigest
    return block
}

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
    MixDigest:          %x
    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.MixDigest, 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 }