aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/.gitignore12
-rw-r--r--core/asm.go50
-rw-r--r--core/block_processor.go332
-rw-r--r--core/block_processor_test.go34
-rw-r--r--core/chain_manager.go438
-rw-r--r--core/chain_manager_test.go154
-rw-r--r--core/error.go130
-rw-r--r--core/events.go18
-rw-r--r--core/execution.go77
-rw-r--r--core/fees.go7
-rw-r--r--core/filter.go187
-rw-r--r--core/filter_test.go1
-rw-r--r--core/genesis.go70
-rw-r--r--core/helper_test.go84
-rw-r--r--core/manager.go20
-rw-r--r--core/state_transition.go274
-rw-r--r--core/transaction_pool.go201
-rw-r--r--core/transaction_pool_test.go97
-rw-r--r--core/types/block.go279
-rw-r--r--core/types/block_test.go1
-rw-r--r--core/types/bloom9.go55
-rw-r--r--core/types/bloom9_test.go31
-rw-r--r--core/types/common.go7
-rw-r--r--core/types/derive_sha.go22
-rw-r--r--core/types/receipt.go81
-rw-r--r--core/types/transaction.go226
-rw-r--r--core/types/transaction_test.go1
-rw-r--r--core/vm_env.go72
28 files changed, 2961 insertions, 0 deletions
diff --git a/core/.gitignore b/core/.gitignore
new file mode 100644
index 000000000..f725d58d1
--- /dev/null
+++ b/core/.gitignore
@@ -0,0 +1,12 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile ~/.gitignore_global
+
+/tmp
+*/**/*un~
+*un~
+.DS_Store
+*/**/.DS_Store
+
diff --git a/core/asm.go b/core/asm.go
new file mode 100644
index 000000000..a8b3023f4
--- /dev/null
+++ b/core/asm.go
@@ -0,0 +1,50 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+func Disassemble(script []byte) (asm []string) {
+ pc := new(big.Int)
+ for {
+ if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
+ return
+ }
+
+ // Get the memory location of pc
+ val := script[pc.Int64()]
+ // Get the opcode (it must be an opcode!)
+ op := vm.OpCode(val)
+
+ asm = append(asm, fmt.Sprintf("%04v: %v", pc, op))
+
+ switch op {
+ case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8,
+ vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15,
+ vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22,
+ vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29,
+ vm.PUSH30, vm.PUSH31, vm.PUSH32:
+ pc.Add(pc, ethutil.Big1)
+ a := int64(op) - int64(vm.PUSH1) + 1
+ if int(pc.Int64()+a) > len(script) {
+ return
+ }
+
+ data := script[pc.Int64() : pc.Int64()+a]
+ if len(data) == 0 {
+ data = []byte{0}
+ }
+ asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data))
+
+ pc.Add(pc, big.NewInt(a-1))
+ }
+
+ pc.Add(pc, ethutil.Big1)
+ }
+
+ return asm
+}
diff --git a/core/block_processor.go b/core/block_processor.go
new file mode 100644
index 000000000..5e943bda5
--- /dev/null
+++ b/core/block_processor.go
@@ -0,0 +1,332 @@
+package core
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/pow"
+ "github.com/ethereum/go-ethereum/pow/ezp"
+ "github.com/ethereum/go-ethereum/state"
+ "gopkg.in/fatih/set.v0"
+)
+
+type PendingBlockEvent struct {
+ Block *types.Block
+}
+
+var statelogger = logger.NewLogger("BLOCK")
+
+type BlockProcessor struct {
+ db ethutil.Database
+ // Mutex for locking the block processor. Blocks can only be handled one at a time
+ mutex sync.Mutex
+ // Canonical block chain
+ bc *ChainManager
+ // non-persistent key/value memory storage
+ mem map[string]*big.Int
+ // Proof of work used for validating
+ Pow pow.PoW
+
+ txpool *TxPool
+
+ // The last attempted block is mainly used for debugging purposes
+ // This does not have to be a valid block and will be set during
+ // 'Process' & canonical validation.
+ lastAttemptedBlock *types.Block
+
+ events event.Subscription
+
+ eventMux *event.TypeMux
+}
+
+func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+ sm := &BlockProcessor{
+ db: db,
+ mem: make(map[string]*big.Int),
+ Pow: ezp.New(),
+ bc: chainManager,
+ eventMux: eventMux,
+ txpool: txpool,
+ }
+
+ return sm
+}
+
+func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
+ coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
+ coinbase.SetGasPool(block.Header().GasLimit)
+
+ // Process the transactions on to parent state
+ receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
+ if err != nil {
+ return nil, err
+ }
+
+ return receipts, nil
+}
+
+func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
+ // If we are mining this block and validating we want to set the logs back to 0
+ statedb.EmptyLogs()
+
+ txGas := new(big.Int).Set(tx.Gas())
+
+ cb := statedb.GetStateObject(coinbase.Address())
+ st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb)
+ _, err := st.TransitionState()
+ if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) {
+ return nil, nil, err
+ }
+
+ txGas.Sub(txGas, st.gas)
+
+ // Update the state with pending changes
+ statedb.Update(txGas)
+
+ cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas))
+ receipt := types.NewReceipt(statedb.Root(), cumulative)
+ receipt.SetLogs(statedb.Logs())
+ receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+ chainlogger.Debugln(receipt)
+
+ // Notify all subscribers
+ if !transientProcess {
+ go self.eventMux.Post(TxPostEvent{tx})
+ logs := statedb.Logs()
+ go self.eventMux.Post(logs)
+ }
+
+ return receipt, txGas, err
+}
+
+func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
+ var (
+ receipts types.Receipts
+ handled, unhandled types.Transactions
+ erroneous types.Transactions
+ totalUsedGas = big.NewInt(0)
+ err error
+ cumulativeSum = new(big.Int)
+ )
+
+ for _, tx := range txs {
+ receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
+ if err != nil {
+ switch {
+ case IsNonceErr(err):
+ return nil, nil, nil, nil, err
+ case state.IsGasLimitErr(err):
+ return nil, nil, nil, nil, err
+ default:
+ statelogger.Infoln(err)
+ erroneous = append(erroneous, tx)
+ err = nil
+ }
+ }
+ receipts = append(receipts, receipt)
+ handled = append(handled, tx)
+
+ cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
+ }
+
+ block.Reward = cumulativeSum
+ block.Header().GasUsed = totalUsedGas
+
+ if transientProcess {
+ go self.eventMux.Post(PendingBlockEvent{block})
+ }
+
+ return receipts, handled, unhandled, erroneous, err
+}
+
+// Process block will attempt to process the given block's transactions and applies them
+// on top of the block's parent state (given it exists) and will return wether it was
+// successful or not.
+func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, err error) {
+ // Processing a blocks may never happen simultaneously
+ sm.mutex.Lock()
+ defer sm.mutex.Unlock()
+
+ header := block.Header()
+ if sm.bc.HasBlock(header.Hash()) {
+ return nil, &KnownBlockError{header.Number, header.Hash()}
+ }
+
+ if !sm.bc.HasBlock(header.ParentHash) {
+ return nil, ParentError(header.ParentHash)
+ }
+ parent := sm.bc.GetBlock(header.ParentHash)
+
+ return sm.processWithParent(block, parent)
+}
+
+func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big.Int, err error) {
+ sm.lastAttemptedBlock = block
+
+ // Create a new state based on the parent's root (e.g., create copy)
+ state := state.New(parent.Root(), sm.db)
+
+ // Block validation
+ if err = sm.ValidateBlock(block, parent); err != nil {
+ return
+ }
+
+ receipts, err := sm.TransitionState(state, parent, block, false)
+ if err != nil {
+ return
+ }
+
+ header := block.Header()
+
+ // Validate the received block's bloom with the one derived from the generated receipts.
+ // For valid blocks this should always validate to true.
+ rbloom := types.CreateBloom(receipts)
+ if bytes.Compare(rbloom, header.Bloom) != 0 {
+ err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
+ return
+ }
+
+ // The transactions Trie's root (R = (Tr [[H1, T1], [H2, T2], ... [Hn, Tn]]))
+ // can be used by light clients to make sure they've received the correct Txs
+ txSha := types.DeriveSha(block.Transactions())
+ if bytes.Compare(txSha, header.TxHash) != 0 {
+ err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
+ return
+ }
+
+ // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
+ receiptSha := types.DeriveSha(receipts)
+ if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
+ fmt.Println("receipts", receipts)
+ state.Sync()
+ chainlogger.Infof("%s\n", state.Dump())
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha)
+ return
+ }
+
+ // Accumulate static rewards; block reward, uncle's and uncle inclusion.
+ if err = sm.AccumulateRewards(state, block, parent); err != nil {
+ return
+ }
+
+ // Commit state objects/accounts to a temporary trie (does not save)
+ // used to calculate the state root.
+ state.Update(ethutil.Big0)
+ if !bytes.Equal(header.Root, state.Root()) {
+ err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
+ return
+ }
+
+ // Calculate the td for this block
+ td = CalculateTD(block, parent)
+ // Sync the current block's state to the database
+ state.Sync()
+ // Remove transactions from the pool
+ sm.txpool.RemoveSet(block.Transactions())
+
+ chainlogger.Infof("processed block #%d (%x...)\n", header.Number, block.Hash()[0:4])
+
+ return td, nil
+}
+
+// Validates the current block. Returns an error if the block was invalid,
+// an uncle or anything that isn't on the current block chain.
+// Validation validates easy over difficult (dagger takes longer time = difficult)
+func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
+ if len(block.Header().Extra) > 1024 {
+ return fmt.Errorf("Block extra data too long (%d)", len(block.Header().Extra))
+ }
+
+ expd := CalcDifficulty(block, parent)
+ if expd.Cmp(block.Header().Difficulty) != 0 {
+ return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
+ }
+
+ expl := CalcGasLimit(parent, block)
+ if expl.Cmp(block.Header().GasLimit) != 0 {
+ return fmt.Errorf("GasLimit check failed for block %v, %v", block.Header().GasLimit, expl)
+ }
+
+ if block.Time() < parent.Time() {
+ return ValidationError("Block timestamp not after prev block (%v - %v)", block.Header().Time, parent.Header().Time)
+ }
+
+ if block.Time() > time.Now().Unix() {
+ return BlockFutureErr
+ }
+
+ if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 {
+ return BlockNumberErr
+ }
+
+ // Verify the nonce of the block. Return an error if it's not valid
+ if !sm.Pow.Verify(block) {
+ return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
+ }
+
+ return nil
+}
+
+func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, parent *types.Block) error {
+ reward := new(big.Int).Set(BlockReward)
+
+ ancestors := set.New()
+ for _, ancestor := range sm.bc.GetAncestors(block, 7) {
+ ancestors.Add(string(ancestor.Hash()))
+ }
+
+ uncles := set.New()
+ uncles.Add(string(block.Hash()))
+ for _, uncle := range block.Uncles() {
+ if uncles.Has(string(uncle.Hash())) {
+ // Error not unique
+ return UncleError("Uncle not unique")
+ }
+ uncles.Add(string(uncle.Hash()))
+
+ if !ancestors.Has(string(uncle.ParentHash)) {
+ return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
+ }
+
+ if !sm.Pow.Verify(types.NewBlockWithHeader(uncle)) {
+ return ValidationError("Uncle's nonce is invalid (= %v)", ethutil.Bytes2Hex(uncle.Nonce))
+ }
+
+ r := new(big.Int)
+ r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
+
+ statedb.AddBalance(uncle.Coinbase, r)
+
+ reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
+ }
+
+ // Get the account associated with the coinbase
+ statedb.AddBalance(block.Header().Coinbase, reward)
+
+ return nil
+}
+
+func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
+ if !sm.bc.HasBlock(block.Header().ParentHash) {
+ return nil, ParentError(block.Header().ParentHash)
+ }
+
+ sm.lastAttemptedBlock = block
+
+ var (
+ parent = sm.bc.GetBlock(block.Header().ParentHash)
+ state = state.New(parent.Root(), sm.db)
+ )
+
+ sm.TransitionState(state, parent, block, true)
+ sm.AccumulateRewards(state, block, parent)
+
+ return state.Logs(), nil
+}
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
new file mode 100644
index 000000000..35aeaa714
--- /dev/null
+++ b/core/block_processor_test.go
@@ -0,0 +1,34 @@
+package core
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+func proc() (*BlockProcessor, *ChainManager) {
+ db, _ := ethdb.NewMemDatabase()
+ var mux event.TypeMux
+
+ chainMan := NewChainManager(db, &mux)
+ return NewBlockProcessor(db, nil, chainMan, &mux), chainMan
+}
+
+func TestNumber(t *testing.T) {
+ bp, chain := proc()
+ block1 := chain.NewBlock(nil)
+ block1.Header().Number = big.NewInt(3)
+
+ err := bp.ValidateBlock(block1, chain.Genesis())
+ if err != BlockNumberErr {
+ t.Errorf("expected block number error")
+ }
+
+ block1 = chain.NewBlock(nil)
+ err = bp.ValidateBlock(block1, chain.Genesis())
+ if err == BlockNumberErr {
+ t.Errorf("didn't expect block number error")
+ }
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
new file mode 100644
index 000000000..2f6c36382
--- /dev/null
+++ b/core/chain_manager.go
@@ -0,0 +1,438 @@
+package core
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+var chainlogger = logger.NewLogger("CHAIN")
+
+type ChainEvent struct {
+ Block *types.Block
+ Td *big.Int
+}
+
+type StateQuery interface {
+ GetAccount(addr []byte) *state.StateObject
+}
+
+func CalcDifficulty(block, parent *types.Block) *big.Int {
+ diff := new(big.Int)
+
+ //adjust := new(big.Int).Rsh(parent.Difficulty(), 10)
+ //if block.Time() >= parent.Time()+8 {
+ adjust := new(big.Int).Div(parent.Difficulty(), big.NewInt(2048))
+ if (block.Time() - parent.Time()) < 8 {
+ diff.Add(parent.Difficulty(), adjust)
+ } else {
+ diff.Sub(parent.Difficulty(), adjust)
+ }
+
+ return diff
+}
+
+func CalculateTD(block, parent *types.Block) *big.Int {
+ uncleDiff := new(big.Int)
+ for _, uncle := range block.Uncles() {
+ uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
+ }
+
+ // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
+ td := new(big.Int)
+ td = td.Add(parent.Td, uncleDiff)
+ td = td.Add(td, block.Header().Difficulty)
+
+ return td
+}
+
+func CalcGasLimit(parent, block *types.Block) *big.Int {
+ if block.Number().Cmp(big.NewInt(0)) == 0 {
+ return ethutil.BigPow(10, 6)
+ }
+
+ // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
+
+ previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
+ current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
+ curInt := new(big.Int).Div(current.Num(), current.Denom())
+
+ result := new(big.Int).Add(previous, curInt)
+ result.Div(result, big.NewInt(1024))
+
+ min := big.NewInt(125000)
+
+ return ethutil.BigMax(min, result)
+}
+
+type ChainManager struct {
+ //eth EthManager
+ db ethutil.Database
+ processor types.BlockProcessor
+ eventMux *event.TypeMux
+ genesisBlock *types.Block
+ // Last known total difficulty
+ mu sync.RWMutex
+ tsmu sync.RWMutex
+ td *big.Int
+ currentBlock *types.Block
+ lastBlockHash []byte
+
+ transState *state.StateDB
+ txState *state.StateDB
+}
+
+func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
+ bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
+ bc.setLastBlock()
+ bc.transState = bc.State().Copy()
+ bc.txState = bc.State().Copy()
+
+ return bc
+}
+
+func (self *ChainManager) Td() *big.Int {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.td
+}
+
+func (self *ChainManager) LastBlockHash() []byte {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.lastBlockHash
+}
+
+func (self *ChainManager) CurrentBlock() *types.Block {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.currentBlock
+}
+
+func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
+}
+
+func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
+ self.processor = proc
+}
+
+func (self *ChainManager) State() *state.StateDB {
+ return state.New(self.CurrentBlock().Root(), self.db)
+}
+
+func (self *ChainManager) TransState() *state.StateDB {
+ self.tsmu.RLock()
+ defer self.tsmu.RUnlock()
+
+ return self.transState
+}
+
+func (self *ChainManager) TxState() *state.StateDB {
+ self.tsmu.RLock()
+ defer self.tsmu.RUnlock()
+
+ return self.txState
+}
+
+func (self *ChainManager) setTxState(state *state.StateDB) {
+ self.tsmu.Lock()
+ defer self.tsmu.Unlock()
+ self.txState = state
+}
+
+func (self *ChainManager) setTransState(statedb *state.StateDB) {
+ self.transState = statedb
+}
+
+func (bc *ChainManager) setLastBlock() {
+ data, _ := bc.db.Get([]byte("LastBlock"))
+ if len(data) != 0 {
+ var block types.Block
+ rlp.Decode(bytes.NewReader(data), &block)
+ bc.currentBlock = &block
+ bc.lastBlockHash = block.Hash()
+
+ // Set the last know difficulty (might be 0x0 as initial value, Genesis)
+ bc.td = ethutil.BigD(bc.db.LastKnownTD())
+ } else {
+ bc.Reset()
+ }
+
+ chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
+}
+
+// Block creation & chain handling
+func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
+ bc.mu.RLock()
+ defer bc.mu.RUnlock()
+
+ var root []byte
+ parentHash := ZeroHash256
+
+ if bc.currentBlock != nil {
+ root = bc.currentBlock.Header().Root
+ parentHash = bc.lastBlockHash
+ }
+
+ block := types.NewBlock(
+ parentHash,
+ coinbase,
+ root,
+ ethutil.BigPow(2, 32),
+ nil,
+ "")
+ block.SetUncles(nil)
+ block.SetTransactions(nil)
+ block.SetReceipts(nil)
+
+ parent := bc.currentBlock
+ if parent != nil {
+ header := block.Header()
+ header.Difficulty = CalcDifficulty(block, parent)
+ header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
+ header.GasLimit = CalcGasLimit(parent, block)
+
+ }
+
+ return block
+}
+
+func (bc *ChainManager) Reset() {
+ bc.mu.Lock()
+ defer bc.mu.Unlock()
+
+ for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
+ bc.db.Delete(block.Hash())
+ }
+
+ // Prepare the genesis block
+ bc.write(bc.genesisBlock)
+ bc.insert(bc.genesisBlock)
+ bc.currentBlock = bc.genesisBlock
+
+ bc.setTotalDifficulty(ethutil.Big("0"))
+}
+
+func (self *ChainManager) Export() []byte {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
+
+ blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
+ for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
+ blocks[block.NumberU64()] = block
+ }
+
+ return ethutil.Encode(blocks)
+}
+
+func (bc *ChainManager) insert(block *types.Block) {
+ encodedBlock := ethutil.Encode(block)
+ bc.db.Put([]byte("LastBlock"), encodedBlock)
+ bc.currentBlock = block
+ bc.lastBlockHash = block.Hash()
+}
+
+func (bc *ChainManager) write(block *types.Block) {
+ encodedBlock := ethutil.Encode(block.RlpDataForStorage())
+ bc.db.Put(block.Hash(), encodedBlock)
+}
+
+// Accessors
+func (bc *ChainManager) Genesis() *types.Block {
+ return bc.genesisBlock
+}
+
+// Block fetching methods
+func (bc *ChainManager) HasBlock(hash []byte) bool {
+ data, _ := bc.db.Get(hash)
+ return len(data) != 0
+}
+
+func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
+ block := self.GetBlock(hash)
+ if block == nil {
+ return
+ }
+
+ // XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
+ for i := uint64(0); i < max; i++ {
+ parentHash := block.Header().ParentHash
+ block = self.GetBlock(parentHash)
+ if block == nil {
+ chainlogger.Infof("GetBlockHashesFromHash Parent UNKNOWN %x\n", parentHash)
+ break
+ }
+
+ chain = append(chain, block.Hash())
+ if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
+ break
+ }
+ }
+
+ return
+}
+
+func (self *ChainManager) GetBlock(hash []byte) *types.Block {
+ data, _ := self.db.Get(hash)
+ if len(data) == 0 {
+ return nil
+ }
+ var block types.Block
+ if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
+ fmt.Println(err)
+ return nil
+ }
+
+ return &block
+}
+
+func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
+ for i := 0; block != nil && i < length; i++ {
+ uncles = append(uncles, block.Uncles()...)
+ block = self.GetBlock(block.ParentHash())
+ }
+
+ return
+}
+
+func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks []*types.Block) {
+ for i := 0; i < length; i++ {
+ block = self.GetBlock(block.ParentHash())
+ if block == nil {
+ break
+ }
+
+ blocks = append(blocks, block)
+ }
+
+ return
+}
+
+func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ var block *types.Block
+
+ if num <= self.currentBlock.Number().Uint64() {
+ block = self.currentBlock
+ for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
+ if block.Header().Number.Uint64() == num {
+ break
+ }
+ }
+ }
+
+ return block
+}
+
+func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
+ bc.db.Put([]byte("LTD"), td.Bytes())
+ bc.td = td
+}
+
+func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
+ parent := self.GetBlock(block.Header().ParentHash)
+ if parent == nil {
+ return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
+ }
+
+ parentTd := parent.Td
+
+ uncleDiff := new(big.Int)
+ for _, uncle := range block.Uncles() {
+ uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
+ }
+
+ td := new(big.Int)
+ td = td.Add(parentTd, uncleDiff)
+ td = td.Add(td, block.Header().Difficulty)
+
+ return td, nil
+}
+
+func (bc *ChainManager) Stop() {
+ if bc.CurrentBlock != nil {
+ chainlogger.Infoln("Stopped")
+ }
+}
+
+func (self *ChainManager) InsertChain(chain types.Blocks) error {
+ self.tsmu.Lock()
+ defer self.tsmu.Unlock()
+
+ for _, block := range chain {
+ // Call in to the block processor and check for errors. It's likely that if one block fails
+ // all others will fail too (unless a known block is returned).
+ td, err := self.processor.Process(block)
+ if err != nil {
+ if IsKnownBlockErr(err) {
+ continue
+ }
+
+ h := block.Header()
+ chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
+ chainlogger.Infoln(block)
+ chainlogger.Infoln(err)
+ return err
+ }
+ block.Td = td
+
+ var canonical, split bool
+ self.mu.Lock()
+ {
+ // Write block to database. Eventually we'll have to improve on this and throw away blocks that are
+ // not in the canonical chain.
+ self.write(block)
+ cblock := self.currentBlock
+ // Compare the TD of the last known block in the canonical chain to make sure it's greater.
+ // At this point it's possible that a different chain (fork) becomes the new canonical chain.
+ if td.Cmp(self.td) > 0 {
+ if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
+ chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
+ split = true
+ }
+
+ self.setTotalDifficulty(td)
+ self.insert(block)
+
+ canonical = true
+ }
+ }
+ self.mu.Unlock()
+
+ if canonical {
+ self.setTransState(state.New(block.Root(), self.db))
+ self.eventMux.Post(ChainEvent{block, td})
+ }
+
+ if split {
+ self.setTxState(state.New(block.Root(), self.db))
+ self.eventMux.Post(ChainSplitEvent{block})
+ }
+ }
+
+ return nil
+}
+
+// Satisfy state query interface
+func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
+ return self.State().GetAccount(addr)
+}
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
new file mode 100644
index 000000000..bc3a264d1
--- /dev/null
+++ b/core/chain_manager_test.go
@@ -0,0 +1,154 @@
+package core
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "path"
+ "runtime"
+ "strconv"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+func init() {
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
+}
+
+func loadChain(fn string, t *testing.T) (types.Blocks, error) {
+ fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ var chain types.Blocks
+ if err := rlp.Decode(fh, &chain); err != nil {
+ return nil, err
+ }
+
+ return chain, nil
+}
+
+func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
+ err := chainMan.InsertChain(chain)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+ done <- true
+}
+
+func TestChainInsertions(t *testing.T) {
+ t.Skip() // travil fails.
+
+ db, _ := ethdb.NewMemDatabase()
+
+ chain1, err := loadChain("valid1", t)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+
+ chain2, err := loadChain("valid2", t)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(db, &eventMux)
+ txPool := NewTxPool(&eventMux)
+ blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
+
+ const max = 2
+ done := make(chan bool, max)
+
+ go insertChain(done, chainMan, chain1, t)
+ go insertChain(done, chainMan, chain2, t)
+
+ for i := 0; i < max; i++ {
+ <-done
+ }
+
+ if bytes.Equal(chain2[len(chain2)-1].Hash(), chainMan.CurrentBlock().Hash()) {
+ t.Error("chain2 is canonical and shouldn't be")
+ }
+
+ if !bytes.Equal(chain1[len(chain1)-1].Hash(), chainMan.CurrentBlock().Hash()) {
+ t.Error("chain1 isn't canonical and should be")
+ }
+}
+
+func TestChainMultipleInsertions(t *testing.T) {
+ t.Skip() // travil fails.
+
+ db, _ := ethdb.NewMemDatabase()
+
+ const max = 4
+ chains := make([]types.Blocks, max)
+ var longest int
+ for i := 0; i < max; i++ {
+ var err error
+ name := "valid" + strconv.Itoa(i+1)
+ chains[i], err = loadChain(name, t)
+ if len(chains[i]) >= len(chains[longest]) {
+ longest = i
+ }
+ fmt.Println("loaded", name, "with a length of", len(chains[i]))
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+ }
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(db, &eventMux)
+ txPool := NewTxPool(&eventMux)
+ blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
+ done := make(chan bool, max)
+ for i, chain := range chains {
+ // XXX the go routine would otherwise reference the same (chain[3]) variable and fail
+ i := i
+ chain := chain
+ go func() {
+ insertChain(done, chainMan, chain, t)
+ fmt.Println(i, "done")
+ }()
+ }
+
+ for i := 0; i < max; i++ {
+ <-done
+ }
+
+ if !bytes.Equal(chains[longest][len(chains[longest])-1].Hash(), chainMan.CurrentBlock().Hash()) {
+ t.Error("Invalid canonical chain")
+ }
+}
+
+func TestGetAncestors(t *testing.T) {
+ t.Skip() // travil fails.
+
+ db, _ := ethdb.NewMemDatabase()
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(db, &eventMux)
+ chain, err := loadChain("valid1", t)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+
+ for _, block := range chain {
+ chainMan.write(block)
+ }
+
+ ancestors := chainMan.GetAncestors(chain[len(chain)-1], 4)
+ fmt.Println(ancestors)
+}
diff --git a/core/error.go b/core/error.go
new file mode 100644
index 000000000..e86bacb2d
--- /dev/null
+++ b/core/error.go
@@ -0,0 +1,130 @@
+package core
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+)
+
+var (
+ BlockNumberErr = errors.New("block number invalid")
+ BlockFutureErr = errors.New("block time is in the future")
+)
+
+// Parent error. In case a parent is unknown this error will be thrown
+// by the block manager
+type ParentErr struct {
+ Message string
+}
+
+func (err *ParentErr) Error() string {
+ return err.Message
+}
+
+func ParentError(hash []byte) error {
+ return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)}
+}
+
+func IsParentErr(err error) bool {
+ _, ok := err.(*ParentErr)
+
+ return ok
+}
+
+type UncleErr struct {
+ Message string
+}
+
+func (err *UncleErr) Error() string {
+ return err.Message
+}
+
+func UncleError(str string) error {
+ return &UncleErr{Message: str}
+}
+
+func IsUncleErr(err error) bool {
+ _, ok := err.(*UncleErr)
+
+ return ok
+}
+
+// Block validation error. If any validation fails, this error will be thrown
+type ValidationErr struct {
+ Message string
+}
+
+func (err *ValidationErr) Error() string {
+ return err.Message
+}
+
+func ValidationError(format string, v ...interface{}) *ValidationErr {
+ return &ValidationErr{Message: fmt.Sprintf(format, v...)}
+}
+
+func IsValidationErr(err error) bool {
+ _, ok := err.(*ValidationErr)
+
+ return ok
+}
+
+type NonceErr struct {
+ Message string
+ Is, Exp uint64
+}
+
+func (err *NonceErr) Error() string {
+ return err.Message
+}
+
+func NonceError(is, exp uint64) *NonceErr {
+ return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp}
+}
+
+func IsNonceErr(err error) bool {
+ _, ok := err.(*NonceErr)
+
+ return ok
+}
+
+type OutOfGasErr struct {
+ Message string
+}
+
+func OutOfGasError() *OutOfGasErr {
+ return &OutOfGasErr{Message: "Out of gas"}
+}
+func (self *OutOfGasErr) Error() string {
+ return self.Message
+}
+
+func IsOutOfGasErr(err error) bool {
+ _, ok := err.(*OutOfGasErr)
+
+ return ok
+}
+
+type TDError struct {
+ a, b *big.Int
+}
+
+func (self *TDError) Error() string {
+ return fmt.Sprintf("incoming chain has a lower or equal TD (%v <= %v)", self.a, self.b)
+}
+func IsTDError(e error) bool {
+ _, ok := e.(*TDError)
+ return ok
+}
+
+type KnownBlockError struct {
+ number *big.Int
+ hash []byte
+}
+
+func (self *KnownBlockError) Error() string {
+ return fmt.Sprintf("block %v already known (%x)", self.number, self.hash[0:4])
+}
+func IsKnownBlockErr(e error) bool {
+ _, ok := e.(*KnownBlockError)
+ return ok
+}
diff --git a/core/events.go b/core/events.go
new file mode 100644
index 000000000..4cbbc609c
--- /dev/null
+++ b/core/events.go
@@ -0,0 +1,18 @@
+package core
+
+import "github.com/ethereum/go-ethereum/core/types"
+
+// TxPreEvent is posted when a transaction enters the transaction pool.
+type TxPreEvent struct{ Tx *types.Transaction }
+
+// TxPostEvent is posted when a transaction has been processed.
+type TxPostEvent struct{ Tx *types.Transaction }
+
+// NewBlockEvent is posted when a block has been imported.
+type NewBlockEvent struct{ Block *types.Block }
+
+// NewMinedBlockEvent is posted when a block has been imported.
+type NewMinedBlockEvent struct{ Block *types.Block }
+
+// ChainSplit is posted when a new head is detected
+type ChainSplitEvent struct{ Block *types.Block }
diff --git a/core/execution.go b/core/execution.go
new file mode 100644
index 000000000..f7d5a8945
--- /dev/null
+++ b/core/execution.go
@@ -0,0 +1,77 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+type Execution struct {
+ env vm.Environment
+ address, input []byte
+ Gas, price, value *big.Int
+}
+
+func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
+ return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
+}
+
+func (self *Execution) Addr() []byte {
+ return self.address
+}
+
+func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) {
+ // Retrieve the executing code
+ code := self.env.State().GetCode(codeAddr)
+
+ return self.exec(code, codeAddr, caller)
+}
+
+func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret []byte, err error) {
+ env := self.env
+ evm := vm.NewVm(env)
+ if env.Depth() == vm.MaxCallDepth {
+ caller.ReturnGas(self.Gas, self.price)
+
+ return nil, vm.DepthError{}
+ }
+
+ vsnapshot := env.State().Copy()
+ if len(self.address) == 0 {
+ // Generate a new address
+ nonce := env.State().GetNonce(caller.Address())
+ self.address = crypto.CreateAddress(caller.Address(), nonce)
+ env.State().SetNonce(caller.Address(), nonce+1)
+ }
+
+ from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
+ err = env.Transfer(from, to, self.value)
+ if err != nil {
+ env.State().Set(vsnapshot)
+
+ caller.ReturnGas(self.Gas, self.price)
+
+ return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
+ }
+
+ snapshot := env.State().Copy()
+ start := time.Now()
+ ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
+ chainlogger.Debugf("vm took %v\n", time.Since(start))
+ if err != nil {
+ env.State().Set(snapshot)
+ }
+
+ return
+}
+
+func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
+ ret, err = self.exec(self.input, nil, caller)
+ account = self.env.State().GetStateObject(self.address)
+
+ return
+}
diff --git a/core/fees.go b/core/fees.go
new file mode 100644
index 000000000..bbce01b84
--- /dev/null
+++ b/core/fees.go
@@ -0,0 +1,7 @@
+package core
+
+import (
+ "math/big"
+)
+
+var BlockReward *big.Int = big.NewInt(1.5e+18)
diff --git a/core/filter.go b/core/filter.go
new file mode 100644
index 000000000..cdf7b282d
--- /dev/null
+++ b/core/filter.go
@@ -0,0 +1,187 @@
+package core
+
+import (
+ "bytes"
+ "math"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+type AccountChange struct {
+ Address, StateAddress []byte
+}
+
+type FilterOptions struct {
+ Earliest int64
+ Latest int64
+
+ Address [][]byte
+ Topics [][]byte
+
+ Skip int
+ Max int
+}
+
+// Filtering interface
+type Filter struct {
+ eth Backend
+ earliest int64
+ latest int64
+ skip int
+ address [][]byte
+ max int
+ topics [][]byte
+
+ BlockCallback func(*types.Block)
+ PendingCallback func(*types.Block)
+ LogsCallback func(state.Logs)
+}
+
+// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block
+// is interesting or not.
+func NewFilter(eth Backend) *Filter {
+ return &Filter{eth: eth}
+}
+
+func (self *Filter) SetOptions(options FilterOptions) {
+ self.earliest = options.Earliest
+ self.latest = options.Latest
+ self.skip = options.Skip
+ self.max = options.Max
+ self.address = options.Address
+ self.topics = options.Topics
+
+}
+
+// Set the earliest and latest block for filtering.
+// -1 = latest block (i.e., the current block)
+// hash = particular hash from-to
+func (self *Filter) SetEarliestBlock(earliest int64) {
+ self.earliest = earliest
+}
+
+func (self *Filter) SetLatestBlock(latest int64) {
+ self.latest = latest
+}
+
+func (self *Filter) SetAddress(addr [][]byte) {
+ self.address = addr
+}
+
+func (self *Filter) SetTopics(topics [][]byte) {
+ self.topics = topics
+}
+
+func (self *Filter) SetMax(max int) {
+ self.max = max
+}
+
+func (self *Filter) SetSkip(skip int) {
+ self.skip = skip
+}
+
+// Run filters logs with the current parameters set
+func (self *Filter) Find() state.Logs {
+ earliestBlock := self.eth.ChainManager().CurrentBlock()
+ var earliestBlockNo uint64 = uint64(self.earliest)
+ if self.earliest == -1 {
+ earliestBlockNo = earliestBlock.NumberU64()
+ }
+ var latestBlockNo uint64 = uint64(self.latest)
+ if self.latest == -1 {
+ latestBlockNo = earliestBlock.NumberU64()
+ }
+
+ var (
+ logs state.Logs
+ block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo)
+ quit bool
+ )
+ for i := 0; !quit && block != nil; i++ {
+ // Quit on latest
+ switch {
+ case block.NumberU64() == earliestBlockNo, block.NumberU64() == 0:
+ quit = true
+ case self.max <= len(logs):
+ break
+ }
+
+ // Use bloom filtering to see if this block is interesting given the
+ // current parameters
+ if self.bloomFilter(block) {
+ // Get the logs of the block
+ unfiltered, err := self.eth.BlockProcessor().GetLogs(block)
+ if err != nil {
+ chainlogger.Warnln("err: filter get logs ", err)
+
+ break
+ }
+
+ logs = append(logs, self.FilterLogs(unfiltered)...)
+ }
+
+ block = self.eth.ChainManager().GetBlock(block.ParentHash())
+ }
+
+ skip := int(math.Min(float64(len(logs)), float64(self.skip)))
+
+ return logs[skip:]
+}
+
+func includes(addresses [][]byte, a []byte) bool {
+ for _, addr := range addresses {
+ if !bytes.Equal(addr, a) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
+ var ret state.Logs
+
+ // Filter the logs for interesting stuff
+Logs:
+ for _, log := range logs {
+ if !includes(self.address, log.Address()) {
+ continue
+ }
+
+ max := int(math.Min(float64(len(self.topics)), float64(len(log.Topics()))))
+ for i := 0; i < max; i++ {
+ if !bytes.Equal(log.Topics()[i], self.topics[i]) {
+ continue Logs
+ }
+ }
+
+ ret = append(ret, log)
+ }
+
+ return ret
+}
+
+func (self *Filter) bloomFilter(block *types.Block) bool {
+ if len(self.address) > 0 {
+ var included bool
+ for _, addr := range self.address {
+ if types.BloomLookup(block.Bloom(), addr) {
+ included = true
+ break
+ }
+ }
+
+ if !included {
+ return false
+ }
+ }
+
+ for _, topic := range self.topics {
+ if !types.BloomLookup(block.Bloom(), topic) {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/core/filter_test.go b/core/filter_test.go
new file mode 100644
index 000000000..9a8bc9592
--- /dev/null
+++ b/core/filter_test.go
@@ -0,0 +1 @@
+package core
diff --git a/core/genesis.go b/core/genesis.go
new file mode 100644
index 000000000..decffc541
--- /dev/null
+++ b/core/genesis.go
@@ -0,0 +1,70 @@
+package core
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "os"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+/*
+ * This is the special genesis block.
+ */
+
+var ZeroHash256 = make([]byte, 32)
+var ZeroHash160 = make([]byte, 20)
+var ZeroHash512 = make([]byte, 64)
+var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
+var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
+
+func GenesisBlock(db ethutil.Database) *types.Block {
+ genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "")
+ genesis.Header().Number = ethutil.Big0
+ genesis.Header().GasLimit = big.NewInt(1000000)
+ genesis.Header().GasUsed = ethutil.Big0
+ genesis.Header().Time = 0
+ genesis.Td = ethutil.Big0
+
+ genesis.SetUncles([]*types.Header{})
+ genesis.SetTransactions(types.Transactions{})
+ genesis.SetReceipts(types.Receipts{})
+
+ var accounts map[string]struct{ Balance string }
+ err := json.Unmarshal(genesisData, &accounts)
+ if err != nil {
+ fmt.Println("enable to decode genesis json data:", err)
+ os.Exit(1)
+ }
+
+ statedb := state.New(genesis.Root(), db)
+ for addr, account := range accounts {
+ codedAddr := ethutil.Hex2Bytes(addr)
+ accountState := statedb.GetAccount(codedAddr)
+ accountState.SetBalance(ethutil.Big(account.Balance))
+ statedb.UpdateStateObject(accountState)
+ }
+ statedb.Sync()
+ genesis.Header().Root = statedb.Root()
+
+ return genesis
+}
+
+var genesisData = []byte(`{
+ "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"},
+ "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"},
+ "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"},
+ "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"}
+}`)
diff --git a/core/helper_test.go b/core/helper_test.go
new file mode 100644
index 000000000..473576e3f
--- /dev/null
+++ b/core/helper_test.go
@@ -0,0 +1,84 @@
+package core
+
+import (
+ "container/list"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+// Implement our EthTest Manager
+type TestManager struct {
+ // stateManager *StateManager
+ eventMux *event.TypeMux
+
+ db ethutil.Database
+ txPool *TxPool
+ blockChain *ChainManager
+ Blocks []*types.Block
+}
+
+func (s *TestManager) IsListening() bool {
+ return false
+}
+
+func (s *TestManager) IsMining() bool {
+ return false
+}
+
+func (s *TestManager) PeerCount() int {
+ return 0
+}
+
+func (s *TestManager) Peers() *list.List {
+ return list.New()
+}
+
+func (s *TestManager) ChainManager() *ChainManager {
+ return s.blockChain
+}
+
+func (tm *TestManager) TxPool() *TxPool {
+ return tm.txPool
+}
+
+// func (tm *TestManager) StateManager() *StateManager {
+// return tm.stateManager
+// }
+
+func (tm *TestManager) EventMux() *event.TypeMux {
+ return tm.eventMux
+}
+func (tm *TestManager) KeyManager() *crypto.KeyManager {
+ return nil
+}
+
+func (tm *TestManager) Db() ethutil.Database {
+ return tm.db
+}
+
+func NewTestManager() *TestManager {
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "ETH")
+
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ fmt.Println("Could not create mem-db, failing")
+ return nil
+ }
+
+ testManager := &TestManager{}
+ testManager.eventMux = new(event.TypeMux)
+ testManager.db = db
+ // testManager.txPool = NewTxPool(testManager)
+ // testManager.blockChain = NewChainManager(testManager)
+ // testManager.stateManager = NewStateManager(testManager)
+
+ // Start the tx pool
+ testManager.txPool.Start()
+
+ return testManager
+}
diff --git a/core/manager.go b/core/manager.go
new file mode 100644
index 000000000..bb039d063
--- /dev/null
+++ b/core/manager.go
@@ -0,0 +1,20 @@
+package core
+
+import (
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/p2p"
+)
+
+type Backend interface {
+ BlockProcessor() *BlockProcessor
+ ChainManager() *ChainManager
+ TxPool() *TxPool
+ PeerCount() int
+ IsListening() bool
+ Peers() []*p2p.Peer
+ KeyManager() *crypto.KeyManager
+ Db() ethutil.Database
+ EventMux() *event.TypeMux
+}
diff --git a/core/state_transition.go b/core/state_transition.go
new file mode 100644
index 000000000..8626504f9
--- /dev/null
+++ b/core/state_transition.go
@@ -0,0 +1,274 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+const tryJit = false
+
+var (
+ GasTx = big.NewInt(21000)
+ GasTxNonZeroByte = big.NewInt(37)
+ GasTxZeroByte = big.NewInt(2)
+)
+
+/*
+ * The State transitioning model
+ *
+ * A state transition is a change made when a transaction is applied to the current world state
+ * The state transitioning model does all all the necessary work to work out a valid new state root.
+ * 1) Nonce handling
+ * 2) Pre pay / buy gas of the coinbase (miner)
+ * 3) Create a new state object if the recipient is \0*32
+ * 4) Value transfer
+ * == If contract creation ==
+ * 4a) Attempt to run transaction data
+ * 4b) If valid, use result as code for the new state object
+ * == end ==
+ * 5) Run Script section
+ * 6) Derive new state root
+ */
+type StateTransition struct {
+ coinbase []byte
+ msg Message
+ gas, gasPrice *big.Int
+ initialGas *big.Int
+ value *big.Int
+ data []byte
+ state *state.StateDB
+
+ cb, rec, sen *state.StateObject
+
+ env vm.Environment
+}
+
+type Message interface {
+ Hash() []byte
+
+ From() []byte
+ To() []byte
+
+ GasPrice() *big.Int
+ Gas() *big.Int
+ Value() *big.Int
+
+ Nonce() uint64
+ Data() []byte
+}
+
+func AddressFromMessage(msg Message) []byte {
+ // Generate a new address
+ return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:]
+}
+
+func MessageCreatesContract(msg Message) bool {
+ return len(msg.To()) == 0
+}
+
+func MessageGasValue(msg Message) *big.Int {
+ return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
+}
+
+func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition {
+ return &StateTransition{
+ coinbase: coinbase.Address(),
+ env: env,
+ msg: msg,
+ gas: new(big.Int),
+ gasPrice: new(big.Int).Set(msg.GasPrice()),
+ initialGas: new(big.Int),
+ value: msg.Value(),
+ data: msg.Data(),
+ state: env.State(),
+ cb: coinbase,
+ }
+}
+
+func (self *StateTransition) Coinbase() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.coinbase)
+}
+func (self *StateTransition) From() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.msg.From())
+}
+func (self *StateTransition) To() *state.StateObject {
+ if self.msg != nil && MessageCreatesContract(self.msg) {
+ return nil
+ }
+ return self.state.GetOrNewStateObject(self.msg.To())
+}
+
+func (self *StateTransition) UseGas(amount *big.Int) error {
+ if self.gas.Cmp(amount) < 0 {
+ return OutOfGasError()
+ }
+ self.gas.Sub(self.gas, amount)
+
+ return nil
+}
+
+func (self *StateTransition) AddGas(amount *big.Int) {
+ self.gas.Add(self.gas, amount)
+}
+
+func (self *StateTransition) BuyGas() error {
+ var err error
+
+ sender := self.From()
+ if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
+ return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance())
+ }
+
+ coinbase := self.Coinbase()
+ err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice())
+ if err != nil {
+ return err
+ }
+
+ self.AddGas(self.msg.Gas())
+ self.initialGas.Set(self.msg.Gas())
+ sender.SubBalance(MessageGasValue(self.msg))
+
+ return nil
+}
+
+func (self *StateTransition) preCheck() (err error) {
+ var (
+ msg = self.msg
+ sender = self.From()
+ )
+
+ // Make sure this transaction's nonce is correct
+ if sender.Nonce() != msg.Nonce() {
+ return NonceError(msg.Nonce(), sender.Nonce())
+ }
+
+ // Pre-pay gas / Buy gas of the coinbase account
+ if err = self.BuyGas(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (self *StateTransition) TransitionState() (ret []byte, err error) {
+ statelogger.Debugf("(~) %x\n", self.msg.Hash())
+
+ // XXX Transactions after this point are considered valid.
+ if err = self.preCheck(); err != nil {
+ return
+ }
+
+ var (
+ msg = self.msg
+ sender = self.From()
+ )
+
+ defer self.RefundGas()
+
+ // Increment the nonce for the next transaction
+ self.state.SetNonce(sender.Address(), sender.Nonce()+1)
+ //sender.Nonce += 1
+
+ // Transaction gas
+ if err = self.UseGas(GasTx); err != nil {
+ return
+ }
+
+ // Pay data gas
+ var dgas int64
+ for _, byt := range self.data {
+ if byt != 0 {
+ dgas += GasTxNonZeroByte.Int64()
+ } else {
+ dgas += GasTxZeroByte.Int64()
+ }
+ }
+ if err = self.UseGas(big.NewInt(dgas)); err != nil {
+ return
+ }
+
+ //stateCopy := self.env.State().Copy()
+ vmenv := self.env
+ var ref vm.ContextRef
+ if MessageCreatesContract(msg) {
+ contract := MakeContract(msg, self.state)
+ ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ if err == nil {
+ dataGas := big.NewInt(int64(len(ret)))
+ dataGas.Mul(dataGas, vm.GasCreateByte)
+ if err := self.UseGas(dataGas); err == nil {
+ ref.SetCode(ret)
+ }
+ }
+
+ /*
+ if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
+ statelogger.Infof("CREATE: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
+ // re-run using the JIT (validation for the JIT)
+ goodState := vmenv.State().Copy()
+ vmenv.state = stateCopy
+ vmenv.SetVmType(vm.JitVmTy)
+ vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
+ self.state.Set(goodState)
+ }
+ */
+ } else {
+ ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+
+ /*
+ if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
+ statelogger.Infof("CALL: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
+ // re-run using the JIT (validation for the JIT)
+ goodState := vmenv.State().Copy()
+ vmenv.state = stateCopy
+ vmenv.SetVmType(vm.JitVmTy)
+ vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
+ self.state.Set(goodState)
+ }
+ */
+ }
+
+ if err != nil {
+ self.UseGas(self.gas)
+ }
+
+ return
+}
+
+// Converts an transaction in to a state object
+func MakeContract(msg Message, state *state.StateDB) *state.StateObject {
+ addr := AddressFromMessage(msg)
+
+ contract := state.GetOrNewStateObject(addr)
+ contract.SetInitCode(msg.Data())
+
+ return contract
+}
+
+func (self *StateTransition) RefundGas() {
+ coinbase, sender := self.Coinbase(), self.From()
+ // Return remaining gas
+ remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
+ sender.AddBalance(remaining)
+
+ uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
+ for addr, ref := range self.state.Refunds() {
+ refund := ethutil.BigMin(uhalf, ref)
+ self.gas.Add(self.gas, refund)
+ self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
+ }
+
+ coinbase.RefundGas(self.gas, self.msg.GasPrice())
+}
+
+func (self *StateTransition) GasUsed() *big.Int {
+ return new(big.Int).Sub(self.initialGas, self.gas)
+}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
new file mode 100644
index 000000000..050cff3d8
--- /dev/null
+++ b/core/transaction_pool.go
@@ -0,0 +1,201 @@
+package core
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/logger"
+)
+
+var (
+ txplogger = logger.NewLogger("TXP")
+
+ ErrInvalidSender = errors.New("Invalid sender")
+)
+
+const txPoolQueueSize = 50
+
+type TxPoolHook chan *types.Transaction
+type TxMsg struct {
+ Tx *types.Transaction
+}
+
+const (
+ minGasPrice = 1000000
+)
+
+type TxProcessor interface {
+ ProcessTransaction(tx *types.Transaction)
+}
+
+// The tx pool a thread safe transaction pool handler. In order to
+// guarantee a non blocking pool we use a queue channel which can be
+// independently read without needing access to the actual pool.
+type TxPool struct {
+ mu sync.RWMutex
+ // Queueing channel for reading and writing incoming
+ // transactions to
+ queueChan chan *types.Transaction
+ // Quiting channel
+ quit chan bool
+ // The actual pool
+ //pool *list.List
+ txs map[string]*types.Transaction
+
+ SecondaryProcessor TxProcessor
+
+ subscribers []chan TxMsg
+
+ eventMux *event.TypeMux
+}
+
+func NewTxPool(eventMux *event.TypeMux) *TxPool {
+ return &TxPool{
+ txs: make(map[string]*types.Transaction),
+ queueChan: make(chan *types.Transaction, txPoolQueueSize),
+ quit: make(chan bool),
+ eventMux: eventMux,
+ }
+}
+
+func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
+ if len(tx.To()) != 0 && len(tx.To()) != 20 {
+ return fmt.Errorf("Invalid recipient. len = %d", len(tx.To()))
+ }
+
+ // Validate curve param
+ v, _, _ := tx.Curve()
+ if v > 28 || v < 27 {
+ return fmt.Errorf("tx.v != (28 || 27) => %v", v)
+ }
+
+ // Validate sender address
+ senderAddr := tx.From()
+ if senderAddr == nil || len(senderAddr) != 20 {
+ return ErrInvalidSender
+ }
+
+ /* XXX this kind of validation needs to happen elsewhere in the gui when sending txs.
+ Other clients should do their own validation. Value transfer could throw error
+ but doesn't necessarily invalidate the tx. Gas can still be payed for and miner
+ can still be rewarded for their inclusion and processing.
+ sender := pool.stateQuery.GetAccount(senderAddr)
+ totAmount := new(big.Int).Set(tx.Value())
+ // Make sure there's enough in the sender's account. Having insufficient
+ // funds won't invalidate this transaction but simple ignores it.
+ if sender.Balance().Cmp(totAmount) < 0 {
+ return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
+ }
+ */
+
+ return nil
+}
+
+func (self *TxPool) addTx(tx *types.Transaction) {
+ self.txs[string(tx.Hash())] = tx
+}
+
+func (self *TxPool) add(tx *types.Transaction) error {
+ if self.txs[string(tx.Hash())] != nil {
+ return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4])
+ }
+
+ err := self.ValidateTransaction(tx)
+ if err != nil {
+ return err
+ }
+
+ self.addTx(tx)
+
+ var to string
+ if len(tx.To()) > 0 {
+ to = ethutil.Bytes2Hex(tx.To()[:4])
+ } else {
+ to = "[NEW_CONTRACT]"
+ }
+
+ txplogger.Debugf("(t) %x => %s (%v) %x\n", tx.From()[:4], to, tx.Value, tx.Hash())
+
+ // Notify the subscribers
+ go self.eventMux.Post(TxPreEvent{tx})
+
+ return nil
+}
+
+func (self *TxPool) Size() int {
+ return len(self.txs)
+}
+
+func (self *TxPool) Add(tx *types.Transaction) error {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+ return self.add(tx)
+}
+func (self *TxPool) AddTransactions(txs []*types.Transaction) {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+
+ for _, tx := range txs {
+ if err := self.add(tx); err != nil {
+ txplogger.Debugln(err)
+ } else {
+ txplogger.Debugf("tx %x\n", tx.Hash()[0:4])
+ }
+ }
+}
+
+func (self *TxPool) GetTransactions() (txs types.Transactions) {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ txs = make(types.Transactions, self.Size())
+ i := 0
+ for _, tx := range self.txs {
+ txs[i] = tx
+ i++
+ }
+
+ return
+}
+
+func (pool *TxPool) RemoveInvalid(query StateQuery) {
+ pool.mu.Lock()
+
+ var removedTxs types.Transactions
+ for _, tx := range pool.txs {
+ sender := query.GetAccount(tx.From())
+ err := pool.ValidateTransaction(tx)
+ if err != nil || sender.Nonce() >= tx.Nonce() {
+ removedTxs = append(removedTxs, tx)
+ }
+ }
+ pool.mu.Unlock()
+
+ pool.RemoveSet(removedTxs)
+}
+
+func (self *TxPool) RemoveSet(txs types.Transactions) {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+
+ for _, tx := range txs {
+ delete(self.txs, string(tx.Hash()))
+ }
+}
+
+func (pool *TxPool) Flush() {
+ pool.txs = make(map[string]*types.Transaction)
+}
+
+func (pool *TxPool) Start() {
+}
+
+func (pool *TxPool) Stop() {
+ pool.Flush()
+
+ txplogger.Infoln("Stopped")
+}
diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go
new file mode 100644
index 000000000..b2d981f01
--- /dev/null
+++ b/core/transaction_pool_test.go
@@ -0,0 +1,97 @@
+package core
+
+import (
+ "crypto/ecdsa"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+// State query interface
+type stateQuery struct{ db ethutil.Database }
+
+func SQ() stateQuery {
+ db, _ := ethdb.NewMemDatabase()
+ return stateQuery{db: db}
+}
+
+func (self stateQuery) GetAccount(addr []byte) *state.StateObject {
+ return state.NewStateObject(addr, self.db)
+}
+
+func transaction() *types.Transaction {
+ return types.NewTransactionMessage(make([]byte, 20), ethutil.Big0, ethutil.Big0, ethutil.Big0, nil)
+}
+
+func setup() (*TxPool, *ecdsa.PrivateKey) {
+ var m event.TypeMux
+ key, _ := crypto.GenerateKey()
+ return NewTxPool(&m), key
+}
+
+func TestTxAdding(t *testing.T) {
+ pool, key := setup()
+ tx1 := transaction()
+ tx1.SignECDSA(key)
+ err := pool.Add(tx1)
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = pool.Add(tx1)
+ if err == nil {
+ t.Error("added tx twice")
+ }
+}
+
+func TestAddInvalidTx(t *testing.T) {
+ pool, _ := setup()
+ tx1 := transaction()
+ err := pool.Add(tx1)
+ if err == nil {
+ t.Error("expected error")
+ }
+}
+
+func TestRemoveSet(t *testing.T) {
+ pool, _ := setup()
+ tx1 := transaction()
+ pool.addTx(tx1)
+ pool.RemoveSet(types.Transactions{tx1})
+ if pool.Size() > 0 {
+ t.Error("expected pool size to be 0")
+ }
+}
+
+func TestRemoveInvalid(t *testing.T) {
+ pool, key := setup()
+ tx1 := transaction()
+ pool.addTx(tx1)
+ pool.RemoveInvalid(SQ())
+ if pool.Size() > 0 {
+ t.Error("expected pool size to be 0")
+ }
+
+ tx1.SetNonce(1)
+ tx1.SignECDSA(key)
+ pool.addTx(tx1)
+ pool.RemoveInvalid(SQ())
+ if pool.Size() != 1 {
+ t.Error("expected pool size to be 1, is", pool.Size())
+ }
+}
+
+func TestInvalidSender(t *testing.T) {
+ pool, _ := setup()
+ tx := new(types.Transaction)
+ tx.V = 28
+ err := pool.ValidateTransaction(tx)
+ if err != ErrInvalidSender {
+ t.Error("expected %v, got %v", ErrInvalidSender, err)
+ }
+}
diff --git a/core/types/block.go b/core/types/block.go
new file mode 100644
index 000000000..d57de1311
--- /dev/null
+++ b/core/types/block.go
@@ -0,0 +1,279 @@
+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 }
diff --git a/core/types/block_test.go b/core/types/block_test.go
new file mode 100644
index 000000000..ab1254f4c
--- /dev/null
+++ b/core/types/block_test.go
@@ -0,0 +1 @@
+package types
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
new file mode 100644
index 000000000..578265a34
--- /dev/null
+++ b/core/types/bloom9.go
@@ -0,0 +1,55 @@
+package types
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+func CreateBloom(receipts Receipts) []byte {
+ bin := new(big.Int)
+ for _, receipt := range receipts {
+ bin.Or(bin, LogsBloom(receipt.logs))
+ }
+
+ return ethutil.LeftPadBytes(bin.Bytes(), 256)
+}
+
+func LogsBloom(logs state.Logs) *big.Int {
+ bin := new(big.Int)
+ for _, log := range logs {
+ data := make([][]byte, len(log.Topics())+1)
+ data[0] = log.Address()
+
+ for i, topic := range log.Topics() {
+ data[i+1] = topic
+ }
+
+ for _, b := range data {
+ bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes()))
+ }
+ }
+
+ return bin
+}
+
+func bloom9(b []byte) *big.Int {
+ r := new(big.Int)
+
+ for i := 0; i < 16; i += 2 {
+ t := big.NewInt(1)
+ b := uint(b[i+1]) + 1024*(uint(b[i])&1)
+ r.Or(r, t.Lsh(t, b))
+ }
+
+ return r
+}
+
+func BloomLookup(bin, topic []byte) bool {
+ bloom := ethutil.BigD(bin)
+ cmp := bloom9(crypto.Sha3(topic))
+
+ return bloom.And(bloom, cmp).Cmp(cmp) == 0
+}
diff --git a/core/types/bloom9_test.go b/core/types/bloom9_test.go
new file mode 100644
index 000000000..74e00cac6
--- /dev/null
+++ b/core/types/bloom9_test.go
@@ -0,0 +1,31 @@
+package types
+
+/*
+import (
+ "testing"
+
+ "github.com/ethereum/go-ethereum/state"
+)
+
+func TestBloom9(t *testing.T) {
+ testCase := []byte("testtest")
+ bin := LogsBloom([]state.Log{
+ {testCase, [][]byte{[]byte("hellohello")}, nil},
+ }).Bytes()
+ res := BloomLookup(bin, testCase)
+
+ if !res {
+ t.Errorf("Bloom lookup failed")
+ }
+}
+
+
+func TestAddress(t *testing.T) {
+ block := &Block{}
+ block.Coinbase = ethutil.Hex2Bytes("22341ae42d6dd7384bc8584e50419ea3ac75b83f")
+ fmt.Printf("%x\n", crypto.Sha3(block.Coinbase))
+
+ bin := CreateBloom(block)
+ fmt.Printf("bin = %x\n", ethutil.LeftPadBytes(bin, 64))
+}
+*/
diff --git a/core/types/common.go b/core/types/common.go
new file mode 100644
index 000000000..795374959
--- /dev/null
+++ b/core/types/common.go
@@ -0,0 +1,7 @@
+package types
+
+import "math/big"
+
+type BlockProcessor interface {
+ Process(*Block) (*big.Int, error)
+}
diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go
new file mode 100644
index 000000000..b2c442210
--- /dev/null
+++ b/core/types/derive_sha.go
@@ -0,0 +1,22 @@
+package types
+
+import (
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/trie"
+)
+
+type DerivableList interface {
+ Len() int
+ GetRlp(i int) []byte
+}
+
+func DeriveSha(list DerivableList) []byte {
+ db, _ := ethdb.NewMemDatabase()
+ trie := trie.New(nil, db)
+ for i := 0; i < list.Len(); i++ {
+ trie.Update(ethutil.Encode(i), list.GetRlp(i))
+ }
+
+ return trie.Root()
+}
diff --git a/core/types/receipt.go b/core/types/receipt.go
new file mode 100644
index 000000000..49e68e233
--- /dev/null
+++ b/core/types/receipt.go
@@ -0,0 +1,81 @@
+package types
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+type Receipt struct {
+ PostState []byte
+ CumulativeGasUsed *big.Int
+ Bloom []byte
+ logs state.Logs
+}
+
+func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt {
+ return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumalativeGasUsed)}
+}
+
+func NewRecieptFromValue(val *ethutil.Value) *Receipt {
+ r := &Receipt{}
+ r.RlpValueDecode(val)
+
+ return r
+}
+
+func (self *Receipt) SetLogs(logs state.Logs) {
+ self.logs = logs
+}
+
+func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) {
+ self.PostState = decoder.Get(0).Bytes()
+ self.CumulativeGasUsed = decoder.Get(1).BigInt()
+ self.Bloom = decoder.Get(2).Bytes()
+
+ it := decoder.Get(3).NewIterator()
+ for it.Next() {
+ self.logs = append(self.logs, state.NewLogFromValue(it.Value()))
+ }
+}
+
+func (self *Receipt) RlpData() interface{} {
+ return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()}
+}
+
+func (self *Receipt) RlpEncode() []byte {
+ return ethutil.Encode(self.RlpData())
+}
+
+func (self *Receipt) Cmp(other *Receipt) bool {
+ if bytes.Compare(self.PostState, other.PostState) != 0 {
+ return false
+ }
+
+ return true
+}
+
+func (self *Receipt) String() string {
+ return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs)
+}
+
+type Receipts []*Receipt
+
+func (self Receipts) RlpData() interface{} {
+ data := make([]interface{}, len(self))
+ for i, receipt := range self {
+ data[i] = receipt.RlpData()
+ }
+
+ return data
+}
+
+func (self Receipts) RlpEncode() []byte {
+ return ethutil.Encode(self.RlpData())
+}
+
+func (self Receipts) Len() int { return len(self) }
+func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) }
diff --git a/core/types/transaction.go b/core/types/transaction.go
new file mode 100644
index 000000000..7a1d6104e
--- /dev/null
+++ b/core/types/transaction.go
@@ -0,0 +1,226 @@
+package types
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+func IsContractAddr(addr []byte) bool {
+ return len(addr) == 0
+}
+
+type Transaction struct {
+ AccountNonce uint64
+ Price *big.Int
+ GasLimit *big.Int
+ Recipient []byte
+ Amount *big.Int
+ Payload []byte
+ V uint64
+ R, S []byte
+}
+
+func NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction {
+ return NewTransactionMessage(nil, Amount, gasAmount, price, data)
+}
+
+func NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction {
+ return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data}
+}
+
+func NewTransactionFromBytes(data []byte) *Transaction {
+ tx := &Transaction{}
+ tx.RlpDecode(data)
+
+ return tx
+}
+
+func NewTransactionFromAmount(val *ethutil.Value) *Transaction {
+ tx := &Transaction{}
+ tx.RlpValueDecode(val)
+
+ return tx
+}
+
+func (tx *Transaction) Hash() []byte {
+ data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
+
+ return crypto.Sha3(ethutil.Encode(data))
+}
+
+func (self *Transaction) Data() []byte {
+ return self.Payload
+}
+
+func (self *Transaction) Gas() *big.Int {
+ return self.GasLimit
+}
+
+func (self *Transaction) GasPrice() *big.Int {
+ return self.Price
+}
+
+func (self *Transaction) Value() *big.Int {
+ return self.Amount
+}
+
+func (self *Transaction) Nonce() uint64 {
+ return self.AccountNonce
+}
+
+func (self *Transaction) SetNonce(AccountNonce uint64) {
+ self.AccountNonce = AccountNonce
+}
+
+func (self *Transaction) From() []byte {
+ return self.sender()
+}
+
+func (self *Transaction) To() []byte {
+ return self.Recipient
+}
+
+func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
+ v = byte(tx.V)
+ r = ethutil.LeftPadBytes(tx.R, 32)
+ s = ethutil.LeftPadBytes(tx.S, 32)
+
+ return
+}
+
+func (tx *Transaction) Signature(key []byte) []byte {
+ hash := tx.Hash()
+
+ sig, _ := secp256k1.Sign(hash, key)
+
+ return sig
+}
+
+func (tx *Transaction) PublicKey() []byte {
+ hash := tx.Hash()
+
+ v, r, s := tx.Curve()
+
+ sig := append(r, s...)
+ sig = append(sig, v-27)
+
+ //pubkey := crypto.Ecrecover(append(hash, sig...))
+ pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
+
+ return pubkey
+}
+
+func (tx *Transaction) sender() []byte {
+ pubkey := tx.PublicKey()
+
+ // Validate the returned key.
+ // Return nil if public key isn't in full format
+ if len(pubkey) == 0 || pubkey[0] != 4 {
+ return nil
+ }
+
+ return crypto.Sha3(pubkey[1:])[12:]
+}
+
+func (tx *Transaction) Sign(privk []byte) error {
+
+ sig := tx.Signature(privk)
+
+ tx.R = sig[:32]
+ tx.S = sig[32:64]
+ tx.V = uint64(sig[64] + 27)
+
+ return nil
+}
+
+func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error {
+ return tx.Sign(crypto.FromECDSA(key))
+}
+
+func (tx *Transaction) RlpData() interface{} {
+ data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
+
+ return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes())
+}
+
+func (tx *Transaction) RlpEncode() []byte {
+ return ethutil.Encode(tx)
+}
+
+func (tx *Transaction) RlpDecode(data []byte) {
+ rlp.Decode(bytes.NewReader(data), tx)
+}
+
+func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
+ tx.AccountNonce = decoder.Get(0).Uint()
+ tx.Price = decoder.Get(1).BigInt()
+ tx.GasLimit = decoder.Get(2).BigInt()
+ tx.Recipient = decoder.Get(3).Bytes()
+ tx.Amount = decoder.Get(4).BigInt()
+ tx.Payload = decoder.Get(5).Bytes()
+ tx.V = decoder.Get(6).Uint()
+ tx.R = decoder.Get(7).Bytes()
+ tx.S = decoder.Get(8).Bytes()
+}
+
+func (tx *Transaction) String() string {
+ return fmt.Sprintf(`
+ TX(%x)
+ Contract: %v
+ From: %x
+ To: %x
+ Nonce: %v
+ GasPrice: %v
+ GasLimit %v
+ Value: %v
+ Data: 0x%x
+ V: 0x%x
+ R: 0x%x
+ S: 0x%x
+ Hex: %x
+`,
+ tx.Hash(),
+ len(tx.Recipient) == 0,
+ tx.From(),
+ tx.To(),
+ tx.AccountNonce,
+ tx.Price,
+ tx.GasLimit,
+ tx.Amount,
+ tx.Payload,
+ tx.V,
+ tx.R,
+ tx.S,
+ ethutil.Encode(tx),
+ )
+}
+
+// Transaction slice type for basic sorting
+type Transactions []*Transaction
+
+func (self Transactions) RlpData() interface{} {
+ // Marshal the transactions of this block
+ enc := make([]interface{}, len(self))
+ for i, tx := range self {
+ // Cast it to a string (safe)
+ enc[i] = tx.RlpData()
+ }
+
+ return enc
+}
+func (s Transactions) Len() int { return len(s) }
+func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) }
+
+type TxByNonce struct{ Transactions }
+
+func (s TxByNonce) Less(i, j int) bool {
+ return s.Transactions[i].AccountNonce < s.Transactions[j].AccountNonce
+}
diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go
new file mode 100644
index 000000000..ab1254f4c
--- /dev/null
+++ b/core/types/transaction_test.go
@@ -0,0 +1 @@
+package types
diff --git a/core/vm_env.go b/core/vm_env.go
new file mode 100644
index 000000000..c7491bcdc
--- /dev/null
+++ b/core/vm_env.go
@@ -0,0 +1,72 @@
+package core
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+type VMEnv struct {
+ state *state.StateDB
+ block *types.Block
+ msg Message
+ depth int
+ chain *ChainManager
+ typ vm.Type
+}
+
+func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
+ return &VMEnv{
+ chain: chain,
+ state: state,
+ block: block,
+ msg: msg,
+ typ: vm.StdVmTy,
+ }
+}
+
+func (self *VMEnv) Origin() []byte { return self.msg.From() }
+func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
+func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() }
+func (self *VMEnv) Time() int64 { return self.block.Time() }
+func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
+func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
+func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
+func (self *VMEnv) State() *state.StateDB { return self.state }
+func (self *VMEnv) Depth() int { return self.depth }
+func (self *VMEnv) SetDepth(i int) { self.depth = i }
+func (self *VMEnv) VmType() vm.Type { return self.typ }
+func (self *VMEnv) SetVmType(t vm.Type) { self.typ = t }
+func (self *VMEnv) GetHash(n uint64) []byte {
+ if block := self.chain.GetBlockByNumber(n); block != nil {
+ return block.Hash()
+ }
+
+ return nil
+}
+func (self *VMEnv) AddLog(log state.Log) {
+ self.state.AddLog(log)
+}
+func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
+ return vm.Transfer(from, to, amount)
+}
+
+func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution {
+ return NewExecution(self, addr, data, gas, price, value)
+}
+
+func (self *VMEnv) Call(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
+ exe := self.vm(addr, data, gas, price, value)
+ return exe.Call(addr, me)
+}
+func (self *VMEnv) CallCode(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {
+ exe := self.vm(me.Address(), data, gas, price, value)
+ return exe.Call(addr, me)
+}
+
+func (self *VMEnv) Create(me vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
+ exe := self.vm(addr, data, gas, price, value)
+ return exe.Create(me)
+}