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_manager.go414
-rw-r--r--core/chain_manager.go276
-rw-r--r--core/chain_manager_test.go116
-rw-r--r--core/dagger.go245
-rw-r--r--core/dagger_test.go19
-rw-r--r--core/error.go141
-rw-r--r--core/events.go12
-rw-r--r--core/execution.go80
-rw-r--r--core/fees.go7
-rw-r--r--core/filter.go200
-rw-r--r--core/filter_test.go7
-rw-r--r--core/genesis.go52
-rw-r--r--core/helper_test.go93
-rw-r--r--core/state_transition.go198
-rw-r--r--core/transaction_pool.go236
-rw-r--r--core/types/block.go413
-rw-r--r--core/types/bloom9.go56
-rw-r--r--core/types/bloom9_test.go31
-rw-r--r--core/types/common.go11
-rw-r--r--core/types/derive_sha.go20
-rw-r--r--core/types/receipt.go68
-rw-r--r--core/types/transaction.go225
-rw-r--r--core/types/transaction_test.go1
-rw-r--r--core/vm_env.go63
26 files changed, 3046 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_manager.go b/core/block_manager.go
new file mode 100644
index 000000000..f0b78b675
--- /dev/null
+++ b/core/block_manager.go
@@ -0,0 +1,414 @@
+package core
+
+import (
+ "bytes"
+ "container/list"
+ "errors"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/wire"
+)
+
+var statelogger = logger.NewLogger("BLOCK")
+
+type Peer interface {
+ Inbound() bool
+ LastSend() time.Time
+ LastPong() int64
+ Host() []byte
+ Port() uint16
+ Version() string
+ PingTime() string
+ Connected() *int32
+ Caps() *ethutil.Value
+}
+
+type EthManager interface {
+ BlockManager() *BlockManager
+ ChainManager() *ChainManager
+ TxPool() *TxPool
+ Broadcast(msgType wire.MsgType, data []interface{})
+ PeerCount() int
+ IsMining() bool
+ IsListening() bool
+ Peers() *list.List
+ KeyManager() *crypto.KeyManager
+ ClientIdentity() wire.ClientIdentity
+ Db() ethutil.Database
+ EventMux() *event.TypeMux
+}
+
+type BlockManager struct {
+ // 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
+ // The ethereum manager interface
+ eth EthManager
+ // The managed states
+ // Transiently state. The trans state isn't ever saved, validated and
+ // it could be used for setting account nonces without effecting
+ // the main states.
+ transState *state.State
+ // Mining state. The mining state is used purely and solely by the mining
+ // operation.
+ miningState *state.State
+
+ // 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
+}
+
+func NewBlockManager(ethereum EthManager) *BlockManager {
+ sm := &BlockManager{
+ mem: make(map[string]*big.Int),
+ Pow: &EasyPow{},
+ eth: ethereum,
+ bc: ethereum.ChainManager(),
+ }
+ sm.transState = ethereum.ChainManager().CurrentBlock.State().Copy()
+ sm.miningState = ethereum.ChainManager().CurrentBlock.State().Copy()
+
+ return sm
+}
+
+func (self *BlockManager) Start() {
+ statelogger.Debugln("Starting block manager")
+}
+
+func (self *BlockManager) Stop() {
+ statelogger.Debugln("Stopping state manager")
+}
+
+func (sm *BlockManager) CurrentState() *state.State {
+ return sm.eth.ChainManager().CurrentBlock.State()
+}
+
+func (sm *BlockManager) TransState() *state.State {
+ return sm.transState
+}
+
+func (sm *BlockManager) MiningState() *state.State {
+ return sm.miningState
+}
+
+func (sm *BlockManager) NewMiningState() *state.State {
+ sm.miningState = sm.eth.ChainManager().CurrentBlock.State().Copy()
+
+ return sm.miningState
+}
+
+func (sm *BlockManager) ChainManager() *ChainManager {
+ return sm.bc
+}
+
+func (sm *BlockManager) TransitionState(statedb *state.State, parent, block *types.Block) (receipts types.Receipts, err error) {
+ coinbase := statedb.GetOrNewStateObject(block.Coinbase)
+ coinbase.SetGasPool(block.CalcGasLimit(parent))
+
+ // Process the transactions on to current block
+ receipts, _, _, _, err = sm.ProcessTransactions(coinbase, statedb, block, parent, block.Transactions())
+ if err != nil {
+ return nil, err
+ }
+
+ return receipts, nil
+}
+
+func (self *BlockManager) ProcessTransactions(coinbase *state.StateObject, state *state.State, block, parent *types.Block, txs types.Transactions) (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)
+ )
+
+done:
+ for i, tx := range txs {
+ // If we are mining this block and validating we want to set the logs back to 0
+ state.EmptyLogs()
+
+ txGas := new(big.Int).Set(tx.Gas)
+
+ cb := state.GetStateObject(coinbase.Address())
+ st := NewStateTransition(cb, tx, state, block)
+ err = st.TransitionState()
+ if err != nil {
+ statelogger.Infoln(err)
+ switch {
+ case IsNonceErr(err):
+ err = nil // ignore error
+ continue
+ case IsGasLimitErr(err):
+ unhandled = txs[i:]
+
+ break done
+ default:
+ statelogger.Infoln(err)
+ erroneous = append(erroneous, tx)
+ err = nil
+ continue
+ }
+ }
+
+ txGas.Sub(txGas, st.gas)
+ cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice))
+
+ // Update the state with pending changes
+ state.Update(txGas)
+
+ cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
+ receipt := types.NewReceipt(state.Root(), cumulative)
+ receipt.SetLogs(state.Logs())
+ receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+
+ // Notify all subscribers
+ go self.eth.EventMux().Post(TxPostEvent{tx})
+
+ receipts = append(receipts, receipt)
+ handled = append(handled, tx)
+
+ if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
+ state.CreateOutputForDiff()
+ }
+ }
+
+ block.Reward = cumulativeSum
+ block.GasUsed = totalUsedGas
+
+ return receipts, handled, unhandled, erroneous, err
+}
+
+func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) {
+ // Processing a blocks may never happen simultaneously
+ sm.mutex.Lock()
+ defer sm.mutex.Unlock()
+
+ if sm.bc.HasBlock(block.Hash()) {
+ return nil, nil, &KnownBlockError{block.Number, block.Hash()}
+ }
+
+ if !sm.bc.HasBlock(block.PrevHash) {
+ return nil, nil, ParentError(block.PrevHash)
+ }
+ parent := sm.bc.GetBlock(block.PrevHash)
+
+ return sm.ProcessWithParent(block, parent)
+}
+
+func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
+ sm.lastAttemptedBlock = block
+
+ state := parent.State().Copy()
+
+ // Defer the Undo on the Trie. If the block processing happened
+ // we don't want to undo but since undo only happens on dirty
+ // nodes this won't happen because Commit would have been called
+ // before that.
+ defer state.Reset()
+
+ if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
+ fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
+ }
+
+ _, err = sm.TransitionState(state, parent, block)
+ if err != nil {
+ return
+ }
+
+ txSha := types.DeriveSha(block.Transactions())
+ if bytes.Compare(txSha, block.TxSha) != 0 {
+ err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha)
+ return
+ }
+
+ /*
+ receiptSha := types.DeriveSha(receipts)
+ if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ return
+ }
+ */
+
+ // Block validation
+ if err = sm.ValidateBlock(block, parent); err != nil {
+ return
+ }
+
+ if err = sm.AccumelateRewards(state, block, parent); err != nil {
+ return
+ }
+
+ /*
+ //block.receipts = receipts // although this isn't necessary it be in the future
+ rbloom := types.CreateBloom(receipts)
+ if bytes.Compare(rbloom, block.LogsBloom) != 0 {
+ err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
+ return
+ }
+ */
+
+ state.Update(ethutil.Big0)
+
+ if !block.State().Cmp(state) {
+ err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())
+ return
+ }
+
+ // Calculate the new total difficulty and sync back to the db
+ if td, ok := sm.CalculateTD(block); ok {
+ // Sync the current block's state to the database and cancelling out the deferred Undo
+ state.Sync()
+
+ messages := state.Manifest().Messages
+ state.Manifest().Reset()
+
+ chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
+
+ sm.transState = state.Copy()
+
+ sm.eth.TxPool().RemoveSet(block.Transactions())
+
+ return td, messages, nil
+ } else {
+ return nil, nil, errors.New("total diff failed")
+ }
+}
+
+func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
+ 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(sm.bc.TD, uncleDiff)
+ td = td.Add(td, block.Difficulty)
+
+ // The new TD will only be accepted if the new difficulty is
+ // is greater than the previous.
+ if td.Cmp(sm.bc.TD) > 0 {
+ return td, true
+ }
+
+ return nil, false
+}
+
+// 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 *BlockManager) ValidateBlock(block, parent *types.Block) error {
+ expd := CalcDifficulty(block, parent)
+ if expd.Cmp(block.Difficulty) < 0 {
+ return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
+ }
+
+ diff := block.Time - parent.Time
+ if diff < 0 {
+ return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time)
+ }
+
+ /* XXX
+ // New blocks must be within the 15 minute range of the last block.
+ if diff > int64(15*time.Minute) {
+ return ValidationError("Block is too far in the future of last block (> 15 minutes)")
+ }
+ */
+
+ // Verify the nonce of the block. Return an error if it's not valid
+ if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) {
+ return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
+ }
+
+ return nil
+}
+
+func (sm *BlockManager) AccumelateRewards(statedb *state.State, block, parent *types.Block) error {
+ reward := new(big.Int).Set(BlockReward)
+
+ knownUncles := ethutil.Set(parent.Uncles)
+ nonces := ethutil.NewSet(block.Nonce)
+ for _, uncle := range block.Uncles {
+ if nonces.Include(uncle.Nonce) {
+ // Error not unique
+ return UncleError("Uncle not unique")
+ }
+
+ uncleParent := sm.bc.GetBlock(uncle.PrevHash)
+ if uncleParent == nil {
+ return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4]))
+ }
+
+ if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {
+ return UncleError("Uncle too old")
+ }
+
+ if knownUncles.Include(uncle.Hash()) {
+ return UncleError("Uncle in chain")
+ }
+
+ nonces.Insert(uncle.Nonce)
+
+ r := new(big.Int)
+ r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
+
+ uncleAccount := statedb.GetAccount(uncle.Coinbase)
+ uncleAccount.AddAmount(r)
+
+ reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
+ }
+
+ // Get the account associated with the coinbase
+ account := statedb.GetAccount(block.Coinbase)
+ // Reward amount of ether to the coinbase address
+ account.AddAmount(reward)
+
+ statedb.Manifest().AddMessage(&state.Message{
+ To: block.Coinbase, From: block.Coinbase,
+ Input: nil,
+ Origin: nil,
+ Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
+ Value: new(big.Int).Add(reward, block.Reward),
+ })
+
+ return nil
+}
+
+func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) {
+ if !sm.bc.HasBlock(block.PrevHash) {
+ return nil, ParentError(block.PrevHash)
+ }
+
+ sm.lastAttemptedBlock = block
+
+ var (
+ parent = sm.bc.GetBlock(block.PrevHash)
+ state = parent.State().Copy()
+ )
+
+ defer state.Reset()
+
+ sm.TransitionState(state, parent, block)
+ sm.AccumelateRewards(state, block, parent)
+
+ return state.Manifest().Messages, nil
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
new file mode 100644
index 000000000..7acd171ec
--- /dev/null
+++ b/core/chain_manager.go
@@ -0,0 +1,276 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "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 chainlogger = logger.NewLogger("CHAIN")
+
+func AddTestNetFunds(block *types.Block) {
+ for _, addr := range []string{
+ "51ba59315b3a95761d0863b05ccc7a7f54703d99",
+ "e4157b34ea9615cfbde6b4fda419828124b70c78",
+ "b9c015918bdaba24b4ff057a92a3873d6eb201be",
+ "6c386a4b26f73c802f34673f7248bb118f97424a",
+ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb",
+ "e6716f9544a56c530d868e4bfbacb172315bdead",
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
+ } {
+ codedAddr := ethutil.Hex2Bytes(addr)
+ account := block.State().GetAccount(codedAddr)
+ account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
+ block.State().UpdateStateObject(account)
+ }
+}
+
+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+5 {
+ diff.Sub(parent.Difficulty, adjust)
+ } else {
+ diff.Add(parent.Difficulty, adjust)
+ }
+
+ return diff
+}
+
+type ChainManager struct {
+ //eth EthManager
+ processor types.BlockProcessor
+ eventMux *event.TypeMux
+ genesisBlock *types.Block
+ // Last known total difficulty
+ TD *big.Int
+
+ LastBlockNumber uint64
+
+ CurrentBlock *types.Block
+ LastBlockHash []byte
+}
+
+func NewChainManager(mux *event.TypeMux) *ChainManager {
+ bc := &ChainManager{}
+ bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis))
+ bc.eventMux = mux
+
+ bc.setLastBlock()
+
+ return bc
+}
+
+func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
+ self.processor = proc
+}
+
+func (bc *ChainManager) setLastBlock() {
+ data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
+ if len(data) != 0 {
+ // Prep genesis
+ AddTestNetFunds(bc.genesisBlock)
+
+ block := types.NewBlockFromBytes(data)
+ bc.CurrentBlock = block
+ bc.LastBlockHash = block.Hash()
+ bc.LastBlockNumber = block.Number.Uint64()
+
+ // Set the last know difficulty (might be 0x0 as initial value, Genesis)
+ bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
+ } else {
+ bc.Reset()
+ }
+
+ chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash())
+}
+
+// Block creation & chain handling
+func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
+ var root interface{}
+ hash := ZeroHash256
+
+ if bc.CurrentBlock != nil {
+ root = bc.CurrentBlock.Root()
+ hash = bc.LastBlockHash
+ }
+
+ block := types.CreateBlock(
+ root,
+ hash,
+ coinbase,
+ ethutil.BigPow(2, 32),
+ nil,
+ "")
+
+ parent := bc.CurrentBlock
+ if parent != nil {
+ block.Difficulty = CalcDifficulty(block, parent)
+ block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
+ block.GasLimit = block.CalcGasLimit(bc.CurrentBlock)
+
+ }
+
+ return block
+}
+
+func (bc *ChainManager) Reset() {
+ AddTestNetFunds(bc.genesisBlock)
+
+ bc.genesisBlock.Trie().Sync()
+ // Prepare the genesis block
+ bc.add(bc.genesisBlock)
+ bc.CurrentBlock = bc.genesisBlock
+
+ bc.SetTotalDifficulty(ethutil.Big("0"))
+
+ // Set the last know difficulty (might be 0x0 as initial value, Genesis)
+ bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
+}
+
+// Add a block to the chain and record addition information
+func (bc *ChainManager) add(block *types.Block) {
+ bc.writeBlockInfo(block)
+
+ bc.CurrentBlock = block
+ bc.LastBlockHash = block.Hash()
+
+ encodedBlock := block.RlpEncode()
+ ethutil.Config.Db.Put(block.Hash(), encodedBlock)
+ ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
+
+ //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
+}
+
+// Accessors
+func (bc *ChainManager) Genesis() *types.Block {
+ return bc.genesisBlock
+}
+
+// Block fetching methods
+func (bc *ChainManager) HasBlock(hash []byte) bool {
+ data, _ := ethutil.Config.Db.Get(hash)
+ return len(data) != 0
+}
+
+func (self *ChainManager) GetChainHashesFromHash(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++ {
+
+ chain = append(chain, block.Hash())
+
+ if block.Number.Cmp(ethutil.Big0) <= 0 {
+ break
+ }
+
+ block = self.GetBlock(block.PrevHash)
+ }
+
+ return
+}
+
+func (self *ChainManager) GetBlock(hash []byte) *types.Block {
+ data, _ := ethutil.Config.Db.Get(hash)
+ if len(data) == 0 {
+ return nil
+ }
+
+ return types.NewBlockFromBytes(data)
+}
+
+func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
+ block := self.CurrentBlock
+ for ; block != nil; block = self.GetBlock(block.PrevHash) {
+ if block.Number.Uint64() == num {
+ break
+ }
+ }
+
+ if block != nil && block.Number.Uint64() == 0 && num != 0 {
+ return nil
+ }
+
+ return block
+}
+
+func (bc *ChainManager) SetTotalDifficulty(td *big.Int) {
+ ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
+ bc.TD = td
+}
+
+func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
+ parent := self.GetBlock(block.PrevHash)
+ if parent == nil {
+ return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash)
+ }
+
+ parentTd := parent.BlockInfo().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.Difficulty)
+
+ return td, nil
+}
+
+func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo {
+ bi := types.BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+// Unexported method for writing extra non-essential block info to the db
+func (bc *ChainManager) writeBlockInfo(block *types.Block) {
+ bc.LastBlockNumber++
+ bi := types.BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD}
+
+ // For now we use the block hash with the words "info" appended as key
+ ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode())
+}
+
+func (bc *ChainManager) Stop() {
+ if bc.CurrentBlock != nil {
+ chainlogger.Infoln("Stopped")
+ }
+}
+
+func (self *ChainManager) InsertChain(chain types.Blocks) error {
+ for _, block := range chain {
+ td, messages, err := self.processor.Process(block)
+ if err != nil {
+ if IsKnownBlockErr(err) {
+ continue
+ }
+
+ chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4])
+ chainlogger.Infoln(block)
+ chainlogger.Infoln(err)
+ return err
+ }
+
+ self.add(block)
+ self.SetTotalDifficulty(td)
+ self.eventMux.Post(NewBlockEvent{block})
+ self.eventMux.Post(messages)
+ }
+
+ return nil
+}
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
new file mode 100644
index 000000000..51e70fb12
--- /dev/null
+++ b/core/chain_manager_test.go
@@ -0,0 +1,116 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/chain/types"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+var TD *big.Int
+
+func init() {
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
+ ethutil.Config.Db, _ = ethdb.NewMemDatabase()
+}
+
+type fakeproc struct {
+}
+
+func (self fakeproc) ProcessWithParent(a, b *types.Block) (*big.Int, state.Messages, error) {
+ TD = new(big.Int).Add(TD, big.NewInt(1))
+ return TD, nil, nil
+}
+
+func makechain(cman *ChainManager, max int) *BlockChain {
+ blocks := make(types.Blocks, max)
+ for i := 0; i < max; i++ {
+ addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
+ block := cman.NewBlock(addr)
+ if i != 0 {
+ cman.CurrentBlock = blocks[i-1]
+ }
+ blocks[i] = block
+ }
+ return NewChain(blocks)
+}
+
+func TestLongerFork(t *testing.T) {
+ cman := NewChainManager()
+ cman.SetProcessor(fakeproc{})
+
+ TD = big.NewInt(1)
+ chainA := makechain(cman, 5)
+
+ TD = big.NewInt(1)
+ chainB := makechain(cman, 10)
+
+ td, err := cman.TestChain(chainA)
+ if err != nil {
+ t.Error("unable to create new TD from chainA:", err)
+ }
+ cman.TD = td
+
+ _, err = cman.TestChain(chainB)
+ if err != nil {
+ t.Error("expected chainB not to give errors:", err)
+ }
+}
+
+func TestEqualFork(t *testing.T) {
+ cman := NewChainManager()
+ cman.SetProcessor(fakeproc{})
+
+ TD = big.NewInt(1)
+ chainA := makechain(cman, 5)
+
+ TD = big.NewInt(2)
+ chainB := makechain(cman, 5)
+
+ td, err := cman.TestChain(chainA)
+ if err != nil {
+ t.Error("unable to create new TD from chainA:", err)
+ }
+ cman.TD = td
+
+ _, err = cman.TestChain(chainB)
+ if err != nil {
+ t.Error("expected chainB not to give errors:", err)
+ }
+}
+
+func TestBrokenChain(t *testing.T) {
+ cman := NewChainManager()
+ cman.SetProcessor(fakeproc{})
+
+ TD = big.NewInt(1)
+ chain := makechain(cman, 5)
+ chain.Remove(chain.Front())
+
+ _, err := cman.TestChain(chain)
+ if err == nil {
+ t.Error("expected broken chain to return error")
+ }
+}
+
+func BenchmarkChainTesting(b *testing.B) {
+ const chainlen = 1000
+
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
+ ethutil.Config.Db, _ = ethdb.NewMemDatabase()
+
+ cman := NewChainManager()
+ cman.SetProcessor(fakeproc{})
+
+ TD = big.NewInt(1)
+ chain := makechain(cman, chainlen)
+
+ stime := time.Now()
+ cman.TestChain(chain)
+ fmt.Println(chainlen, "took", time.Since(stime))
+}
diff --git a/core/dagger.go b/core/dagger.go
new file mode 100644
index 000000000..8a042b34f
--- /dev/null
+++ b/core/dagger.go
@@ -0,0 +1,245 @@
+package core
+
+import (
+ "hash"
+ "math/big"
+ "math/rand"
+ "time"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/obscuren/sha3"
+)
+
+var powlogger = logger.NewLogger("POW")
+
+type PoW interface {
+ Search(block *types.Block, stop <-chan struct{}) []byte
+ Verify(hash []byte, diff *big.Int, nonce []byte) bool
+ GetHashrate() int64
+ Turbo(bool)
+}
+
+type EasyPow struct {
+ hash *big.Int
+ HashRate int64
+ turbo bool
+}
+
+func (pow *EasyPow) GetHashrate() int64 {
+ return pow.HashRate
+}
+
+func (pow *EasyPow) Turbo(on bool) {
+ pow.turbo = on
+}
+
+func (pow *EasyPow) Search(block *types.Block, stop <-chan struct{}) []byte {
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
+ hash := block.HashNoNonce()
+ diff := block.Difficulty
+ i := int64(0)
+ start := time.Now().UnixNano()
+ t := time.Now()
+
+ for {
+ select {
+ case <-stop:
+ powlogger.Infoln("Breaking from mining")
+ pow.HashRate = 0
+ return nil
+ default:
+ i++
+
+ if time.Since(t) > (1 * time.Second) {
+ elapsed := time.Now().UnixNano() - start
+ hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
+ pow.HashRate = int64(hashes)
+ powlogger.Infoln("Hashing @", pow.HashRate, "khash")
+
+ t = time.Now()
+ }
+
+ sha := crypto.Sha3(big.NewInt(r.Int63()).Bytes())
+ if pow.Verify(hash, diff, sha) {
+ return sha
+ }
+ }
+
+ if !pow.turbo {
+ time.Sleep(20 * time.Microsecond)
+ }
+ }
+
+ return nil
+}
+
+func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool {
+ sha := sha3.NewKeccak256()
+
+ d := append(hash, nonce...)
+ sha.Write(d)
+
+ verification := new(big.Int).Div(ethutil.BigPow(2, 256), diff)
+ res := ethutil.U256(ethutil.BigD(sha.Sum(nil)))
+
+ /*
+ fmt.Printf("hash w/o nonce %x\n", hash)
+ fmt.Printf("2**256 / %v = %v\n", diff, verification)
+ fmt.Printf("%v <= %v\n", res, verification)
+ fmt.Printf("vlen: %d rlen: %d\n", len(verification.Bytes()), len(res.Bytes()))
+ */
+
+ return res.Cmp(verification) <= 0
+}
+
+func (pow *EasyPow) SetHash(hash *big.Int) {
+}
+
+type Dagger struct {
+ hash *big.Int
+ xn *big.Int
+}
+
+var Found bool
+
+func (dag *Dagger) Find(obj *big.Int, resChan chan int64) {
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+ for i := 0; i < 1000; i++ {
+ rnd := r.Int63()
+
+ res := dag.Eval(big.NewInt(rnd))
+ powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj)
+ if res.Cmp(obj) < 0 {
+ // Post back result on the channel
+ resChan <- rnd
+ // Notify other threads we've found a valid nonce
+ Found = true
+ }
+
+ // Break out if found
+ if Found {
+ break
+ }
+ }
+
+ resChan <- 0
+}
+
+func (dag *Dagger) Search(hash, diff *big.Int) *big.Int {
+ // TODO fix multi threading. Somehow it results in the wrong nonce
+ amountOfRoutines := 1
+
+ dag.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ Found = false
+ resChan := make(chan int64, 3)
+ var res int64
+
+ for k := 0; k < amountOfRoutines; k++ {
+ go dag.Find(obj, resChan)
+
+ // Wait for each go routine to finish
+ }
+ for k := 0; k < amountOfRoutines; k++ {
+ // Get the result from the channel. 0 = quit
+ if r := <-resChan; r != 0 {
+ res = r
+ }
+ }
+
+ return big.NewInt(res)
+}
+
+func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool {
+ dag.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ return dag.Eval(nonce).Cmp(obj) < 0
+}
+
+func DaggerVerify(hash, diff, nonce *big.Int) bool {
+ dagger := &Dagger{}
+ dagger.hash = hash
+
+ obj := ethutil.BigPow(2, 256)
+ obj = obj.Div(obj, diff)
+
+ return dagger.Eval(nonce).Cmp(obj) < 0
+}
+
+func (dag *Dagger) Node(L uint64, i uint64) *big.Int {
+ if L == i {
+ return dag.hash
+ }
+
+ var m *big.Int
+ if L == 9 {
+ m = big.NewInt(16)
+ } else {
+ m = big.NewInt(3)
+ }
+
+ sha := sha3.NewKeccak256()
+ sha.Reset()
+ d := sha3.NewKeccak256()
+ b := new(big.Int)
+ ret := new(big.Int)
+
+ for k := 0; k < int(m.Uint64()); k++ {
+ d.Reset()
+ d.Write(dag.hash.Bytes())
+ d.Write(dag.xn.Bytes())
+ d.Write(big.NewInt(int64(L)).Bytes())
+ d.Write(big.NewInt(int64(i)).Bytes())
+ d.Write(big.NewInt(int64(k)).Bytes())
+
+ b.SetBytes(Sum(d))
+ pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1)
+ sha.Write(dag.Node(L-1, pk).Bytes())
+ }
+
+ ret.SetBytes(Sum(sha))
+
+ return ret
+}
+
+func Sum(sha hash.Hash) []byte {
+ //in := make([]byte, 32)
+ return sha.Sum(nil)
+}
+
+func (dag *Dagger) Eval(N *big.Int) *big.Int {
+ pow := ethutil.BigPow(2, 26)
+ dag.xn = pow.Div(N, pow)
+
+ sha := sha3.NewKeccak256()
+ sha.Reset()
+ ret := new(big.Int)
+
+ for k := 0; k < 4; k++ {
+ d := sha3.NewKeccak256()
+ b := new(big.Int)
+
+ d.Reset()
+ d.Write(dag.hash.Bytes())
+ d.Write(dag.xn.Bytes())
+ d.Write(N.Bytes())
+ d.Write(big.NewInt(int64(k)).Bytes())
+
+ b.SetBytes(Sum(d))
+ pk := (b.Uint64() & 0x1ffffff)
+
+ sha.Write(dag.Node(9, pk).Bytes())
+ }
+
+ return ret.SetBytes(Sum(sha))
+}
diff --git a/core/dagger_test.go b/core/dagger_test.go
new file mode 100644
index 000000000..e80064e6b
--- /dev/null
+++ b/core/dagger_test.go
@@ -0,0 +1,19 @@
+package core
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+func BenchmarkDaggerSearch(b *testing.B) {
+ hash := big.NewInt(0)
+ diff := ethutil.BigPow(2, 36)
+ o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity
+
+ // Reset timer so the big generation isn't included in the benchmark
+ b.ResetTimer()
+ // Validate
+ DaggerVerify(hash, diff, o)
+}
diff --git a/core/error.go b/core/error.go
new file mode 100644
index 000000000..11d8c1653
--- /dev/null
+++ b/core/error.go
@@ -0,0 +1,141 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+)
+
+// 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 GasLimitErr struct {
+ Message string
+ Is, Max *big.Int
+}
+
+func IsGasLimitErr(err error) bool {
+ _, ok := err.(*GasLimitErr)
+
+ return ok
+}
+func (err *GasLimitErr) Error() string {
+ return err.Message
+}
+func GasLimitError(is, max *big.Int) *GasLimitErr {
+ return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max}
+}
+
+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..deeba3e98
--- /dev/null
+++ b/core/events.go
@@ -0,0 +1,12 @@
+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 }
diff --git a/core/execution.go b/core/execution.go
new file mode 100644
index 000000000..9f9d9a5d9
--- /dev/null
+++ b/core/execution.go
@@ -0,0 +1,80 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+type Execution struct {
+ vm vm.VirtualMachine
+ address, input []byte
+ Gas, price, value *big.Int
+ object *state.StateObject
+ SkipTransfer bool
+}
+
+func NewExecution(vm vm.VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
+ return &Execution{vm: vm, 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.ClosureRef) ([]byte, error) {
+ // Retrieve the executing code
+ code := self.vm.Env().State().GetCode(codeAddr)
+
+ return self.exec(code, codeAddr, caller)
+}
+
+func (self *Execution) exec(code, caddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
+ env := self.vm.Env()
+
+ chainlogger.Debugf("pre state %x\n", env.State().Root())
+ snapshot := env.State().Copy()
+ defer func() {
+ if vm.IsDepthErr(err) || vm.IsOOGErr(err) {
+ env.State().Set(snapshot)
+ }
+ chainlogger.Debugf("post state %x\n", env.State().Root())
+ }()
+
+ from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
+ // Skipping transfer is used on testing for the initial call
+ if !self.SkipTransfer {
+ err = env.Transfer(from, to, self.value)
+ }
+
+ if err != nil {
+ caller.ReturnGas(self.Gas, self.price)
+
+ err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance)
+ } else {
+ self.object = to
+ // Pre-compiled contracts (address.go) 1, 2 & 3.
+ naddr := ethutil.BigD(caddr).Uint64()
+ if p := vm.Precompiled[naddr]; p != nil {
+ if self.Gas.Cmp(p.Gas) >= 0 {
+ ret = p.Call(self.input)
+ self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret)
+ self.vm.Endl()
+ }
+ } else {
+ ret, err = self.vm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
+ }
+ }
+
+ return
+}
+
+func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject) {
+ ret, err = self.exec(self.input, nil, caller)
+ account = self.vm.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..fe3665bf3
--- /dev/null
+++ b/core/filter.go
@@ -0,0 +1,200 @@
+package core
+
+import (
+ "bytes"
+ "math"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+)
+
+type AccountChange struct {
+ Address, StateAddress []byte
+}
+
+// Filtering interface
+type Filter struct {
+ eth EthManager
+ earliest int64
+ latest int64
+ skip int
+ from, to [][]byte
+ max int
+
+ Altered []AccountChange
+
+ BlockCallback func(*types.Block)
+ MessageCallback func(state.Messages)
+}
+
+// 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 EthManager) *Filter {
+ return &Filter{eth: eth}
+}
+
+func (self *Filter) AddAltered(address, stateAddress []byte) {
+ self.Altered = append(self.Altered, AccountChange{address, stateAddress})
+}
+
+// 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) SetFrom(addr [][]byte) {
+ self.from = addr
+}
+
+func (self *Filter) AddFrom(addr []byte) {
+ self.from = append(self.from, addr)
+}
+
+func (self *Filter) SetTo(addr [][]byte) {
+ self.to = addr
+}
+
+func (self *Filter) AddTo(addr []byte) {
+ self.to = append(self.to, addr)
+}
+
+func (self *Filter) SetMax(max int) {
+ self.max = max
+}
+
+func (self *Filter) SetSkip(skip int) {
+ self.skip = skip
+}
+
+// Run filters messages with the current parameters set
+func (self *Filter) Find() []*state.Message {
+ var earliestBlockNo uint64 = uint64(self.earliest)
+ if self.earliest == -1 {
+ earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ }
+ var latestBlockNo uint64 = uint64(self.latest)
+ if self.latest == -1 {
+ latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ }
+
+ var (
+ messages []*state.Message
+ block = self.eth.ChainManager().GetBlockByNumber(latestBlockNo)
+ quit bool
+ )
+ for i := 0; !quit && block != nil; i++ {
+ // Quit on latest
+ switch {
+ case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0:
+ quit = true
+ case self.max <= len(messages):
+ break
+ }
+
+ // Use bloom filtering to see if this block is interesting given the
+ // current parameters
+ if self.bloomFilter(block) {
+ // Get the messages of the block
+ msgs, err := self.eth.BlockManager().GetMessages(block)
+ if err != nil {
+ chainlogger.Warnln("err: filter get messages ", err)
+
+ break
+ }
+
+ messages = append(messages, self.FilterMessages(msgs)...)
+ }
+
+ block = self.eth.ChainManager().GetBlock(block.PrevHash)
+ }
+
+ skip := int(math.Min(float64(len(messages)), float64(self.skip)))
+
+ return messages[skip:]
+}
+
+func includes(addresses [][]byte, a []byte) (found bool) {
+ for _, addr := range addresses {
+ if bytes.Compare(addr, a) == 0 {
+ return true
+ }
+ }
+
+ return
+}
+
+func (self *Filter) FilterMessages(msgs []*state.Message) []*state.Message {
+ var messages []*state.Message
+
+ // Filter the messages for interesting stuff
+ for _, message := range msgs {
+ if len(self.to) > 0 && !includes(self.to, message.To) {
+ continue
+ }
+
+ if len(self.from) > 0 && !includes(self.from, message.From) {
+ continue
+ }
+
+ var match bool
+ if len(self.Altered) == 0 {
+ match = true
+ }
+
+ for _, accountChange := range self.Altered {
+ if len(accountChange.Address) > 0 && bytes.Compare(message.To, accountChange.Address) != 0 {
+ continue
+ }
+
+ if len(accountChange.StateAddress) > 0 && !includes(message.ChangedAddresses, accountChange.StateAddress) {
+ continue
+ }
+
+ match = true
+ break
+ }
+
+ if !match {
+ continue
+ }
+
+ messages = append(messages, message)
+ }
+
+ return messages
+}
+
+func (self *Filter) bloomFilter(block *types.Block) bool {
+ var fromIncluded, toIncluded bool
+ if len(self.from) > 0 {
+ for _, from := range self.from {
+ if types.BloomLookup(block.LogsBloom, from) || bytes.Equal(block.Coinbase, from) {
+ fromIncluded = true
+ break
+ }
+ }
+ } else {
+ fromIncluded = true
+ }
+
+ if len(self.to) > 0 {
+ for _, to := range self.to {
+ if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase, to) {
+ toIncluded = true
+ break
+ }
+ }
+ } else {
+ toIncluded = true
+ }
+
+ return fromIncluded && toIncluded
+}
diff --git a/core/filter_test.go b/core/filter_test.go
new file mode 100644
index 000000000..d53b835b7
--- /dev/null
+++ b/core/filter_test.go
@@ -0,0 +1,7 @@
+package core
+
+// import "testing"
+
+// func TestFilter(t *testing.T) {
+// NewFilter(NewTestManager())
+// }
diff --git a/core/genesis.go b/core/genesis.go
new file mode 100644
index 000000000..707154759
--- /dev/null
+++ b/core/genesis.go
@@ -0,0 +1,52 @@
+package core
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+)
+
+/*
+ * 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(""))
+
+var GenesisHeader = []interface{}{
+ // Previous hash (none)
+ ZeroHash256,
+ // Empty uncles
+ EmptyShaList,
+ // Coinbase
+ ZeroHash160,
+ // Root state
+ EmptyShaList,
+ // tx root
+ EmptyListRoot,
+ // receipt root
+ EmptyListRoot,
+ // bloom
+ ZeroHash512,
+ // Difficulty
+ //ethutil.BigPow(2, 22),
+ big.NewInt(131072),
+ // Number
+ ethutil.Big0,
+ // Block upper gas bound
+ big.NewInt(1000000),
+ // Block gas used
+ ethutil.Big0,
+ // Time
+ ethutil.Big0,
+ // Extra
+ nil,
+ // Nonce
+ crypto.Sha3(big.NewInt(42).Bytes()),
+}
+
+var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
diff --git a/core/helper_test.go b/core/helper_test.go
new file mode 100644
index 000000000..2b1510ea4
--- /dev/null
+++ b/core/helper_test.go
@@ -0,0 +1,93 @@
+package core
+
+import (
+ "container/list"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/chain/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/wire"
+)
+
+// 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) Broadcast(msgType wire.MsgType, data []interface{}) {
+ fmt.Println("Broadcast not implemented")
+}
+
+func (tm *TestManager) ClientIdentity() wire.ClientIdentity {
+ return nil
+}
+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
+ }
+ ethutil.Config.Db = db
+
+ 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/state_transition.go b/core/state_transition.go
new file mode 100644
index 000000000..e3eea57de
--- /dev/null
+++ b/core/state_transition.go
@@ -0,0 +1,198 @@
+package core
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/vm"
+)
+
+/*
+ * 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, receiver []byte
+ tx *types.Transaction
+ gas, gasPrice *big.Int
+ value *big.Int
+ data []byte
+ state *state.State
+ block *types.Block
+
+ cb, rec, sen *state.StateObject
+}
+
+func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.State, block *types.Block) *StateTransition {
+ return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil}
+}
+
+func (self *StateTransition) Coinbase() *state.StateObject {
+ if self.cb != nil {
+ return self.cb
+ }
+
+ self.cb = self.state.GetOrNewStateObject(self.coinbase)
+ return self.cb
+}
+func (self *StateTransition) Sender() *state.StateObject {
+ if self.sen != nil {
+ return self.sen
+ }
+
+ self.sen = self.state.GetOrNewStateObject(self.tx.Sender())
+
+ return self.sen
+}
+func (self *StateTransition) Receiver() *state.StateObject {
+ if self.tx != nil && self.tx.CreatesContract() {
+ return nil
+ }
+
+ if self.rec != nil {
+ return self.rec
+ }
+
+ self.rec = self.state.GetOrNewStateObject(self.tx.Recipient)
+ return self.rec
+}
+
+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.Sender()
+ if sender.Balance().Cmp(self.tx.GasValue()) < 0 {
+ return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance())
+ }
+
+ coinbase := self.Coinbase()
+ err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice)
+ if err != nil {
+ return err
+ }
+
+ self.AddGas(self.tx.Gas)
+ sender.SubAmount(self.tx.GasValue())
+
+ return nil
+}
+
+func (self *StateTransition) RefundGas() {
+ coinbase, sender := self.Coinbase(), self.Sender()
+ coinbase.RefundGas(self.gas, self.tx.GasPrice)
+
+ // Return remaining gas
+ remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice)
+ sender.AddAmount(remaining)
+}
+
+func (self *StateTransition) preCheck() (err error) {
+ var (
+ tx = self.tx
+ sender = self.Sender()
+ )
+
+ // Make sure this transaction's nonce is correct
+ if sender.Nonce != tx.Nonce {
+ return NonceError(tx.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() (err error) {
+ statelogger.Debugf("(~) %x\n", self.tx.Hash())
+
+ // XXX Transactions after this point are considered valid.
+ if err = self.preCheck(); err != nil {
+ return
+ }
+
+ var (
+ tx = self.tx
+ sender = self.Sender()
+ receiver *state.StateObject
+ )
+
+ defer self.RefundGas()
+
+ // Increment the nonce for the next transaction
+ sender.Nonce += 1
+
+ // Transaction gas
+ if err = self.UseGas(vm.GasTx); err != nil {
+ return
+ }
+
+ // Pay data gas
+ var dgas int64
+ for _, byt := range self.data {
+ if byt != 0 {
+ dgas += vm.GasData.Int64()
+ } else {
+ dgas += 1 // This is 1/5. If GasData changes this fails
+ }
+ }
+ if err = self.UseGas(big.NewInt(dgas)); err != nil {
+ return
+ }
+
+ var ret []byte
+ vmenv := NewEnv(self.state, self.tx, self.block)
+ var ref vm.ClosureRef
+ if tx.CreatesContract() {
+ self.rec = MakeContract(tx, self.state)
+
+ ret, err, ref = vmenv.Create(sender, receiver.Address(), self.tx.Data, self.gas, self.gasPrice, self.value)
+ ref.SetCode(ret)
+ } else {
+ ret, err = vmenv.Call(self.Sender(), self.Receiver().Address(), self.tx.Data, self.gas, self.gasPrice, self.value)
+ }
+ if err != nil {
+ statelogger.Debugln(err)
+ }
+
+ return
+}
+
+// Converts an transaction in to a state object
+func MakeContract(tx *types.Transaction, state *state.State) *state.StateObject {
+ addr := tx.CreationAddress(state)
+
+ contract := state.GetOrNewStateObject(addr)
+ contract.InitCode = tx.Data
+
+ return contract
+}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
new file mode 100644
index 000000000..2a14e48b2
--- /dev/null
+++ b/core/transaction_pool.go
@@ -0,0 +1,236 @@
+package core
+
+import (
+ "bytes"
+ "container/list"
+ "fmt"
+ "math/big"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/wire"
+)
+
+var txplogger = logger.NewLogger("TXP")
+
+const txPoolQueueSize = 50
+
+type TxPoolHook chan *types.Transaction
+type TxMsgTy byte
+
+const (
+ minGasPrice = 1000000
+)
+
+var MinGasPrice = big.NewInt(10000000000000)
+
+type TxMsg struct {
+ Tx *types.Transaction
+ Type TxMsgTy
+}
+
+func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool) {
+ for e := pool.Front(); e != nil; e = e.Next() {
+ if it(e.Value.(*types.Transaction), e) {
+ break
+ }
+ }
+}
+
+func FindTx(pool *list.List, finder func(*types.Transaction, *list.Element) bool) *types.Transaction {
+ for e := pool.Front(); e != nil; e = e.Next() {
+ if tx, ok := e.Value.(*types.Transaction); ok {
+ if finder(tx, e) {
+ return tx
+ }
+ }
+ }
+
+ return nil
+}
+
+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. If the
+// pool is being drained or synced for whatever reason the transactions
+// will simple queue up and handled when the mutex is freed.
+type TxPool struct {
+ Ethereum EthManager
+ // The mutex for accessing the Tx pool.
+ mutex sync.Mutex
+ // Queueing channel for reading and writing incoming
+ // transactions to
+ queueChan chan *types.Transaction
+ // Quiting channel
+ quit chan bool
+ // The actual pool
+ pool *list.List
+
+ SecondaryProcessor TxProcessor
+
+ subscribers []chan TxMsg
+}
+
+func NewTxPool(ethereum EthManager) *TxPool {
+ return &TxPool{
+ pool: list.New(),
+ queueChan: make(chan *types.Transaction, txPoolQueueSize),
+ quit: make(chan bool),
+ Ethereum: ethereum,
+ }
+}
+
+// Blocking function. Don't use directly. Use QueueTransaction instead
+func (pool *TxPool) addTransaction(tx *types.Transaction) {
+ pool.mutex.Lock()
+ defer pool.mutex.Unlock()
+
+ pool.pool.PushBack(tx)
+
+ // Broadcast the transaction to the rest of the peers
+ pool.Ethereum.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()})
+}
+
+func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
+ // Get the last block so we can retrieve the sender and receiver from
+ // the merkle trie
+ block := pool.Ethereum.ChainManager().CurrentBlock
+ // Something has gone horribly wrong if this happens
+ if block == nil {
+ return fmt.Errorf("No last block on the block chain")
+ }
+
+ if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 {
+ return fmt.Errorf("Invalid recipient. len = %d", len(tx.Recipient))
+ }
+
+ v, _, _ := tx.Curve()
+ if v > 28 || v < 27 {
+ return fmt.Errorf("tx.v != (28 || 27)")
+ }
+
+ if tx.GasPrice.Cmp(MinGasPrice) < 0 {
+ return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice)
+ }
+
+ // Get the sender
+ sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender())
+
+ 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.Sender())
+ }
+
+ if tx.IsContract() {
+ if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 {
+ return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice)
+ }
+ }
+
+ // Increment the nonce making each tx valid only once to prevent replay
+ // attacks
+
+ return nil
+}
+
+func (self *TxPool) Add(tx *types.Transaction) error {
+ hash := tx.Hash()
+ foundTx := FindTx(self.pool, func(tx *types.Transaction, e *list.Element) bool {
+ return bytes.Compare(tx.Hash(), hash) == 0
+ })
+
+ if foundTx != nil {
+ return fmt.Errorf("Known transaction (%x)", hash[0:4])
+ }
+
+ err := self.ValidateTransaction(tx)
+ if err != nil {
+ return err
+ }
+
+ self.addTransaction(tx)
+
+ tmp := make([]byte, 4)
+ copy(tmp, tx.Recipient)
+
+ txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash())
+
+ // Notify the subscribers
+ self.Ethereum.EventMux().Post(TxPreEvent{tx})
+
+ return nil
+}
+
+func (pool *TxPool) CurrentTransactions() []*types.Transaction {
+ pool.mutex.Lock()
+ defer pool.mutex.Unlock()
+
+ txList := make([]*types.Transaction, pool.pool.Len())
+ i := 0
+ for e := pool.pool.Front(); e != nil; e = e.Next() {
+ tx := e.Value.(*types.Transaction)
+
+ txList[i] = tx
+
+ i++
+ }
+
+ return txList
+}
+
+func (pool *TxPool) RemoveInvalid(state *state.State) {
+ pool.mutex.Lock()
+ defer pool.mutex.Unlock()
+
+ for e := pool.pool.Front(); e != nil; e = e.Next() {
+ tx := e.Value.(*types.Transaction)
+ sender := state.GetAccount(tx.Sender())
+ err := pool.ValidateTransaction(tx)
+ if err != nil || sender.Nonce >= tx.Nonce {
+ pool.pool.Remove(e)
+ }
+ }
+}
+
+func (self *TxPool) RemoveSet(txs types.Transactions) {
+ self.mutex.Lock()
+ defer self.mutex.Unlock()
+
+ for _, tx := range txs {
+ EachTx(self.pool, func(t *types.Transaction, element *list.Element) bool {
+ if t == tx {
+ self.pool.Remove(element)
+ return true // To stop the loop
+ }
+ return false
+ })
+ }
+}
+
+func (pool *TxPool) Flush() []*types.Transaction {
+ txList := pool.CurrentTransactions()
+
+ // Recreate a new list all together
+ // XXX Is this the fastest way?
+ pool.pool = list.New()
+
+ return txList
+}
+
+func (pool *TxPool) Start() {
+ //go pool.queueHandler()
+}
+
+func (pool *TxPool) Stop() {
+ pool.Flush()
+
+ txplogger.Infoln("Stopped")
+}
diff --git a/core/types/block.go b/core/types/block.go
new file mode 100644
index 000000000..feab7072f
--- /dev/null
+++ b/core/types/block.go
@@ -0,0 +1,413 @@
+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/state"
+ "github.com/ethereum/go-ethereum/trie"
+)
+
+type BlockInfo struct {
+ Number uint64
+ Hash []byte
+ Parent []byte
+ TD *big.Int
+}
+
+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()
+ bi.TD = decoder.Get(3).BigInt()
+}
+
+func (bi *BlockInfo) RlpEncode() []byte {
+ return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD})
+}
+
+type Blocks []*Block
+
+func (self Blocks) AsSet() ethutil.UniqueSet {
+ set := make(ethutil.UniqueSet)
+ for _, block := range self {
+ set.Insert(block.Hash())
+ }
+
+ return set
+}
+
+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.Number.Cmp(b2.Number) < 0 }
+
+type Block struct {
+ // Hash to the previous block
+ PrevHash ethutil.Bytes
+ // Uncles of this block
+ Uncles Blocks
+ UncleSha []byte
+ // The coin base address
+ Coinbase []byte
+ // Block Trie state
+ //state *ethutil.Trie
+ state *state.State
+ // Difficulty for the current block
+ Difficulty *big.Int
+ // Creation time
+ Time int64
+ // The block number
+ Number *big.Int
+ // Gas limit
+ GasLimit *big.Int
+ // Gas used
+ GasUsed *big.Int
+ // Extra data
+ Extra string
+ // Block Nonce for verification
+ Nonce ethutil.Bytes
+ // List of transactions and/or contracts
+ transactions Transactions
+ receipts Receipts
+ TxSha, ReceiptSha []byte
+ LogsBloom []byte
+
+ Reward *big.Int
+}
+
+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) *Block {
+
+ block := &Block{
+ PrevHash: prevHash,
+ Coinbase: base,
+ Difficulty: Difficulty,
+ Nonce: Nonce,
+ Time: time.Now().Unix(),
+ Extra: extra,
+ UncleSha: nil,
+ GasUsed: new(big.Int),
+ GasLimit: new(big.Int),
+ }
+ block.SetUncles([]*Block{})
+
+ block.state = state.New(trie.New(ethutil.Config.Db, root))
+
+ return block
+}
+
+// Returns a hash of the block
+func (block *Block) Hash() ethutil.Bytes {
+ return crypto.Sha3(ethutil.NewValue(block.header()).Encode())
+ //return crypto.Sha3(block.Value().Encode())
+}
+
+func (block *Block) HashNoNonce() []byte {
+ return crypto.Sha3(ethutil.Encode(block.miningHeader()))
+}
+
+func (block *Block) State() *state.State {
+ return block.state
+}
+
+func (block *Block) Transactions() Transactions {
+ return block.transactions
+}
+
+func (block *Block) CalcGasLimit(parent *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)
+}
+
+func (block *Block) BlockInfo() BlockInfo {
+ bi := BlockInfo{}
+ data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
+ bi.RlpDecode(data)
+
+ return bi
+}
+
+func (self *Block) GetTransaction(hash []byte) *Transaction {
+ for _, tx := range self.transactions {
+ if bytes.Compare(tx.Hash(), hash) == 0 {
+ return tx
+ }
+ }
+
+ return nil
+}
+
+// Sync the block's state and contract respectively
+func (block *Block) Sync() {
+ block.state.Sync()
+}
+
+func (block *Block) Undo() {
+ // Sync the block state itself
+ block.state.Reset()
+}
+
+/////// Block Encoding
+func (block *Block) rlpReceipts() interface{} {
+ // Marshal the transactions of this block
+ encR := make([]interface{}, len(block.receipts))
+ for i, r := range block.receipts {
+ // Cast it to a string (safe)
+ encR[i] = r.RlpData()
+ }
+
+ return encR
+}
+
+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
+ block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles()))
+}
+
+func (self *Block) SetReceipts(receipts Receipts) {
+ self.receipts = receipts
+ self.ReceiptSha = DeriveSha(receipts)
+ self.LogsBloom = CreateBloom(receipts)
+}
+
+func (self *Block) SetTransactions(txs Transactions) {
+ self.transactions = txs
+ self.TxSha = DeriveSha(txs)
+}
+
+func (block *Block) Value() *ethutil.Value {
+ return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()})
+}
+
+func (block *Block) RlpEncode() []byte {
+ // Encode a slice interface which contains the header and the list of
+ // transactions.
+ return block.Value().Encode()
+}
+
+func (block *Block) RlpDecode(data []byte) {
+ rlpValue := ethutil.NewValueFromBytes(data)
+ block.RlpValueDecode(rlpValue)
+}
+
+func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
+ block.setHeader(decoder.Get(0))
+
+ // Tx list might be empty if this is an uncle. Uncles only have their
+ // header set.
+ if decoder.Get(1).IsNil() == false { // Yes explicitness
+ //receipts := decoder.Get(1)
+ //block.receipts = make([]*Receipt, receipts.Len())
+ txs := decoder.Get(1)
+ block.transactions = make(Transactions, txs.Len())
+ for i := 0; i < txs.Len(); i++ {
+ block.transactions[i] = NewTransactionFromValue(txs.Get(i))
+ //receipt := NewRecieptFromValue(receipts.Get(i))
+ //block.transactions[i] = receipt.Tx
+ //block.receipts[i] = receipt
+ }
+
+ }
+
+ 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 (self *Block) setHeader(header *ethutil.Value) {
+ self.PrevHash = header.Get(0).Bytes()
+ self.UncleSha = header.Get(1).Bytes()
+ self.Coinbase = header.Get(2).Bytes()
+ self.state = state.New(trie.New(ethutil.Config.Db, header.Get(3).Val))
+ self.TxSha = header.Get(4).Bytes()
+ self.ReceiptSha = header.Get(5).Bytes()
+ self.LogsBloom = header.Get(6).Bytes()
+ self.Difficulty = header.Get(7).BigInt()
+ self.Number = header.Get(8).BigInt()
+ self.GasLimit = header.Get(9).BigInt()
+ self.GasUsed = header.Get(10).BigInt()
+ self.Time = int64(header.Get(11).BigInt().Uint64())
+ self.Extra = header.Get(12).Str()
+ self.Nonce = header.Get(13).Bytes()
+}
+
+func NewUncleBlockFromValue(header *ethutil.Value) *Block {
+ block := &Block{}
+ block.setHeader(header)
+
+ return block
+}
+
+func (block *Block) Trie() *trie.Trie {
+ return block.state.Trie
+}
+
+func (block *Block) Root() interface{} {
+ return block.state.Root()
+}
+
+func (block *Block) Diff() *big.Int {
+ return block.Difficulty
+}
+
+func (self *Block) Receipts() []*Receipt {
+ return self.receipts
+}
+
+func (block *Block) miningHeader() []interface{} {
+ return []interface{}{
+ // Sha of the previous block
+ block.PrevHash,
+ // Sha of uncles
+ block.UncleSha,
+ // Coinbase address
+ block.Coinbase,
+ // root state
+ block.Root(),
+ // tx root
+ block.TxSha,
+ // Sha of tx
+ block.ReceiptSha,
+ // Bloom
+ block.LogsBloom,
+ // Current block Difficulty
+ block.Difficulty,
+ // The block number
+ block.Number,
+ // Block upper gas bound
+ block.GasLimit,
+ // Block gas used
+ block.GasUsed,
+ // Time the block was found?
+ block.Time,
+ // Extra data
+ block.Extra,
+ }
+}
+
+func (block *Block) header() []interface{} {
+ return append(block.miningHeader(), block.Nonce)
+}
+
+func (block *Block) String() string {
+ return fmt.Sprintf(`
+ BLOCK(%x): Size: %v
+ PrevHash: %x
+ UncleSha: %x
+ Coinbase: %x
+ Root: %x
+ TxSha %x
+ ReceiptSha: %x
+ Bloom: %x
+ Difficulty: %v
+ Number: %v
+ MaxLimit: %v
+ GasUsed: %v
+ Time: %v
+ Extra: %v
+ Nonce: %x
+ NumTx: %v
+`,
+ block.Hash(),
+ block.Size(),
+ block.PrevHash,
+ block.UncleSha,
+ block.Coinbase,
+ block.Root(),
+ block.TxSha,
+ block.ReceiptSha,
+ block.LogsBloom,
+ block.Difficulty,
+ block.Number,
+ block.GasLimit,
+ block.GasUsed,
+ block.Time,
+ block.Extra,
+ block.Nonce,
+ len(block.transactions),
+ )
+}
+
+func (self *Block) Size() ethutil.StorageSize {
+ return ethutil.StorageSize(len(self.RlpEncode()))
+}
+
+// Implement RlpEncodable
+func (self *Block) RlpData() interface{} {
+ return self.Value().Val
+}
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
new file mode 100644
index 000000000..77aa6eef5
--- /dev/null
+++ b/core/types/bloom9.go
@@ -0,0 +1,56 @@
+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(), 64)
+}
+
+func LogsBloom(logs state.Logs) *big.Int {
+ bin := new(big.Int)
+ for _, log := range logs {
+ data := [][]byte{log.Address}
+ for _, topic := range log.Topics {
+ data = append(data, topic)
+ }
+
+ for _, b := range data {
+ bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes()))
+ }
+
+ //if log.Data != nil {
+ // data = append(data, log.Data)
+ //}
+ }
+
+ return bin
+}
+
+func bloom9(b []byte) *big.Int {
+ r := new(big.Int)
+ for _, i := range []int{0, 2, 4} {
+ t := big.NewInt(1)
+ b := uint(b[i+1]) + 256*(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..ba88b77e1
--- /dev/null
+++ b/core/types/common.go
@@ -0,0 +1,11 @@
+package types
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/state"
+)
+
+type BlockProcessor interface {
+ Process(*Block) (*big.Int, state.Messages, error)
+}
diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go
new file mode 100644
index 000000000..1897ff198
--- /dev/null
+++ b/core/types/derive_sha.go
@@ -0,0 +1,20 @@
+package types
+
+import (
+ "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 {
+ trie := trie.New(ethutil.Config.Db, "")
+ for i := 0; i < list.Len(); i++ {
+ trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i)))
+ }
+
+ return trie.GetRoot()
+}
diff --git a/core/types/receipt.go b/core/types/receipt.go
new file mode 100644
index 000000000..25fa8fb07
--- /dev/null
+++ b/core/types/receipt.go
@@ -0,0 +1,68 @@
+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: 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) 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..efc90b6f2
--- /dev/null
+++ b/core/types/transaction.go
@@ -0,0 +1,225 @@
+package types
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/obscuren/secp256k1-go"
+)
+
+var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+func IsContractAddr(addr []byte) bool {
+ return len(addr) == 0
+ //return bytes.Compare(addr, ContractAddr) == 0
+}
+
+type Transaction struct {
+ Nonce uint64
+ Recipient []byte
+ Value *big.Int
+ Gas *big.Int
+ GasPrice *big.Int
+ Data []byte
+ v byte
+ r, s []byte
+
+ // Indicates whether this tx is a contract creation transaction
+ contractCreation bool
+}
+
+func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
+ return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true}
+}
+
+func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
+ return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)}
+}
+
+func NewTransactionFromBytes(data []byte) *Transaction {
+ tx := &Transaction{}
+ tx.RlpDecode(data)
+
+ return tx
+}
+
+func NewTransactionFromValue(val *ethutil.Value) *Transaction {
+ tx := &Transaction{}
+ tx.RlpValueDecode(val)
+
+ return tx
+}
+
+func (self *Transaction) GasValue() *big.Int {
+ return new(big.Int).Mul(self.Gas, self.GasPrice)
+}
+
+func (self *Transaction) TotalValue() *big.Int {
+ v := self.GasValue()
+ return v.Add(v, self.Value)
+}
+
+func (tx *Transaction) Hash() []byte {
+ data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+
+ return crypto.Sha3(ethutil.NewValue(data).Encode())
+}
+
+func (tx *Transaction) CreatesContract() bool {
+ return tx.contractCreation
+}
+
+/* Deprecated */
+func (tx *Transaction) IsContract() bool {
+ return tx.CreatesContract()
+}
+
+func (tx *Transaction) CreationAddress(state *state.State) []byte {
+ // Generate a new address
+ return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:]
+}
+
+func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
+ v = 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 = sig[64] + 27
+
+ return nil
+}
+
+func (tx *Transaction) RlpData() interface{} {
+ data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+
+ // TODO Remove prefixing zero's
+
+ return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes())
+}
+
+func (tx *Transaction) RlpValue() *ethutil.Value {
+ return ethutil.NewValue(tx.RlpData())
+}
+
+func (tx *Transaction) RlpEncode() []byte {
+ return tx.RlpValue().Encode()
+}
+
+func (tx *Transaction) RlpDecode(data []byte) {
+ tx.RlpValueDecode(ethutil.NewValueFromBytes(data))
+}
+
+func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
+ tx.Nonce = decoder.Get(0).Uint()
+ tx.GasPrice = decoder.Get(1).BigInt()
+ tx.Gas = decoder.Get(2).BigInt()
+ tx.Recipient = decoder.Get(3).Bytes()
+ tx.Value = decoder.Get(4).BigInt()
+ tx.Data = decoder.Get(5).Bytes()
+ tx.v = byte(decoder.Get(6).Uint())
+
+ tx.r = decoder.Get(7).Bytes()
+ tx.s = decoder.Get(8).Bytes()
+
+ if IsContractAddr(tx.Recipient) {
+ tx.contractCreation = true
+ }
+}
+
+func (tx *Transaction) String() string {
+ return fmt.Sprintf(`
+ TX(%x)
+ Contract: %v
+ From: %x
+ To: %x
+ Nonce: %v
+ GasPrice: %v
+ Gas: %v
+ Value: %v
+ Data: 0x%x
+ V: 0x%x
+ R: 0x%x
+ S: 0x%x
+ `,
+ tx.Hash(),
+ len(tx.Recipient) == 0,
+ tx.Sender(),
+ tx.Recipient,
+ tx.Nonce,
+ tx.GasPrice,
+ tx.Gas,
+ tx.Value,
+ tx.Data,
+ tx.v,
+ tx.r,
+ tx.s)
+}
+
+// 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].Nonce < s.Transactions[j].Nonce
+}
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..17686b28f
--- /dev/null
+++ b/core/vm_env.go
@@ -0,0 +1,63 @@
+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.State
+ block *types.Block
+ tx *types.Transaction
+ depth int
+}
+
+func NewEnv(state *state.State, tx *types.Transaction, block *types.Block) *VMEnv {
+ return &VMEnv{
+ state: state,
+ block: block,
+ tx: tx,
+ }
+}
+
+func (self *VMEnv) Origin() []byte { return self.tx.Sender() }
+func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
+func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
+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) BlockHash() []byte { return self.block.Hash() }
+func (self *VMEnv) Value() *big.Int { return self.tx.Value }
+func (self *VMEnv) State() *state.State { return self.state }
+func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
+func (self *VMEnv) Depth() int { return self.depth }
+func (self *VMEnv) SetDepth(i int) { self.depth = i }
+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 {
+ evm := vm.New(self, vm.DebugVmTy)
+
+ return NewExecution(evm, addr, data, gas, price, value)
+}
+
+func (self *VMEnv) Call(me vm.ClosureRef, 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.ClosureRef, 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.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ClosureRef) {
+ exe := self.vm(addr, data, gas, price, value)
+ return exe.Create(me)
+}