aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain/block.go
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-02-15 06:56:09 +0800
committerobscuren <geffobscura@gmail.com>2014-02-15 06:56:09 +0800
commitf6d1bfe45bf3709d7bad40bf563b5c09228622e3 (patch)
treedf48311a5a494c66c74dcd51f1056cc699f01507 /ethchain/block.go
parentc2fb9f06ad018d01ce335c82b3542de16045a32d (diff)
downloaddexon-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.tar.gz
dexon-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.tar.zst
dexon-f6d1bfe45bf3709d7bad40bf563b5c09228622e3.zip
The great merge
Diffstat (limited to 'ethchain/block.go')
-rw-r--r--ethchain/block.go363
1 files changed, 363 insertions, 0 deletions
diff --git a/ethchain/block.go b/ethchain/block.go
new file mode 100644
index 000000000..a7a1f787b
--- /dev/null
+++ b/ethchain/block.go
@@ -0,0 +1,363 @@
+package ethchain
+
+import (
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+ "time"
+)
+
+type BlockInfo struct {
+ Number uint64
+ Hash []byte
+ Parent []byte
+}
+
+func (bi *BlockInfo) RlpDecode(data []byte) {
+ decoder := ethutil.NewValueFromBytes(data)
+
+ bi.Number = decoder.Get(0).Uint()
+ bi.Hash = decoder.Get(1).Bytes()
+ bi.Parent = decoder.Get(2).Bytes()
+}
+
+func (bi *BlockInfo) RlpEncode() []byte {
+ return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
+}
+
+type Block struct {
+ // Hash to the previous block
+ PrevHash []byte
+ // Uncles of this block
+ Uncles []*Block
+ UncleSha []byte
+ // The coin base address
+ Coinbase []byte
+ // Block Trie state
+ state *ethutil.Trie
+ // Difficulty for the current block
+ Difficulty *big.Int
+ // Creation time
+ Time int64
+ // Extra data
+ Extra string
+ // Block Nonce for verification
+ Nonce []byte
+ // List of transactions and/or contracts
+ transactions []*Transaction
+ TxSha []byte
+}
+
+// New block takes a raw encoded string
+// XXX DEPRICATED
+func NewBlockFromData(raw []byte) *Block {
+ return NewBlockFromBytes(raw)
+}
+
+func NewBlockFromBytes(raw []byte) *Block {
+ block := &Block{}
+ block.RlpDecode(raw)
+
+ return block
+}
+
+// New block takes a raw encoded string
+func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
+ block := &Block{}
+ block.RlpValueDecode(rlpValue)
+
+ return block
+}
+
+func CreateBlock(root interface{},
+ prevHash []byte,
+ base []byte,
+ Difficulty *big.Int,
+ Nonce []byte,
+ extra string,
+ txes []*Transaction) *Block {
+
+ block := &Block{
+ // Slice of transactions to include in this block
+ transactions: txes,
+ PrevHash: prevHash,
+ Coinbase: base,
+ Difficulty: Difficulty,
+ Nonce: Nonce,
+ Time: time.Now().Unix(),
+ Extra: extra,
+ UncleSha: EmptyShaList,
+ }
+ block.SetTransactions(txes)
+ block.SetUncles([]*Block{})
+
+ block.state = ethutil.NewTrie(ethutil.Config.Db, root)
+
+ for _, tx := range txes {
+ block.MakeContract(tx)
+ }
+
+ return block
+}
+
+// Returns a hash of the block
+func (block *Block) Hash() []byte {
+ return ethutil.Sha3Bin(block.RlpValue().Encode())
+}
+
+func (block *Block) HashNoNonce() []byte {
+ return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
+}
+
+func (block *Block) PrintHash() {
+ fmt.Println(block)
+ fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
+}
+
+func (block *Block) State() *ethutil.Trie {
+ return block.state
+}
+
+func (block *Block) Transactions() []*Transaction {
+ return block.transactions
+}
+
+func (block *Block) GetContract(addr []byte) *Contract {
+ data := block.state.Get(string(addr))
+ if data == "" {
+ return nil
+ }
+
+ contract := &Contract{}
+ contract.RlpDecode([]byte(data))
+
+ return contract
+}
+func (block *Block) UpdateContract(addr []byte, contract *Contract) {
+ // Make sure the state is synced
+ contract.State().Sync()
+
+ block.state.Update(string(addr), string(contract.RlpEncode()))
+}
+
+func (block *Block) GetAddr(addr []byte) *Address {
+ var address *Address
+
+ data := block.State().Get(string(addr))
+ if data == "" {
+ address = NewAddress(big.NewInt(0))
+ } else {
+ address = NewAddressFromData([]byte(data))
+ }
+
+ return address
+}
+func (block *Block) UpdateAddr(addr []byte, address *Address) {
+ block.state.Update(string(addr), string(address.RlpEncode()))
+}
+
+func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
+ contract := block.GetContract(addr)
+ // If we can't pay the fee return
+ if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
+ fmt.Println("Contract has insufficient funds", contract.Amount, fee)
+
+ return false
+ }
+
+ base := new(big.Int)
+ contract.Amount = base.Sub(contract.Amount, fee)
+ block.state.Update(string(addr), string(contract.RlpEncode()))
+
+ data := block.state.Get(string(block.Coinbase))
+
+ // Get the ether (Coinbase) and add the fee (gief fee to miner)
+ ether := NewAddressFromData([]byte(data))
+
+ base = new(big.Int)
+ ether.Amount = base.Add(ether.Amount, fee)
+
+ block.state.Update(string(block.Coinbase), string(ether.RlpEncode()))
+
+ return true
+}
+
+func (block *Block) BlockInfo() BlockInfo {
+ bi := BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+func (block *Block) MakeContract(tx *Transaction) {
+ // Create contract if there's no recipient
+ if tx.IsContract() {
+ addr := tx.Hash()
+
+ value := tx.Value
+ contract := NewContract(value, []byte(""))
+ block.state.Update(string(addr), string(contract.RlpEncode()))
+ for i, val := range tx.Data {
+ contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val)
+ }
+ block.UpdateContract(addr, contract)
+ }
+}
+
+/////// Block Encoding
+func (block *Block) encodedUncles() interface{} {
+ uncles := make([]interface{}, len(block.Uncles))
+ for i, uncle := range block.Uncles {
+ uncles[i] = uncle.RlpEncode()
+ }
+
+ return uncles
+}
+
+func (block *Block) encodedTxs() interface{} {
+ // Marshal the transactions of this block
+ encTx := make([]interface{}, len(block.transactions))
+ for i, tx := range block.transactions {
+ // Cast it to a string (safe)
+ encTx[i] = tx.RlpData()
+ }
+
+ return encTx
+}
+
+func (block *Block) rlpTxs() interface{} {
+ // Marshal the transactions of this block
+ encTx := make([]interface{}, len(block.transactions))
+ for i, tx := range block.transactions {
+ // Cast it to a string (safe)
+ encTx[i] = tx.RlpData()
+ }
+
+ return encTx
+}
+
+func (block *Block) rlpUncles() interface{} {
+ // Marshal the transactions of this block
+ uncles := make([]interface{}, len(block.Uncles))
+ for i, uncle := range block.Uncles {
+ // Cast it to a string (safe)
+ uncles[i] = uncle.header()
+ }
+
+ return uncles
+}
+
+func (block *Block) SetUncles(uncles []*Block) {
+ block.Uncles = uncles
+
+ // Sha of the concatenated uncles
+ block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
+}
+
+func (block *Block) SetTransactions(txs []*Transaction) {
+ block.transactions = txs
+
+ block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs()))
+}
+
+func (block *Block) RlpValue() *ethutil.RlpValue {
+ return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
+}
+
+func (block *Block) RlpEncode() []byte {
+ // Encode a slice interface which contains the header and the list of
+ // transactions.
+ return block.RlpValue().Encode()
+}
+
+func (block *Block) RlpDecode(data []byte) {
+ rlpValue := ethutil.NewValueFromBytes(data)
+ block.RlpValueDecode(rlpValue)
+}
+
+func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
+ header := decoder.Get(0)
+
+ block.PrevHash = header.Get(0).Bytes()
+ block.UncleSha = header.Get(1).Bytes()
+ block.Coinbase = header.Get(2).Bytes()
+ block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
+ block.TxSha = header.Get(4).Bytes()
+ block.Difficulty = header.Get(5).BigInt()
+ block.Time = int64(header.Get(6).BigInt().Uint64())
+ block.Extra = header.Get(7).Str()
+ block.Nonce = header.Get(8).Bytes()
+
+ // Tx list might be empty if this is an uncle. Uncles only have their
+ // header set.
+ if decoder.Get(1).IsNil() == false { // Yes explicitness
+ txes := decoder.Get(1)
+ block.transactions = make([]*Transaction, txes.Len())
+ for i := 0; i < txes.Len(); i++ {
+ tx := NewTransactionFromValue(txes.Get(i))
+
+ block.transactions[i] = tx
+
+ /*
+ if ethutil.Config.Debug {
+ ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx))
+ }
+ */
+ }
+
+ }
+
+ if decoder.Get(2).IsNil() == false { // Yes explicitness
+ uncles := decoder.Get(2)
+ block.Uncles = make([]*Block, uncles.Len())
+ for i := 0; i < uncles.Len(); i++ {
+ block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
+ }
+ }
+
+}
+
+func NewUncleBlockFromValue(header *ethutil.Value) *Block {
+ block := &Block{}
+
+ block.PrevHash = header.Get(0).Bytes()
+ block.UncleSha = header.Get(1).Bytes()
+ block.Coinbase = header.Get(2).Bytes()
+ block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
+ block.TxSha = header.Get(4).Bytes()
+ block.Difficulty = header.Get(5).BigInt()
+ block.Time = int64(header.Get(6).BigInt().Uint64())
+ block.Extra = header.Get(7).Str()
+ block.Nonce = header.Get(8).Bytes()
+
+ return block
+}
+
+func (block *Block) String() string {
+ return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce)
+}
+
+//////////// UNEXPORTED /////////////////
+func (block *Block) header() []interface{} {
+ return []interface{}{
+ // Sha of the previous block
+ block.PrevHash,
+ // Sha of uncles
+ block.UncleSha,
+ // Coinbase address
+ block.Coinbase,
+ // root state
+ block.state.Root,
+ // Sha of tx
+ block.TxSha,
+ // Current block Difficulty
+ block.Difficulty,
+ // Time the block was found?
+ block.Time,
+ // Extra data
+ block.Extra,
+ // Block's Nonce for validation
+ block.Nonce,
+ }
+}