aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-09-23 01:34:31 +0800
committerobscuren <geffobscura@gmail.com>2014-09-23 01:34:31 +0800
commitce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9 (patch)
treeac183aa3312a4589cb3e4995cc103cfa58ef95da
parent8ef17c2fb138ae254a0cc7ac509a7ab1177ee4ac (diff)
parent7d08e4f7d14600ee4ed38fc9d435e9c2e0e0fdac (diff)
downloadgo-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar.gz
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar.bz2
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar.lz
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar.xz
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.tar.zst
go-tangerine-ce149d2733bd55e8e9b16dd4b60b6bad17c3d7d9.zip
Merge branch 'release/0.6.5'
-rw-r--r--README.md2
-rw-r--r--block_pool.go58
-rw-r--r--ethchain/block.go53
-rw-r--r--ethchain/block_chain.go192
-rw-r--r--ethchain/error.go18
-rw-r--r--ethchain/fees.go2
-rw-r--r--ethchain/filter.go3
-rw-r--r--ethchain/state_manager.go100
-rw-r--r--ethchain/state_transition.go11
-rw-r--r--ethchain/transaction.go5
-rw-r--r--ethchain/transaction_pool.go9
-rw-r--r--ethchain/types.go244
-rw-r--r--ethcrypto/crypto_test.go17
-rw-r--r--ethdb/database.go13
-rw-r--r--ethereum.go173
-rw-r--r--ethminer/miner.go2
-rw-r--r--ethpipe/js_pipe.go130
-rw-r--r--ethpipe/js_types.go33
-rw-r--r--ethpipe/pipe.go27
-rw-r--r--ethreact/reactor.go5
-rw-r--r--ethrpc/packages.go21
-rw-r--r--ethstate/dump.go2
-rw-r--r--ethstate/state.go16
-rw-r--r--ethstate/state_object.go25
-rw-r--r--ethtrie/trie.go7
-rw-r--r--ethutil/bytes.go16
-rw-r--r--ethutil/list.go61
-rw-r--r--ethutil/path.go2
-rw-r--r--ethutil/rlp.go6
-rw-r--r--ethutil/script.go18
-rw-r--r--ethutil/set.go36
-rw-r--r--ethutil/size.go15
-rw-r--r--ethutil/size_test.go12
-rw-r--r--ethutil/value.go14
-rw-r--r--ethutil/value_test.go6
-rw-r--r--ethvm/closure.go1
-rw-r--r--ethvm/stack.go6
-rw-r--r--ethvm/types.go47
-rw-r--r--ethvm/vm.go331
-rw-r--r--ethwire/client_identity.go22
-rw-r--r--ethwire/messages2.go199
-rw-r--r--ethwire/messaging.go272
-rw-r--r--natpmp.go1
-rw-r--r--peer.go400
44 files changed, 1493 insertions, 1140 deletions
diff --git a/README.md b/README.md
index ae624d84a..a80ed34b0 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof
-of Concept 0.6.4". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
+of Concept 0.6.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.
diff --git a/block_pool.go b/block_pool.go
index 3225bdff2..6753308b6 100644
--- a/block_pool.go
+++ b/block_pool.go
@@ -33,6 +33,10 @@ func NewBlockPool(eth *Ethereum) *BlockPool {
}
}
+func (self *BlockPool) Len() int {
+ return len(self.hashPool)
+}
+
func (self *BlockPool) HasLatestHash() bool {
return self.pool[string(self.eth.BlockChain().CurrentBlock.Hash())] != nil
}
@@ -49,51 +53,37 @@ func (self *BlockPool) AddHash(hash []byte) {
}
}
-func (self *BlockPool) SetBlock(b *ethchain.Block) {
+func (self *BlockPool) SetBlock(b *ethchain.Block, peer *Peer) {
hash := string(b.Hash())
- if self.pool[string(hash)] == nil {
- self.pool[hash] = &block{nil, nil}
+ if self.pool[hash] == nil && !self.eth.BlockChain().HasBlock(b.Hash()) {
+ self.hashPool = append(self.hashPool, b.Hash())
+ self.pool[hash] = &block{peer, b}
+ } else if self.pool[hash] != nil {
+ self.pool[hash].block = b
}
-
- self.pool[hash].block = b
}
-func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool {
- self.mut.Lock()
- defer self.mut.Unlock()
-
- if self.IsLinked() {
- for i, hash := range self.hashPool {
- block := self.pool[string(hash)].block
- if block != nil {
- f(block)
+func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) {
- delete(self.pool, string(hash))
- } else {
- self.hashPool = self.hashPool[i:]
-
- return false
- }
+ var blocks ethchain.Blocks
+ for _, item := range self.pool {
+ if item.block != nil {
+ blocks = append(blocks, item.block)
}
-
- return true
}
- return false
-}
+ ethchain.BlockBy(ethchain.Number).Sort(blocks)
+ for _, block := range blocks {
+ if self.eth.BlockChain().HasBlock(block.PrevHash) {
+ f(block)
-func (self *BlockPool) IsLinked() bool {
- if len(self.hashPool) == 0 {
- return false
- }
+ hash := block.Hash()
+ self.hashPool = ethutil.DeleteFromByteSlice(self.hashPool, hash)
+ delete(self.pool, string(hash))
+ }
- block := self.pool[string(self.hashPool[0])].block
- if block != nil {
- return self.eth.BlockChain().HasBlock(block.PrevHash)
}
-
- return false
}
func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) {
@@ -104,7 +94,7 @@ func (self *BlockPool) Take(amount int, peer *Peer) (hashes [][]byte) {
j := 0
for i := 0; i < len(self.hashPool) && j < num; i++ {
hash := string(self.hashPool[i])
- if self.pool[hash].peer == nil || self.pool[hash].peer == peer {
+ if self.pool[hash] != nil && (self.pool[hash].peer == nil || self.pool[hash].peer == peer) && self.pool[hash].block == nil {
self.pool[hash].peer = peer
hashes = append(hashes, self.hashPool[i])
diff --git a/ethchain/block.go b/ethchain/block.go
index 5765abd51..157be2a52 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"math/big"
+ "sort"
_ "strconv"
"time"
@@ -31,11 +32,45 @@ func (bi *BlockInfo) RlpEncode() []byte {
return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
}
+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 []byte
+ PrevHash ethutil.Bytes
// Uncles of this block
- Uncles []*Block
+ Uncles Blocks
UncleSha []byte
// The coin base address
Coinbase []byte
@@ -57,7 +92,7 @@ type Block struct {
// Extra data
Extra string
// Block Nonce for verification
- Nonce []byte
+ Nonce ethutil.Bytes
// List of transactions and/or contracts
transactions []*Transaction
receipts []*Receipt
@@ -106,8 +141,9 @@ func CreateBlock(root interface{},
}
// Returns a hash of the block
-func (block *Block) Hash() []byte {
- return ethcrypto.Sha3Bin(block.Value().Encode())
+func (block *Block) Hash() ethutil.Bytes {
+ return ethcrypto.Sha3Bin(ethutil.NewValue(block.header()).Encode())
+ //return ethcrypto.Sha3Bin(block.Value().Encode())
}
func (block *Block) HashNoNonce() []byte {
@@ -351,7 +387,7 @@ func (block *Block) header() []interface{} {
func (block *Block) String() string {
return fmt.Sprintf(`
- BLOCK(%x):
+ BLOCK(%x): Size: %v
PrevHash: %x
UncleSha: %x
Coinbase: %x
@@ -368,6 +404,7 @@ func (block *Block) String() string {
NumTx: %v
`,
block.Hash(),
+ block.Size(),
block.PrevHash,
block.UncleSha,
block.Coinbase,
@@ -384,3 +421,7 @@ func (block *Block) String() string {
len(block.transactions),
)
}
+
+func (self *Block) Size() ethutil.StorageSize {
+ return ethutil.StorageSize(len(self.RlpEncode()))
+}
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
index 3445bbb87..7c9b60fc5 100644
--- a/ethchain/block_chain.go
+++ b/ethchain/block_chain.go
@@ -2,12 +2,10 @@ package ethchain
import (
"bytes"
- "math"
"math/big"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
- "github.com/ethereum/eth-go/ethwire"
)
var chainlogger = ethlog.NewLogger("CHAIN")
@@ -60,24 +58,20 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
block.MinGasPrice = big.NewInt(10000000000000)
- if bc.CurrentBlock != nil {
- var mul *big.Int
- if block.Time < lastBlockTime+42 {
- mul = big.NewInt(1)
+ parent := bc.CurrentBlock
+ if parent != nil {
+ diff := new(big.Int)
+
+ adjust := new(big.Int).Rsh(parent.Difficulty, 10)
+ if block.Time >= lastBlockTime+5 {
+ diff.Sub(parent.Difficulty, adjust)
} else {
- mul = big.NewInt(-1)
+ diff.Add(parent.Difficulty, adjust)
}
-
- diff := new(big.Int)
- diff.Add(diff, bc.CurrentBlock.Difficulty)
- diff.Div(diff, big.NewInt(1024))
- diff.Mul(diff, mul)
- diff.Add(diff, bc.CurrentBlock.Difficulty)
block.Difficulty = diff
-
block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
-
block.GasLimit = block.CalcGasLimit(bc.CurrentBlock)
+
}
return block
@@ -110,99 +104,6 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int {
return blockDiff
}
-func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool {
- var blocks []*Block
- for i := 0; i < (msg.Data.Len() - 1); i++ {
- block := NewBlockFromRlpValue(msg.Data.Get(i))
- blocks = append(blocks, block)
- }
- return bc.FindCanonicalChain(blocks, commonBlockHash)
-}
-
-// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one
-// Return true if we are the using the canonical chain false if not
-func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool {
- // 1. Calculate TD of the current chain
- // 2. Calculate TD of the new chain
- // Reset state to the correct one
-
- chainDifficulty := new(big.Int)
-
- // Calculate the entire chain until the block we both have
- // Start with the newest block we got, all the way back to the common block we both know
- for _, block := range blocks {
- if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
- chainlogger.Infoln("We have found the common parent block, breaking")
- break
- }
- chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block))
- }
-
- chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty)
-
- curChainDifficulty := new(big.Int)
- block := bc.CurrentBlock
- for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) {
- i++
- if bytes.Compare(block.Hash(), commonBlockHash) == 0 {
- chainlogger.Infoln("Found the common parent block")
- break
- }
- anOtherBlock := bc.GetBlock(block.PrevHash)
- if anOtherBlock == nil {
- // We do not want to count the genesis block for difficulty since that's not being sent
- chainlogger.Infoln("Found genesis block. Stop")
- break
- }
- curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block))
- }
-
- chainlogger.Infoln("Current chain difficulty:", curChainDifficulty)
- if chainDifficulty.Cmp(curChainDifficulty) == 1 {
- chainlogger.Infof("Resetting to block %x. Changing chain.")
- bc.ResetTillBlockHash(commonBlockHash)
- return false
- } else {
- chainlogger.Infoln("Current chain is longest chain. Ignoring incoming chain.")
- return true
- }
-}
-func (bc *BlockChain) ResetTillBlockHash(hash []byte) error {
- lastBlock := bc.CurrentBlock
- var returnTo *Block
- // Reset to Genesis if that's all the origin there is.
- if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 {
- returnTo = bc.genesisBlock
- bc.CurrentBlock = bc.genesisBlock
- bc.LastBlockHash = bc.genesisBlock.Hash()
- bc.LastBlockNumber = 1
- } else {
- returnTo = bc.GetBlock(hash)
- bc.CurrentBlock = returnTo
- bc.LastBlockHash = returnTo.Hash()
- bc.LastBlockNumber = returnTo.Number.Uint64()
- }
-
- // Manually reset the last sync block
- err := ethutil.Config.Db.Delete(lastBlock.Hash())
- if err != nil {
- return err
- }
-
- var block *Block
- for ; block != nil; block = bc.GetBlock(block.PrevHash) {
- if bytes.Compare(block.Hash(), hash) == 0 {
- chainlogger.Infoln("We have arrived at the the common parent block, breaking")
- break
- }
- err = ethutil.Config.Db.Delete(block.Hash())
- if err != nil {
- return err
- }
- }
- chainlogger.Infoln("Split chain deleted and reverted to common parent block.")
- return nil
-}
func (bc *BlockChain) GenesisBlock() *Block {
return bc.genesisBlock
@@ -228,66 +129,6 @@ func (self *BlockChain) GetChainHashesFromHash(hash []byte, max uint64) (chain [
return
}
-// Get chain return blocks from hash up to max in RLP format
-func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} {
- var chain []interface{}
- // Get the current hash to start with
- currentHash := bc.CurrentBlock.Hash()
- // Get the last number on the block chain
- lastNumber := bc.CurrentBlock.Number.Uint64()
- // Get the parents number
- parentNumber := bc.GetBlock(hash).Number.Uint64()
- // Get the min amount. We might not have max amount of blocks
- count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max)))
- startNumber := parentNumber + count
-
- num := lastNumber
- for num > startNumber {
- num--
-
- block := bc.GetBlock(currentHash)
- if block == nil {
- break
- }
- currentHash = block.PrevHash
- }
-
- for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ {
- // Get the block of the chain
- block := bc.GetBlock(currentHash)
- if block == nil {
- chainlogger.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash)
- break
- }
-
- currentHash = block.PrevHash
-
- chain = append(chain, block.Value().Val)
-
- num--
- }
-
- return chain
-}
-
-func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block {
- genHash := bc.genesisBlock.Hash()
-
- block := bc.GetBlock(hash)
- var blocks []*Block
-
- for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) {
- blocks = append([]*Block{block}, blocks...)
-
- if bytes.Compare(genHash, block.Hash()) == 0 {
- break
- }
- i++
- }
-
- return blocks
-}
-
func AddTestNetFunds(block *Block) {
for _, addr := range []string{
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
@@ -307,6 +148,9 @@ func AddTestNetFunds(block *Block) {
}
func (bc *BlockChain) setLastBlock() {
+ // Prep genesis
+ AddTestNetFunds(bc.genesisBlock)
+
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
block := NewBlockFromBytes(data)
@@ -315,13 +159,12 @@ func (bc *BlockChain) setLastBlock() {
bc.LastBlockNumber = block.Number.Uint64()
} else {
- AddTestNetFunds(bc.genesisBlock)
-
bc.genesisBlock.state.Trie.Sync()
// Prepare the genesis block
bc.Add(bc.genesisBlock)
fk := append([]byte("bloom"), bc.genesisBlock.Hash()...)
bc.Ethereum.Db().Put(fk, make([]byte, 255))
+ bc.CurrentBlock = bc.genesisBlock
}
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
@@ -331,7 +174,7 @@ func (bc *BlockChain) setLastBlock() {
}
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
- ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes())
+ ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
bc.TD = td
}
@@ -359,10 +202,13 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block {
func (self *BlockChain) GetBlockByNumber(num uint64) *Block {
block := self.CurrentBlock
- for ; block.Number.Uint64() != num; block = self.GetBlock(block.PrevHash) {
+ for ; block != nil; block = self.GetBlock(block.PrevHash) {
+ if block.Number.Uint64() == num {
+ break
+ }
}
- if block.Number.Uint64() == 0 && num != 0 {
+ if block != nil && block.Number.Uint64() == 0 && num != 0 {
return nil
}
diff --git a/ethchain/error.go b/ethchain/error.go
index 2cf09a1ec..82949141a 100644
--- a/ethchain/error.go
+++ b/ethchain/error.go
@@ -25,6 +25,24 @@ func IsParentErr(err error) bool {
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
diff --git a/ethchain/fees.go b/ethchain/fees.go
index 743be86a2..901357439 100644
--- a/ethchain/fees.go
+++ b/ethchain/fees.go
@@ -5,5 +5,3 @@ import (
)
var BlockReward *big.Int = big.NewInt(1.5e+18)
-var UncleReward *big.Int = big.NewInt(1.125e+18)
-var UncleInclusionReward *big.Int = big.NewInt(1.875e+17)
diff --git a/ethchain/filter.go b/ethchain/filter.go
index 5ed9af977..d9f1796f4 100644
--- a/ethchain/filter.go
+++ b/ethchain/filter.go
@@ -23,6 +23,9 @@ type Filter struct {
max int
altered []data
+
+ BlockCallback func(*Block)
+ MessageCallback func(ethstate.Messages)
}
// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 08bd22d29..b0ea754f4 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -5,6 +5,7 @@ import (
"container/list"
"fmt"
"math/big"
+ "os"
"sync"
"time"
@@ -154,6 +155,10 @@ done:
if i < len(block.Receipts()) {
original := block.Receipts()[i]
if !original.Cmp(receipt) {
+ if ethutil.Config.Diff {
+ os.Exit(1)
+ }
+
return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash())
}
}
@@ -217,13 +222,13 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
return err
}
- // I'm not sure, but I don't know if there should be thrown
- // any errors at this time.
- if err = sm.AccumelateRewards(state, block); err != nil {
+ if err = sm.AccumelateRewards(state, block, parent); err != nil {
statelogger.Errorln("Error accumulating reward", err)
return err
}
+ state.Update()
+
if !block.State().Cmp(state) {
err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root)
return
@@ -237,6 +242,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
// Add the block to the chain
sm.bc.Add(block)
+ sm.transState = state.Copy()
+
// Create a bloom bin for this block
filter := sm.createBloomFilter(state)
// Persist the data
@@ -305,14 +312,16 @@ func (sm *StateManager) ValidateBlock(block *Block) error {
// Check each uncle's previous hash. In order for it to be valid
// is if it has the same block hash as the current
- previousBlock := sm.bc.GetBlock(block.PrevHash)
- for _, uncle := range block.Uncles {
- if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 {
- return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash)
+ parent := sm.bc.GetBlock(block.PrevHash)
+ /*
+ for _, uncle := range block.Uncles {
+ if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 {
+ return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash)
+ }
}
- }
+ */
- diff := block.Time - previousBlock.Time
+ 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)
}
@@ -332,36 +341,46 @@ func (sm *StateManager) ValidateBlock(block *Block) error {
return nil
}
-func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
- base := new(big.Int)
- for i := 0; i < uncleLength; i++ {
- base.Add(base, UncleInclusionReward)
- }
+func (sm *StateManager) AccumelateRewards(state *ethstate.State, block, parent *Block) error {
+ reward := new(big.Int).Set(BlockReward)
- return base.Add(base, 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")
+ }
-func CalculateUncleReward(block *Block) *big.Int {
- return UncleReward
-}
+ uncleParent := sm.bc.GetBlock(uncle.PrevHash)
+ if uncleParent == nil {
+ return UncleError("Uncle's parent unknown")
+ }
-func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error {
- // Get the account associated with the coinbase
- account := state.GetAccount(block.Coinbase)
- // Reward amount of ether to the coinbase address
- account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))
+ if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {
+ return UncleError("Uncle too old")
+ }
- addr := make([]byte, len(block.Coinbase))
- copy(addr, block.Coinbase)
- state.UpdateStateObject(account)
+ 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))
- for _, uncle := range block.Uncles {
uncleAccount := state.GetAccount(uncle.Coinbase)
- uncleAccount.AddAmount(CalculateUncleReward(uncle))
+ uncleAccount.AddAmount(r)
- state.UpdateStateObject(uncleAccount)
+ reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
}
+ // Get the account associated with the coinbase
+ account := state.GetAccount(block.Coinbase)
+ // Reward amount of ether to the coinbase address
+ account.AddAmount(reward)
+
return nil
}
@@ -373,14 +392,6 @@ func (sm *StateManager) Stop() {
func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
bloomf := NewBloomFilter(nil)
- /*
- for addr, stateObject := range state.Manifest().ObjectChanges {
- // Set the bloom filter's bin
- bloomf.Set([]byte(addr))
-
- sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
- }
- */
for _, msg := range state.Manifest().Messages {
bloomf.Set(msg.To)
bloomf.Set(msg.From)
@@ -388,17 +399,6 @@ func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages)
- /*
- for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
- for addr, value := range mappedObjects {
- // Set the bloom filter's bin
- bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr)))
-
- sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
- }
- }
- */
-
return bloomf
}
@@ -418,7 +418,7 @@ func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message,
sm.ApplyDiff(state, parent, block)
- sm.AccumelateRewards(state, block)
+ sm.AccumelateRewards(state, block, parent)
return state.Manifest().Messages, nil
}
diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go
index 9fbc160a5..c1180a641 100644
--- a/ethchain/state_transition.go
+++ b/ethchain/state_transition.go
@@ -140,7 +140,7 @@ func (self *StateTransition) preCheck() (err error) {
}
func (self *StateTransition) TransitionState() (err error) {
- statelogger.Infof("(~) %x\n", self.tx.Hash())
+ statelogger.Debugf("(~) %x\n", self.tx.Hash())
/*
defer func() {
@@ -278,6 +278,15 @@ func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context
ret, _, err = callerClosure.Call(vm, self.tx.Data)
+ if err == nil {
+ // Execute POSTs
+ for e := vm.Queue().Front(); e != nil; e = e.Next() {
+ msg := e.Value.(*ethvm.Message)
+
+ msg.Exec(msg.Addr(), transactor)
+ }
+ }
+
return
}
diff --git a/ethchain/transaction.go b/ethchain/transaction.go
index e1b48a3d3..e7e8f3a9f 100644
--- a/ethchain/transaction.go
+++ b/ethchain/transaction.go
@@ -13,7 +13,8 @@ import (
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 bytes.Compare(addr, ContractAddr) == 0
+ return len(addr) == 0
+ //return bytes.Compare(addr, ContractAddr) == 0
}
type Transaction struct {
@@ -31,7 +32,7 @@ type Transaction struct {
}
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
- return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true}
+ 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 {
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
index b0d62fd91..9a6322432 100644
--- a/ethchain/transaction_pool.go
+++ b/ethchain/transaction_pool.go
@@ -72,8 +72,6 @@ type TxPool struct {
func NewTxPool(ethereum EthManager) *TxPool {
return &TxPool{
- //server: s,
- mutex: sync.Mutex{},
pool: list.New(),
queueChan: make(chan *Transaction, txPoolQueueSize),
quit: make(chan bool),
@@ -101,7 +99,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
return fmt.Errorf("[TXPL] No last block on the block chain")
}
- if len(tx.Recipient) != 20 {
+ if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 {
return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient))
}
@@ -150,7 +148,10 @@ out:
// Call blocking version.
pool.addTransaction(tx)
- txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash())
+ 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
pool.Ethereum.Reactor().Post("newTx:pre", tx)
diff --git a/ethchain/types.go b/ethchain/types.go
index 9e7269f74..45486b06c 100644
--- a/ethchain/types.go
+++ b/ethchain/types.go
@@ -27,10 +27,12 @@ const (
NOT = 0x0f
// 0x10 range - bit ops
- AND = 0x10
- OR = 0x11
- XOR = 0x12
- BYTE = 0x13
+ AND = 0x10
+ OR = 0x11
+ XOR = 0x12
+ BYTE = 0x13
+ ADDMOD = 0x14
+ MULMOD = 0x15
// 0x20 range - crypto
SHA3 = 0x20
@@ -47,6 +49,8 @@ const (
CODESIZE = 0x38
CODECOPY = 0x39
GASPRICE = 0x3a
+ EXTCODECOPY = 0x3b
+ EXTCODESIZE = 0x3c
// 0x40 range - block operations
PREVHASH = 0x40
@@ -57,9 +61,9 @@ const (
GASLIMIT = 0x45
// 0x50 range - 'storage' and execution
- POP = 0x50
- DUP = 0x51
- SWAP = 0x52
+ POP = 0x50
+ //DUP = 0x51
+ //SWAP = 0x52
MLOAD = 0x53
MSTORE = 0x54
MSTORE8 = 0x55
@@ -105,10 +109,46 @@ const (
PUSH31 = 0x7e
PUSH32 = 0x7f
+ DUP1 = 0x80
+ DUP2 = 0x81
+ DUP3 = 0x82
+ DUP4 = 0x83
+ DUP5 = 0x84
+ DUP6 = 0x85
+ DUP7 = 0x86
+ DUP8 = 0x87
+ DUP9 = 0x88
+ DUP10 = 0x89
+ DUP11 = 0x8a
+ DUP12 = 0x8b
+ DUP13 = 0x8c
+ DUP14 = 0x8d
+ DUP15 = 0x8e
+ DUP16 = 0x8f
+
+ SWAP1 = 0x90
+ SWAP2 = 0x91
+ SWAP3 = 0x92
+ SWAP4 = 0x93
+ SWAP5 = 0x94
+ SWAP6 = 0x95
+ SWAP7 = 0x96
+ SWAP8 = 0x97
+ SWAP9 = 0x98
+ SWAP10 = 0x99
+ SWAP11 = 0x9a
+ SWAP12 = 0x9b
+ SWAP13 = 0x9c
+ SWAP14 = 0x9d
+ SWAP15 = 0x9e
+ SWAP16 = 0x9f
+
// 0xf0 range - closures
- CREATE = 0xf0
- CALL = 0xf1
- RETURN = 0xf2
+ CREATE = 0xf0
+ CALL = 0xf1
+ RETURN = 0xf2
+ POST = 0xf3
+ CALLSTATELESS = 0xf4
// 0x70 range - other
LOG = 0xfe // XXX Unofficial
@@ -136,10 +176,12 @@ var opCodeToString = map[OpCode]string{
NOT: "NOT",
// 0x10 range - bit ops
- AND: "AND",
- OR: "OR",
- XOR: "XOR",
- BYTE: "BYTE",
+ AND: "AND",
+ OR: "OR",
+ XOR: "XOR",
+ BYTE: "BYTE",
+ ADDMOD: "ADDMOD",
+ MULMOD: "MULMOD",
// 0x20 range - crypto
SHA3: "SHA3",
@@ -158,17 +200,19 @@ var opCodeToString = map[OpCode]string{
GASPRICE: "TXGASPRICE",
// 0x40 range - block operations
- PREVHASH: "PREVHASH",
- COINBASE: "COINBASE",
- TIMESTAMP: "TIMESTAMP",
- NUMBER: "NUMBER",
- DIFFICULTY: "DIFFICULTY",
- GASLIMIT: "GASLIMIT",
+ PREVHASH: "PREVHASH",
+ COINBASE: "COINBASE",
+ TIMESTAMP: "TIMESTAMP",
+ NUMBER: "NUMBER",
+ DIFFICULTY: "DIFFICULTY",
+ GASLIMIT: "GASLIMIT",
+ EXTCODESIZE: "EXTCODESIZE",
+ EXTCODECOPY: "EXTCODECOPY",
// 0x50 range - 'storage' and execution
- POP: "POP",
- DUP: "DUP",
- SWAP: "SWAP",
+ POP: "POP",
+ //DUP: "DUP",
+ //SWAP: "SWAP",
MLOAD: "MLOAD",
MSTORE: "MSTORE",
MSTORE8: "MSTORE8",
@@ -214,10 +258,46 @@ var opCodeToString = map[OpCode]string{
PUSH31: "PUSH31",
PUSH32: "PUSH32",
+ DUP1: "DUP1",
+ DUP2: "DUP2",
+ DUP3: "DUP3",
+ DUP4: "DUP4",
+ DUP5: "DUP5",
+ DUP6: "DUP6",
+ DUP7: "DUP7",
+ DUP8: "DUP8",
+ DUP9: "DUP9",
+ DUP10: "DUP10",
+ DUP11: "DUP11",
+ DUP12: "DUP12",
+ DUP13: "DUP13",
+ DUP14: "DUP14",
+ DUP15: "DUP15",
+ DUP16: "DUP16",
+
+ SWAP1: "SWAP1",
+ SWAP2: "SWAP2",
+ SWAP3: "SWAP3",
+ SWAP4: "SWAP4",
+ SWAP5: "SWAP5",
+ SWAP6: "SWAP6",
+ SWAP7: "SWAP7",
+ SWAP8: "SWAP8",
+ SWAP9: "SWAP9",
+ SWAP10: "SWAP10",
+ SWAP11: "SWAP11",
+ SWAP12: "SWAP12",
+ SWAP13: "SWAP13",
+ SWAP14: "SWAP14",
+ SWAP15: "SWAP15",
+ SWAP16: "SWAP16",
+
// 0xf0 range
- CREATE: "CREATE",
- CALL: "CALL",
- RETURN: "RETURN",
+ CREATE: "CREATE",
+ CALL: "CALL",
+ RETURN: "RETURN",
+ POST: "POST",
+ CALLSTATELESS: "CALLSTATELESS",
// 0x70 range - other
LOG: "LOG",
@@ -232,115 +312,3 @@ func (o OpCode) String() string {
return str
}
-
-// Op codes for assembling
-var OpCodes = map[string]byte{
- // 0x0 range - arithmetic ops
- "STOP": 0x00,
- "ADD": 0x01,
- "MUL": 0x02,
- "SUB": 0x03,
- "DIV": 0x04,
- "SDIV": 0x05,
- "MOD": 0x06,
- "SMOD": 0x07,
- "EXP": 0x08,
- "NEG": 0x09,
- "LT": 0x0a,
- "GT": 0x0b,
- "EQ": 0x0c,
- "NOT": 0x0d,
-
- // 0x10 range - bit ops
- "AND": 0x10,
- "OR": 0x11,
- "XOR": 0x12,
- "BYTE": 0x13,
-
- // 0x20 range - crypto
- "SHA3": 0x20,
-
- // 0x30 range - closure state
- "ADDRESS": 0x30,
- "BALANCE": 0x31,
- "ORIGIN": 0x32,
- "CALLER": 0x33,
- "CALLVALUE": 0x34,
- "CALLDATALOAD": 0x35,
- "CALLDATASIZE": 0x36,
- "GASPRICE": 0x38,
-
- // 0x40 range - block operations
- "PREVHASH": 0x40,
- "COINBASE": 0x41,
- "TIMESTAMP": 0x42,
- "NUMBER": 0x43,
- "DIFFICULTY": 0x44,
- "GASLIMIT": 0x45,
-
- // 0x50 range - 'storage' and execution
- "POP": 0x51,
- "DUP": 0x52,
- "SWAP": 0x53,
- "MLOAD": 0x54,
- "MSTORE": 0x55,
- "MSTORE8": 0x56,
- "SLOAD": 0x57,
- "SSTORE": 0x58,
- "JUMP": 0x59,
- "JUMPI": 0x5a,
- "PC": 0x5b,
- "MSIZE": 0x5c,
-
- // 0x70 range - 'push'
- "PUSH1": 0x60,
- "PUSH2": 0x61,
- "PUSH3": 0x62,
- "PUSH4": 0x63,
- "PUSH5": 0x64,
- "PUSH6": 0x65,
- "PUSH7": 0x66,
- "PUSH8": 0x67,
- "PUSH9": 0x68,
- "PUSH10": 0x69,
- "PUSH11": 0x6a,
- "PUSH12": 0x6b,
- "PUSH13": 0x6c,
- "PUSH14": 0x6d,
- "PUSH15": 0x6e,
- "PUSH16": 0x6f,
- "PUSH17": 0x70,
- "PUSH18": 0x71,
- "PUSH19": 0x72,
- "PUSH20": 0x73,
- "PUSH21": 0x74,
- "PUSH22": 0x75,
- "PUSH23": 0x76,
- "PUSH24": 0x77,
- "PUSH25": 0x78,
- "PUSH26": 0x70,
- "PUSH27": 0x7a,
- "PUSH28": 0x7b,
- "PUSH29": 0x7c,
- "PUSH30": 0x7d,
- "PUSH31": 0x7e,
- "PUSH32": 0x7f,
-
- // 0xf0 range - closures
- "CREATE": 0xf0,
- "CALL": 0xf1,
- "RETURN": 0xf2,
-
- // 0x70 range - other
- "LOG": 0xfe,
- "SUICIDE": 0x7f,
-}
-
-func IsOpCode(s string) bool {
- for key, _ := range OpCodes {
- if key == s {
- return true
- }
- }
- return false
-}
diff --git a/ethcrypto/crypto_test.go b/ethcrypto/crypto_test.go
new file mode 100644
index 000000000..7323e1646
--- /dev/null
+++ b/ethcrypto/crypto_test.go
@@ -0,0 +1,17 @@
+package ethcrypto
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/ethereum/eth-go/ethutil"
+)
+
+// FIPS 202 test (reverted back to FIPS 180)
+func TestSha3(t *testing.T) {
+ const exp = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"
+ sha3_256 := Sha3Bin([]byte("abc"))
+ if bytes.Compare(sha3_256, ethutil.Hex2Bytes(exp)) != 0 {
+ t.Errorf("Sha3_256 failed. Incorrect result %x", sha3_256)
+ }
+}
diff --git a/ethdb/database.go b/ethdb/database.go
index 09e9d8c7d..e4b069930 100644
--- a/ethdb/database.go
+++ b/ethdb/database.go
@@ -2,9 +2,10 @@ package ethdb
import (
"fmt"
+ "path"
+
"github.com/ethereum/eth-go/ethutil"
"github.com/syndtr/goleveldb/leveldb"
- "path"
)
type LDBDatabase struct {
@@ -45,7 +46,7 @@ func (db *LDBDatabase) Db() *leveldb.DB {
}
func (db *LDBDatabase) LastKnownTD() []byte {
- data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil)
+ data, _ := db.db.Get([]byte("LTD"), nil)
if len(data) == 0 {
data = []byte{0x0}
@@ -54,14 +55,6 @@ func (db *LDBDatabase) LastKnownTD() []byte {
return data
}
-/*
-func (db *LDBDatabase) GetKeys() []*ethutil.Key {
- data, _ := db.Get([]byte("KeyRing"))
-
- return []*ethutil.Key{ethutil.NewKeyFromBytes(data)}
-}
-*/
-
func (db *LDBDatabase) Close() {
// Close the leveldb database
db.db.Close()
diff --git a/ethereum.go b/ethereum.go
index 1e1891589..79e722c26 100644
--- a/ethereum.go
+++ b/ethereum.go
@@ -2,9 +2,11 @@ package eth
import (
"container/list"
+ "encoding/json"
"fmt"
"math/rand"
"net"
+ "path"
"strconv"
"strings"
"sync"
@@ -16,13 +18,14 @@ import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethrpc"
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
)
const (
seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt"
- seedNodeAddress = "54.76.56.74:30303"
+ seedNodeAddress = "poc-6.ethdev.com:30303"
)
var ethlogger = ethlog.NewLogger("SERV")
@@ -30,9 +33,7 @@ var ethlogger = ethlog.NewLogger("SERV")
func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) {
// Loop thru the peers and close them (if we had them)
for e := peers.Front(); e != nil; e = e.Next() {
- if peer, ok := e.Value.(*Peer); ok {
- callback(peer, e)
- }
+ callback(e.Value.(*Peer), e)
}
}
@@ -87,10 +88,11 @@ type Ethereum struct {
clientIdentity ethwire.ClientIdentity
isUpToDate bool
+
+ filters map[int]*ethchain.Filter
}
func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) {
-
var err error
var nat NAT
@@ -101,6 +103,8 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
}
}
+ bootstrapDb(db)
+
ethutil.Config.Db = db
nonce, _ := ethutil.RandomUint64()
@@ -115,6 +119,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
keyManager: keyManager,
clientIdentity: clientIdentity,
isUpToDate: true,
+ filters: make(map[int]*ethchain.Filter),
}
ethereum.reactor = ethreact.New()
@@ -385,6 +390,7 @@ func (s *Ethereum) Start(seed bool) {
// Start the reaping processes
go s.ReapDeadPeerHandler()
go s.update()
+ go s.filterLoop()
if seed {
s.Seed()
@@ -393,47 +399,55 @@ func (s *Ethereum) Start(seed bool) {
}
func (s *Ethereum) Seed() {
- ethlogger.Debugln("Retrieving seed nodes")
-
- // Eth-Go Bootstrapping
- ips, er := net.LookupIP("seed.bysh.me")
- if er == nil {
- peers := []string{}
+ ips := PastPeers()
+ if len(ips) > 0 {
for _, ip := range ips {
- node := fmt.Sprintf("%s:%d", ip.String(), 30303)
- ethlogger.Debugln("Found DNS Go Peer:", node)
- peers = append(peers, node)
+ ethlogger.Infoln("Connecting to previous peer ", ip)
+ s.ConnectToPeer(ip)
+ }
+ } else {
+ ethlogger.Debugln("Retrieving seed nodes")
+
+ // Eth-Go Bootstrapping
+ ips, er := net.LookupIP("seed.bysh.me")
+ if er == nil {
+ peers := []string{}
+ for _, ip := range ips {
+ node := fmt.Sprintf("%s:%d", ip.String(), 30303)
+ ethlogger.Debugln("Found DNS Go Peer:", node)
+ peers = append(peers, node)
+ }
+ s.ProcessPeerList(peers)
}
- s.ProcessPeerList(peers)
- }
- // Official DNS Bootstrapping
- _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
- if err == nil {
- peers := []string{}
- // Iterate SRV nodes
- for _, n := range nodes {
- target := n.Target
- port := strconv.Itoa(int(n.Port))
- // Resolve target to ip (Go returns list, so may resolve to multiple ips?)
- addr, err := net.LookupHost(target)
- if err == nil {
- for _, a := range addr {
- // Build string out of SRV port and Resolved IP
- peer := net.JoinHostPort(a, port)
- ethlogger.Debugln("Found DNS Bootstrap Peer:", peer)
- peers = append(peers, peer)
+ // Official DNS Bootstrapping
+ _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
+ if err == nil {
+ peers := []string{}
+ // Iterate SRV nodes
+ for _, n := range nodes {
+ target := n.Target
+ port := strconv.Itoa(int(n.Port))
+ // Resolve target to ip (Go returns list, so may resolve to multiple ips?)
+ addr, err := net.LookupHost(target)
+ if err == nil {
+ for _, a := range addr {
+ // Build string out of SRV port and Resolved IP
+ peer := net.JoinHostPort(a, port)
+ ethlogger.Debugln("Found DNS Bootstrap Peer:", peer)
+ peers = append(peers, peer)
+ }
+ } else {
+ ethlogger.Debugln("Couldn't resolve :", target)
}
- } else {
- ethlogger.Debugln("Couldn't resolve :", target)
}
+ // Connect to Peer list
+ s.ProcessPeerList(peers)
}
- // Connect to Peer list
- s.ProcessPeerList(peers)
- }
- // XXX tmp
- s.ConnectToPeer(seedNodeAddress)
+ // XXX tmp
+ s.ConnectToPeer(seedNodeAddress)
+ }
}
func (s *Ethereum) peerHandler(listener net.Listener) {
@@ -453,6 +467,16 @@ func (s *Ethereum) Stop() {
// Close the database
defer s.db.Close()
+ var ips []string
+ eachPeer(s.peers, func(p *Peer, e *list.Element) {
+ ips = append(ips, p.conn.RemoteAddr().String())
+ })
+
+ if len(ips) > 0 {
+ d, _ := json.MarshalIndent(ips, "", " ")
+ ethutil.WriteFile(path.Join(ethutil.Config.ExecPath, "known_peers.json"), d)
+ }
+
eachPeer(s.peers, func(p *Peer, e *list.Element) {
p.Stop()
})
@@ -534,3 +558,74 @@ out:
}
}
}
+
+var filterId = 0
+
+func (self *Ethereum) InstallFilter(object map[string]interface{}) (*ethchain.Filter, int) {
+ defer func() { filterId++ }()
+
+ filter := ethchain.NewFilterFromMap(object, self)
+ self.filters[filterId] = filter
+
+ return filter, filterId
+}
+
+func (self *Ethereum) UninstallFilter(id int) {
+ delete(self.filters, id)
+}
+
+func (self *Ethereum) GetFilter(id int) *ethchain.Filter {
+ return self.filters[id]
+}
+
+func (self *Ethereum) filterLoop() {
+ blockChan := make(chan ethreact.Event, 5)
+ messageChan := make(chan ethreact.Event, 5)
+ // Subscribe to events
+ reactor := self.Reactor()
+ reactor.Subscribe("newBlock", blockChan)
+ reactor.Subscribe("messages", messageChan)
+out:
+ for {
+ select {
+ case <-self.quit:
+ break out
+ case block := <-blockChan:
+ if block, ok := block.Resource.(*ethchain.Block); ok {
+ for _, filter := range self.filters {
+ if filter.BlockCallback != nil {
+ filter.BlockCallback(block)
+ }
+ }
+ }
+ case msg := <-messageChan:
+ if messages, ok := msg.Resource.(ethstate.Messages); ok {
+ for _, filter := range self.filters {
+ if filter.MessageCallback != nil {
+ msgs := filter.FilterMessages(messages)
+ if len(msgs) > 0 {
+ filter.MessageCallback(msgs)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func bootstrapDb(db ethutil.Database) {
+ d, _ := db.Get([]byte("ProtocolVersion"))
+ protov := ethutil.NewValue(d).Uint()
+
+ if protov == 0 {
+ db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
+ }
+}
+
+func PastPeers() []string {
+ var ips []string
+ data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "known_peers.json"))
+ json.Unmarshal([]byte(data), &ips)
+
+ return ips
+}
diff --git a/ethminer/miner.go b/ethminer/miner.go
index 799db79f1..083d9ecde 100644
--- a/ethminer/miner.go
+++ b/ethminer/miner.go
@@ -187,7 +187,7 @@ func (self *Miner) mineNewBlock() {
self.block.SetReceipts(receipts, txs)
// Accumulate the rewards included for this block
- stateManager.AccumelateRewards(self.block.State(), self.block)
+ stateManager.AccumelateRewards(self.block.State(), self.block, parent)
self.block.State().Update()
diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go
index b32e94a10..96990b671 100644
--- a/ethpipe/js_pipe.go
+++ b/ethpipe/js_pipe.go
@@ -3,12 +3,10 @@ package ethpipe
import (
"bytes"
"encoding/json"
- "fmt"
"sync/atomic"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto"
- "github.com/ethereum/eth-go/ethreact"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
)
@@ -87,10 +85,6 @@ func (self *JSPipe) CoinBase() string {
return ethutil.Bytes2Hex(self.obj.KeyManager().Address())
}
-func (self *JSPipe) BalanceAt(addr string) string {
- return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance.String()
-}
-
func (self *JSPipe) NumberToHuman(balance string) string {
b := ethutil.Big(balance)
@@ -99,13 +93,22 @@ func (self *JSPipe) NumberToHuman(balance string) string {
func (self *JSPipe) StorageAt(addr, storageAddr string) string {
storage := self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr))
- return storage.BigInt().String()
+
+ return ethutil.Bytes2Hex(storage.Bytes())
+}
+
+func (self *JSPipe) BalanceAt(addr string) string {
+ return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance.String()
}
func (self *JSPipe) TxCountAt(address string) int {
return int(self.World().SafeGet(ethutil.Hex2Bytes(address)).Nonce)
}
+func (self *JSPipe) CodeAt(address string) string {
+ return ethutil.Bytes2Hex(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code)
+}
+
func (self *JSPipe) IsContract(address string) bool {
return len(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) > 0
}
@@ -119,6 +122,18 @@ func (self *JSPipe) SecretToAddress(key string) string {
return ethutil.Bytes2Hex(pair.Address())
}
+func (self *JSPipe) Execute(addr, value, gas, price, data string) (string, error) {
+ ret, err := self.ExecuteObject(&Object{
+ self.World().safeGet(ethutil.Hex2Bytes(addr))},
+ ethutil.Hex2Bytes(data),
+ ethutil.NewValue(value),
+ ethutil.NewValue(gas),
+ ethutil.NewValue(price),
+ )
+
+ return ethutil.Bytes2Hex(ret), err
+}
+
type KeyVal struct {
Key string `json:"key"`
Value string `json:"value"`
@@ -224,6 +239,12 @@ func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr
return NewJSReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil
}
+func (self *JSPipe) PushTx(txStr string) (*JSReceipt, error) {
+ tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr))
+ self.obj.TxPool().QueueTransaction(tx)
+ return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(), tx.Hash(), tx.Sender()), nil
+}
+
func (self *JSPipe) CompileMutan(code string) string {
data, err := self.Pipe.CompileMutan(code)
if err != nil {
@@ -233,102 +254,11 @@ func (self *JSPipe) CompileMutan(code string) string {
return ethutil.Bytes2Hex(data)
}
-func (self *JSPipe) Watch(object map[string]interface{}) *JSFilter {
- return NewJSFilterFromMap(object, self.Pipe.obj)
- /*} else if str, ok := object.(string); ok {
- println("str")
- return NewJSFilterFromString(str, self.Pipe.obj)
- */
-}
-
-func (self *JSPipe) Messages(object map[string]interface{}) string {
- filter := self.Watch(object)
- filter.Uninstall()
-
- return filter.Messages()
-
-}
-
-type JSFilter struct {
- eth ethchain.EthManager
- *ethchain.Filter
- quit chan bool
-
- BlockCallback func(*ethchain.Block)
- MessageCallback func(ethstate.Messages)
-}
-
-func NewJSFilterFromMap(object map[string]interface{}, eth ethchain.EthManager) *JSFilter {
- filter := &JSFilter{eth, ethchain.NewFilterFromMap(object, eth), make(chan bool), nil, nil}
-
- go filter.mainLoop()
-
- return filter
-}
-
-func NewJSFilterFromString(str string, eth ethchain.EthManager) *JSFilter {
- return nil
-}
-
-func (self *JSFilter) MessagesToJson(messages ethstate.Messages) string {
+func ToJSMessages(messages ethstate.Messages) *ethutil.List {
var msgs []JSMessage
for _, m := range messages {
msgs = append(msgs, NewJSMessage(m))
}
- // Return an empty array instead of "null"
- if len(msgs) == 0 {
- return "[]"
- }
-
- b, err := json.Marshal(msgs)
- if err != nil {
- return "{\"error\":" + err.Error() + "}"
- }
-
- return string(b)
-}
-
-func (self *JSFilter) Messages() string {
- return self.MessagesToJson(self.Find())
-}
-
-func (self *JSFilter) mainLoop() {
- blockChan := make(chan ethreact.Event, 5)
- messageChan := make(chan ethreact.Event, 5)
- // Subscribe to events
- reactor := self.eth.Reactor()
- reactor.Subscribe("newBlock", blockChan)
- reactor.Subscribe("messages", messageChan)
-out:
- for {
- select {
- case <-self.quit:
- break out
- case block := <-blockChan:
- if block, ok := block.Resource.(*ethchain.Block); ok {
- if self.BlockCallback != nil {
- self.BlockCallback(block)
- }
- }
- case msg := <-messageChan:
- if messages, ok := msg.Resource.(ethstate.Messages); ok {
- if self.MessageCallback != nil {
- println("messages!")
- msgs := self.FilterMessages(messages)
- if len(msgs) > 0 {
- self.MessageCallback(msgs)
- }
- }
- }
- }
- }
-}
-
-func (self *JSFilter) Changed(object interface{}) {
- fmt.Printf("%T\n", object)
-}
-
-func (self *JSFilter) Uninstall() {
- self.quit <- true
+ return ethutil.NewList(msgs)
}
diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go
index 0fb3a3876..8d2805f3d 100644
--- a/ethpipe/js_types.go
+++ b/ethpipe/js_types.go
@@ -1,7 +1,6 @@
package ethpipe
import (
- "encoding/json"
"strconv"
"strings"
@@ -13,15 +12,17 @@ import (
// Block interface exposed to QML
type JSBlock struct {
+ //Transactions string `json:"transactions"`
ref *ethchain.Block
- Number int `json:"number"`
- Hash string `json:"hash"`
- Transactions string `json:"transactions"`
- Time int64 `json:"time"`
- Coinbase string `json:"coinbase"`
- Name string `json:"name"`
- GasLimit string `json:"gasLimit"`
- GasUsed string `json:"gasUsed"`
+ Size string `json:"size"`
+ Number int `json:"number"`
+ Hash string `json:"hash"`
+ Transactions *ethutil.List `json:"transactions"`
+ Time int64 `json:"time"`
+ Coinbase string `json:"coinbase"`
+ Name string `json:"name"`
+ GasLimit string `json:"gasLimit"`
+ GasUsed string `json:"gasUsed"`
}
// Creates a new QML Block from a chain block
@@ -35,12 +36,16 @@ func NewJSBlock(block *ethchain.Block) *JSBlock {
ptxs = append(ptxs, *NewJSTx(tx))
}
- txJson, err := json.Marshal(ptxs)
- if err != nil {
- return nil
- }
+ /*
+ txJson, err := json.Marshal(ptxs)
+ if err != nil {
+ return nil
+ }
+ return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)}
+ */
+ list := ethutil.NewList(ptxs)
- return &JSBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)}
+ return &JSBlock{ref: block, Size: block.Size().String(), Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: list, Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)}
}
func (self *JSBlock) ToString() string {
diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go
index 800a71139..7c3f491d3 100644
--- a/ethpipe/pipe.go
+++ b/ethpipe/pipe.go
@@ -1,6 +1,7 @@
package ethpipe
import (
+ "fmt"
"strings"
"github.com/ethereum/eth-go/ethchain"
@@ -51,18 +52,19 @@ func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.V
func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) {
var (
- initiator = ethstate.NewStateObject([]byte{0})
- block = self.blockChain.CurrentBlock
- stateObject = object.StateObject
+ initiator = ethstate.NewStateObject(self.obj.KeyManager().KeyPair().Address())
+ block = self.blockChain.CurrentBlock
)
- if self.Vm.State == nil {
- self.Vm.State = self.World().State().Copy()
- }
+
+ self.Vm.State = self.World().State().Copy()
vm := ethvm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address()))
+ vm.Verbose = true
+
+ msg := ethvm.NewMessage(vm, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt())
+ ret, err := msg.Exec(object.Address(), initiator)
- closure := ethvm.NewClosure(&ethstate.Message{}, initiator, stateObject, object.Code, gas.BigInt(), price.BigInt())
- ret, _, err := closure.Call(vm, data)
+ fmt.Println("returned from call", ret, err)
return ret, err
}
@@ -149,6 +151,15 @@ func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price
return tx.Hash(), nil
}
+func (self *Pipe) PushTx(tx *ethchain.Transaction) ([]byte, error) {
+ self.obj.TxPool().QueueTransaction(tx)
+ if tx.Recipient == nil {
+ logger.Infof("Contract addr %x", tx.CreationAddress())
+ return tx.CreationAddress(), nil
+ }
+ return tx.Hash(), nil
+}
+
func (self *Pipe) CompileMutan(code string) ([]byte, error) {
data, err := ethutil.Compile(code, false)
if err != nil {
diff --git a/ethreact/reactor.go b/ethreact/reactor.go
index 7fe2356db..2edcbbbd9 100644
--- a/ethreact/reactor.go
+++ b/ethreact/reactor.go
@@ -1,8 +1,9 @@
package ethreact
import (
- "github.com/ethereum/eth-go/ethlog"
"sync"
+
+ "github.com/ethereum/eth-go/ethlog"
)
var logger = ethlog.NewLogger("REACTOR")
@@ -32,7 +33,7 @@ func (e *EventHandler) Post(event Event) {
select {
case ch <- event:
default:
- logger.Warnf("subscribing channel %d to event %s blocked. skipping\n", i, event.Name)
+ logger.Debugf("subscribing channel %d to event %s blocked. skipping\n", i, event.Name)
}
}
}
diff --git a/ethrpc/packages.go b/ethrpc/packages.go
index f2e57fa49..087167a42 100644
--- a/ethrpc/packages.go
+++ b/ethrpc/packages.go
@@ -145,6 +145,27 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error {
return nil
}
+type PushTxArgs struct {
+ Tx string
+}
+
+func (a *PushTxArgs) requirementsPushTx() error {
+ if a.Tx == "" {
+ return NewErrorResponse("PushTx requires a 'tx' as argument")
+ }
+ return nil
+}
+
+func (p *EthereumApi) PushTx(args *PushTxArgs, reply *string) error {
+ err := args.requirementsPushTx()
+ if err != nil {
+ return err
+ }
+ result, _ := p.pipe.PushTx(args.Tx)
+ *reply = NewSuccessRes(result)
+ return nil
+}
+
func (p *EthereumApi) GetKey(args interface{}, reply *string) error {
*reply = NewSuccessRes(p.pipe.Key())
return nil
diff --git a/ethstate/dump.go b/ethstate/dump.go
index be60a05fc..cdd4228b8 100644
--- a/ethstate/dump.go
+++ b/ethstate/dump.go
@@ -28,7 +28,7 @@ func (self *State) Dump() []byte {
self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) {
stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes())
- account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.CodeHash)}
+ account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.codeHash)}
account.Storage = make(map[string]string)
stateObject.EachStorage(func(key string, value *ethutil.Value) {
diff --git a/ethstate/state.go b/ethstate/state.go
index cf060e795..0e87659fc 100644
--- a/ethstate/state.go
+++ b/ethstate/state.go
@@ -3,7 +3,6 @@ package ethstate
import (
"math/big"
- "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
@@ -49,6 +48,15 @@ func (self *State) GetNonce(addr []byte) uint64 {
return 0
}
+func (self *State) GetCode(addr []byte) []byte {
+ stateObject := self.GetStateObject(addr)
+ if stateObject != nil {
+ return stateObject.Code
+ }
+
+ return nil
+}
+
//
// Setting, updating & deleting state object methods
//
@@ -57,7 +65,9 @@ func (self *State) GetNonce(addr []byte) uint64 {
func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
- ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code)
+ if len(stateObject.CodeHash()) > 0 {
+ ethutil.Config.Db.Put(stateObject.CodeHash(), stateObject.Code)
+ }
self.Trie.Update(string(addr), string(stateObject.RlpEncode()))
}
@@ -103,7 +113,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
func (self *State) NewStateObject(addr []byte) *StateObject {
addr = ethutil.Address(addr)
- statelogger.Infof("(+) %x\n", addr)
+ statelogger.Debugf("(+) %x\n", addr)
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
diff --git a/ethstate/state_object.go b/ethstate/state_object.go
index 67d09edd8..be083e80a 100644
--- a/ethstate/state_object.go
+++ b/ethstate/state_object.go
@@ -32,7 +32,7 @@ type StateObject struct {
address []byte
// Shared attributes
Balance *big.Int
- CodeHash []byte
+ codeHash []byte
Nonce uint64
// Contract related attributes
State *State
@@ -236,7 +236,7 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
func (self *StateObject) Copy() *StateObject {
stateObject := NewStateObject(self.Address())
stateObject.Balance.Set(self.Balance)
- stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash)
+ stateObject.codeHash = ethutil.CopyBytes(self.codeHash)
stateObject.Nonce = self.Nonce
if self.State != nil {
stateObject.State = self.State.Copy()
@@ -245,6 +245,7 @@ func (self *StateObject) Copy() *StateObject {
stateObject.InitCode = ethutil.CopyBytes(self.InitCode)
stateObject.storage = self.storage.Copy()
stateObject.gasPool.Set(self.gasPool)
+ stateObject.remove = self.remove
return stateObject
}
@@ -271,6 +272,11 @@ func (c *StateObject) Init() Code {
return c.InitCode
}
+// To satisfy ClosureRef
+func (self *StateObject) Object() *StateObject {
+ return self
+}
+
// Debug stuff
func (self *StateObject) CreateOutputForDiff() {
fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce)
@@ -292,7 +298,16 @@ func (c *StateObject) RlpEncode() []byte {
root = ""
}
- return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)})
+ return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, c.CodeHash()})
+}
+
+func (c *StateObject) CodeHash() ethutil.Bytes {
+ var codeHash []byte
+ if len(c.Code) > 0 {
+ codeHash = ethcrypto.Sha3Bin(c.Code)
+ }
+
+ return codeHash
}
func (c *StateObject) RlpDecode(data []byte) {
@@ -304,9 +319,9 @@ func (c *StateObject) RlpDecode(data []byte) {
c.storage = make(map[string]*ethutil.Value)
c.gasPool = new(big.Int)
- c.CodeHash = decoder.Get(3).Bytes()
+ c.codeHash = decoder.Get(3).Bytes()
- c.Code, _ = ethutil.Config.Db.Get(c.CodeHash)
+ c.Code, _ = ethutil.Config.Db.Get(c.codeHash)
}
// Storage change object. Used by the manifest for notifying changes to
diff --git a/ethtrie/trie.go b/ethtrie/trie.go
index 38ae0754d..e6e09dd0d 100644
--- a/ethtrie/trie.go
+++ b/ethtrie/trie.go
@@ -92,6 +92,13 @@ func (cache *Cache) Get(key []byte) *ethutil.Value {
data, _ := cache.db.Get(key)
// Create the cached value
value := ethutil.NewValueFromBytes(data)
+
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Println("RECOVER GET", cache, cache.nodes)
+ panic("bye")
+ }
+ }()
// Create caching node
cache.nodes[string(key)] = NewNode(key, value, false)
diff --git a/ethutil/bytes.go b/ethutil/bytes.go
index e38f89454..f151d16ee 100644
--- a/ethutil/bytes.go
+++ b/ethutil/bytes.go
@@ -9,6 +9,22 @@ import (
"strings"
)
+type Bytes []byte
+
+func (self Bytes) String() string {
+ return string(self)
+}
+
+func DeleteFromByteSlice(s [][]byte, hash []byte) [][]byte {
+ for i, h := range s {
+ if bytes.Compare(h, hash) == 0 {
+ return append(s[:i], s[i+1:]...)
+ }
+ }
+
+ return s
+}
+
// Number to bytes
//
// Returns the number in bytes with the specified base
diff --git a/ethutil/list.go b/ethutil/list.go
new file mode 100644
index 000000000..9db96cf18
--- /dev/null
+++ b/ethutil/list.go
@@ -0,0 +1,61 @@
+package ethutil
+
+import (
+ "encoding/json"
+ "reflect"
+)
+
+// The list type is an anonymous slice handler which can be used
+// for containing any slice type to use in an environment which
+// does not support slice types (e.g., JavaScript, QML)
+type List struct {
+ list reflect.Value
+ Length int
+}
+
+// Initialise a new list. Panics if non-slice type is given.
+func NewList(t interface{}) *List {
+ list := reflect.ValueOf(t)
+ if list.Kind() != reflect.Slice {
+ panic("list container initialized with a non-slice type")
+ }
+
+ return &List{list, list.Len()}
+}
+
+func EmptyList() *List {
+ return NewList([]interface{}{})
+}
+
+// Get N element from the embedded slice. Returns nil if OOB.
+func (self *List) Get(i int) interface{} {
+ if self.list.Len() > i {
+ return self.list.Index(i).Interface()
+ }
+
+ return nil
+}
+
+// Appends value at the end of the slice. Panics when incompatible value
+// is given.
+func (self *List) Append(v interface{}) {
+ self.list = reflect.Append(self.list, reflect.ValueOf(v))
+ self.Length = self.list.Len()
+}
+
+// Returns the underlying slice as interface.
+func (self *List) Interface() interface{} {
+ return self.list.Interface()
+}
+
+// For JavaScript <3
+func (self *List) ToJSON() string {
+ var list []interface{}
+ for i := 0; i < self.Length; i++ {
+ list = append(list, self.Get(i))
+ }
+
+ data, _ := json.Marshal(list)
+
+ return string(data)
+}
diff --git a/ethutil/path.go b/ethutil/path.go
index 27022bcfa..cfbc38950 100644
--- a/ethutil/path.go
+++ b/ethutil/path.go
@@ -45,7 +45,7 @@ func ReadAllFile(filePath string) (string, error) {
}
func WriteFile(filePath string, content []byte) error {
- fh, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, os.ModePerm)
+ fh, err := os.OpenFile(filePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return err
}
diff --git a/ethutil/rlp.go b/ethutil/rlp.go
index 17ff627eb..55406133b 100644
--- a/ethutil/rlp.go
+++ b/ethutil/rlp.go
@@ -15,6 +15,10 @@ type RlpEncodeDecode interface {
RlpValue() []interface{}
}
+func Rlp(encoder RlpEncode) []byte {
+ return encoder.RlpEncode()
+}
+
type RlpEncoder struct {
rlpData []byte
}
@@ -124,6 +128,8 @@ func Encode(object interface{}) []byte {
} else {
buff.Write(Encode(t.Bytes()))
}
+ case Bytes:
+ buff.Write(Encode([]byte(t)))
case []byte:
if len(t) == 1 && t[0] <= 0x7f {
buff.Write(t)
diff --git a/ethutil/script.go b/ethutil/script.go
index b796e7c1e..bd087e7e0 100644
--- a/ethutil/script.go
+++ b/ethutil/script.go
@@ -2,9 +2,11 @@ package ethutil
import (
"fmt"
+ "strings"
+
"github.com/obscuren/mutan"
"github.com/obscuren/mutan/backends"
- "strings"
+ "github.com/obscuren/serpent-go"
)
// General compile function
@@ -14,15 +16,13 @@ func Compile(script string, silent bool) (ret []byte, err error) {
if len(line) > 1 && line[0:2] == "#!" {
switch line {
- /*
- case "#!serpent":
- byteCode, err := serpent.Compile(script)
- if err != nil {
- return nil, err
- }
+ case "#!serpent":
+ byteCode, err := serpent.Compile(script)
+ if err != nil {
+ return nil, err
+ }
- return byteCode, nil
- */
+ return byteCode, nil
}
} else {
diff --git a/ethutil/set.go b/ethutil/set.go
new file mode 100644
index 000000000..7955edac0
--- /dev/null
+++ b/ethutil/set.go
@@ -0,0 +1,36 @@
+package ethutil
+
+type Settable interface {
+ AsSet() UniqueSet
+}
+
+type Stringable interface {
+ String() string
+}
+
+type UniqueSet map[string]struct{}
+
+func NewSet(v ...Stringable) UniqueSet {
+ set := make(UniqueSet)
+ for _, val := range v {
+ set.Insert(val)
+ }
+
+ return set
+}
+
+func (self UniqueSet) Insert(k Stringable) UniqueSet {
+ self[k.String()] = struct{}{}
+
+ return self
+}
+
+func (self UniqueSet) Include(k Stringable) bool {
+ _, ok := self[k.String()]
+
+ return ok
+}
+
+func Set(s Settable) UniqueSet {
+ return s.AsSet()
+}
diff --git a/ethutil/size.go b/ethutil/size.go
new file mode 100644
index 000000000..b4426465e
--- /dev/null
+++ b/ethutil/size.go
@@ -0,0 +1,15 @@
+package ethutil
+
+import "fmt"
+
+type StorageSize float64
+
+func (self StorageSize) String() string {
+ if self > 1000000 {
+ return fmt.Sprintf("%.2f mB", self/1000000)
+ } else if self > 1000 {
+ return fmt.Sprintf("%.2f kB", self/1000)
+ } else {
+ return fmt.Sprintf("%.2f B", self)
+ }
+}
diff --git a/ethutil/size_test.go b/ethutil/size_test.go
new file mode 100644
index 000000000..82aa1c653
--- /dev/null
+++ b/ethutil/size_test.go
@@ -0,0 +1,12 @@
+package ethutil
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestSize(t *testing.T) {
+ fmt.Println(StorageSize(2381273))
+ fmt.Println(StorageSize(2192))
+ fmt.Println(StorageSize(12))
+}
diff --git a/ethutil/value.go b/ethutil/value.go
index 608d332ba..b1f887f29 100644
--- a/ethutil/value.go
+++ b/ethutil/value.go
@@ -1,9 +1,11 @@
package ethutil
import (
+ "bytes"
"fmt"
"math/big"
"reflect"
+ "strconv"
)
// Data values are returned by the rlp decoder. The data values represents
@@ -93,6 +95,9 @@ func (val *Value) Int() int64 {
return new(big.Int).SetBytes(Val).Int64()
} else if Val, ok := val.Val.(*big.Int); ok {
return Val.Int64()
+ } else if Val, ok := val.Val.(string); ok {
+ n, _ := strconv.Atoi(Val)
+ return int64(n)
}
return 0
@@ -113,6 +118,8 @@ func (val *Value) BigInt() *big.Int {
return b
} else if a, ok := val.Val.(*big.Int); ok {
return a
+ } else if a, ok := val.Val.(string); ok {
+ return Big(a)
} else {
return big.NewInt(int64(val.Uint()))
}
@@ -141,6 +148,8 @@ func (val *Value) Bytes() []byte {
return []byte(s)
} else if s, ok := val.Val.(*big.Int); ok {
return s.Bytes()
+ } else {
+ return big.NewInt(val.Int()).Bytes()
}
return []byte{}
@@ -244,10 +253,7 @@ func (val *Value) Cmp(o *Value) bool {
}
func (self *Value) DeepCmp(o *Value) bool {
- a := NewValue(self.BigInt())
- b := NewValue(o.BigInt())
-
- return a.Cmp(b)
+ return bytes.Compare(self.Bytes(), o.Bytes()) == 0
}
func (val *Value) Encode() []byte {
diff --git a/ethutil/value_test.go b/ethutil/value_test.go
index 710cbd887..5452a0790 100644
--- a/ethutil/value_test.go
+++ b/ethutil/value_test.go
@@ -2,6 +2,7 @@ package ethutil
import (
"bytes"
+ "fmt"
"math/big"
"testing"
)
@@ -78,3 +79,8 @@ func TestMath(t *testing.T) {
t.Error("Expected 0, got", a)
}
}
+
+func TestString(t *testing.T) {
+ a := NewValue("10")
+ fmt.Println("VALUE WITH STRING:", a.Int())
+}
diff --git a/ethvm/closure.go b/ethvm/closure.go
index 54bfd05f4..c047a83b7 100644
--- a/ethvm/closure.go
+++ b/ethvm/closure.go
@@ -12,6 +12,7 @@ import (
type ClosureRef interface {
ReturnGas(*big.Int, *big.Int)
Address() []byte
+ Object() *ethstate.StateObject
GetStorage(*big.Int) *ethutil.Value
SetStorage(*big.Int, *ethutil.Value)
}
diff --git a/ethvm/stack.go b/ethvm/stack.go
index 82dd612c2..4ac023fb9 100644
--- a/ethvm/stack.go
+++ b/ethvm/stack.go
@@ -65,13 +65,13 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) {
}
func (st *Stack) Swapn(n int) (*big.Int, *big.Int) {
- st.data[n], st.data[0] = st.data[0], st.data[n]
+ st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n]
- return st.data[n], st.data[0]
+ return st.data[len(st.data)-n], st.data[len(st.data)-1]
}
func (st *Stack) Dupn(n int) *big.Int {
- st.Push(st.data[n])
+ st.Push(st.data[len(st.data)-n])
return st.Peek()
}
diff --git a/ethvm/types.go b/ethvm/types.go
index 36ba395d6..9cddd7c33 100644
--- a/ethvm/types.go
+++ b/ethvm/types.go
@@ -49,6 +49,8 @@ const (
CODESIZE = 0x38
CODECOPY = 0x39
GASPRICE = 0x3a
+ EXTCODECOPY = 0x3b
+ EXTCODESIZE = 0x3c
// 0x40 range - block operations
PREVHASH = 0x40
@@ -142,9 +144,11 @@ const (
SWAP16 = 0x9f
// 0xf0 range - closures
- CREATE = 0xf0
- CALL = 0xf1
- RETURN = 0xf2
+ CREATE = 0xf0
+ CALL = 0xf1
+ RETURN = 0xf2
+ POST = 0xf3
+ CALLSTATELESS = 0xf4
// 0x70 range - other
LOG = 0xfe // XXX Unofficial
@@ -196,12 +200,14 @@ var opCodeToString = map[OpCode]string{
GASPRICE: "TXGASPRICE",
// 0x40 range - block operations
- PREVHASH: "PREVHASH",
- COINBASE: "COINBASE",
- TIMESTAMP: "TIMESTAMP",
- NUMBER: "NUMBER",
- DIFFICULTY: "DIFFICULTY",
- GASLIMIT: "GASLIMIT",
+ PREVHASH: "PREVHASH",
+ COINBASE: "COINBASE",
+ TIMESTAMP: "TIMESTAMP",
+ NUMBER: "NUMBER",
+ DIFFICULTY: "DIFFICULTY",
+ GASLIMIT: "GASLIMIT",
+ EXTCODESIZE: "EXTCODESIZE",
+ EXTCODECOPY: "EXTCODECOPY",
// 0x50 range - 'storage' and execution
POP: "POP",
@@ -287,9 +293,11 @@ var opCodeToString = map[OpCode]string{
SWAP16: "SWAP16",
// 0xf0 range
- CREATE: "CREATE",
- CALL: "CALL",
- RETURN: "RETURN",
+ CREATE: "CREATE",
+ CALL: "CALL",
+ RETURN: "RETURN",
+ POST: "POST",
+ CALLSTATELESS: "CALLSTATELESS",
// 0x70 range - other
LOG: "LOG",
@@ -342,7 +350,12 @@ var OpCodes = map[string]byte{
"CALLVALUE": 0x34,
"CALLDATALOAD": 0x35,
"CALLDATASIZE": 0x36,
- "GASPRICE": 0x38,
+ "CALLDATACOPY": 0x37,
+ "CODESIZE": 0x38,
+ "CODECOPY": 0x39,
+ "GASPRICE": 0x3a,
+ "EXTCODECOPY": 0x3b,
+ "EXTCODESIZE": 0x3c,
// 0x40 range - block operations
"PREVHASH": 0x40,
@@ -435,9 +448,11 @@ var OpCodes = map[string]byte{
"SWAP16": 0x9f,
// 0xf0 range - closures
- "CREATE": 0xf0,
- "CALL": 0xf1,
- "RETURN": 0xf2,
+ "CREATE": 0xf0,
+ "CALL": 0xf1,
+ "RETURN": 0xf2,
+ "POST": 0xf3,
+ "CALLSTATELESS": 0xf4,
// 0x70 range - other
"LOG": 0xfe,
diff --git a/ethvm/vm.go b/ethvm/vm.go
index 873a80c44..7aff320f9 100644
--- a/ethvm/vm.go
+++ b/ethvm/vm.go
@@ -1,8 +1,8 @@
package ethvm
import (
+ "container/list"
"fmt"
- "math"
"math/big"
"github.com/ethereum/eth-go/ethcrypto"
@@ -18,11 +18,6 @@ type Debugger interface {
}
type Vm struct {
- // Stack for processing contracts
- stack *Stack
- // non-persistent key/value memory storage
- mem map[string]*big.Int
-
env Environment
Verbose bool
@@ -40,6 +35,8 @@ type Vm struct {
Fn string
Recoverable bool
+
+ queue *list.List
}
type Environment interface {
@@ -66,7 +63,20 @@ func New(env Environment) *Vm {
lt = LogTyDiff
}
- return &Vm{env: env, logTy: lt, Recoverable: true}
+ return &Vm{env: env, logTy: lt, Recoverable: true, queue: list.New()}
+}
+
+func calcMemSize(off, l *big.Int) *big.Int {
+ if l.Cmp(ethutil.Big0) == 0 {
+ return ethutil.Big0
+ }
+
+ return new(big.Int).Add(off, l)
+}
+
+// Simple helper
+func u256(n int64) *big.Int {
+ return big.NewInt(n)
}
func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
@@ -122,15 +132,13 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// XXX Leave this Println intact. Don't change this to the log system.
// Used for creating diffs between implementations
if self.logTy == LogTyDiff {
- /*
- switch op {
- case STOP, RETURN, SUICIDE:
- closure.object.EachStorage(func(key string, value *ethutil.Value) {
- value.Decode()
- fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes())
- })
- }
- */
+ switch op {
+ case STOP, RETURN, SUICIDE:
+ closure.object.EachStorage(func(key string, value *ethutil.Value) {
+ value.Decode()
+ fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes())
+ })
+ }
b := pc.Bytes()
if len(b) == 0 {
@@ -149,7 +157,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
addStepGasUsage(GasStep)
- var newMemSize uint64 = 0
+ var newMemSize *big.Int = ethutil.Big0
switch op {
case STOP:
gas.Set(ethutil.Big0)
@@ -173,52 +181,64 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
gas.Set(GasBalance)
case MSTORE:
require(2)
- newMemSize = stack.Peek().Uint64() + 32
+ newMemSize = calcMemSize(stack.Peek(), u256(32))
case MLOAD:
require(1)
- newMemSize = stack.Peek().Uint64() + 32
+ newMemSize = calcMemSize(stack.Peek(), u256(32))
case MSTORE8:
require(2)
- newMemSize = stack.Peek().Uint64() + 1
+ newMemSize = calcMemSize(stack.Peek(), u256(1))
case RETURN:
require(2)
- newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
+ newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case SHA3:
require(2)
gas.Set(GasSha)
- newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
+ newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
case CALLDATACOPY:
- require(3)
+ require(2)
- newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
+ newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
case CODECOPY:
require(3)
- newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
- case CALL:
+ newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
+ case EXTCODECOPY:
+ require(4)
+
+ newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
+ case CALL, CALLSTATELESS:
require(7)
gas.Set(GasCall)
addStepGasUsage(stack.data[stack.Len()-1])
- x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64()
- y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64()
+ x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
+ y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
- newMemSize = uint64(math.Max(float64(x), float64(y)))
+ newMemSize = ethutil.BigMax(x, y)
case CREATE:
require(3)
gas.Set(GasCreate)
- newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
+ newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
}
- newMemSize = (newMemSize + 31) / 32 * 32
- if newMemSize > uint64(mem.Len()) {
- m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
- addStepGasUsage(big.NewInt(int64(m)))
+ if newMemSize.Cmp(ethutil.Big0) > 0 {
+ newMemSize.Add(newMemSize, u256(31))
+ newMemSize.Div(newMemSize, u256(32))
+ newMemSize.Mul(newMemSize, u256(32))
+
+ if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
+ memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
+ memGasUsage.Mul(GasMemory, memGasUsage)
+ memGasUsage.Div(memGasUsage, u256(32))
+
+ addStepGasUsage(memGasUsage)
+ }
}
if !closure.UseGas(gas) {
@@ -232,7 +252,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf("(pc) %-3d -o- %-14s", pc, op.String())
self.Printf(" (g) %-3v (%v)", gas, closure.Gas)
- mem.Resize(newMemSize)
+ mem.Resize(newMemSize.Uint64())
switch op {
case LOG:
@@ -551,14 +571,32 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
code := closure.Args[cOff : cOff+l]
mem.Set(mOff, l, code)
- case CODESIZE:
- l := big.NewInt(int64(len(closure.Code)))
+ case CODESIZE, EXTCODESIZE:
+ var code []byte
+ if op == EXTCODECOPY {
+ addr := stack.Pop().Bytes()
+
+ code = self.env.State().GetCode(addr)
+ } else {
+ code = closure.Code
+ }
+
+ l := big.NewInt(int64(len(code)))
stack.Push(l)
self.Printf(" => %d", l)
- case CODECOPY:
+ case CODECOPY, EXTCODECOPY:
+ var code []byte
+ if op == EXTCODECOPY {
+ addr := stack.Pop().Bytes()
+
+ code = self.env.State().GetCode(addr)
+ } else {
+ code = closure.Code
+ }
+
var (
- size = int64(len(closure.Code))
+ size = int64(len(code))
mOff = stack.Pop().Int64()
cOff = stack.Pop().Int64()
l = stack.Pop().Int64()
@@ -571,9 +609,9 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
l = 0
}
- code := closure.Code[cOff : cOff+l]
+ codeCopy := code[cOff : cOff+l]
- mem.Set(mOff, l, code)
+ mem.Set(mOff, l, codeCopy)
case GASPRICE:
stack.Push(closure.Price)
@@ -632,11 +670,15 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
stack.Pop()
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
- stack.Dupn(n)
+ v := stack.Dupn(n)
self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes())
+
+ if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP {
+ fmt.Println(toValue(v))
+ }
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
- n := int(op - SWAP1 + 1)
+ n := int(op - SWAP1 + 2)
x, y := stack.Swapn(n)
self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes())
@@ -656,12 +698,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf(" => 0x%x", val)
case MSTORE8:
require(2)
- val, mStart := stack.Popn()
- //base.And(val, new(big.Int).SetInt64(0xff))
- //mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
- mem.store[mStart.Int64()] = byte(val.Int64() & 0xff)
+ off := stack.Pop()
+ val := stack.Pop()
- self.Printf(" => 0x%x", val)
+ mem.store[off.Int64()] = byte(val.Int64() & 0xff)
+
+ self.Printf(" => [%v] 0x%x", off, val)
case SLOAD:
require(1)
loc := stack.Pop()
@@ -711,6 +753,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
err error
value = stack.Pop()
size, offset = stack.Popn()
+ input = mem.Get(offset.Int64(), size.Int64())
+ gas = new(big.Int).Set(closure.Gas)
// Snapshot the current stack so we are able to
// revert back to it later.
@@ -726,37 +770,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf(" (*) %x", addr).Endl()
- msg := self.env.State().Manifest().AddMessage(&ethstate.Message{
- To: addr, From: closure.Address(),
- Origin: self.env.Origin(),
- Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
- Value: value,
- })
-
- // Create a new contract
- contract := self.env.State().NewStateObject(addr)
- if contract.Balance.Cmp(value) >= 0 {
- closure.object.SubAmount(value)
- contract.AddAmount(value)
-
- // Set the init script
- initCode := mem.Get(offset.Int64(), size.Int64())
- msg.Input = initCode
-
- // Transfer all remaining gas to the new
- // contract so it may run the init script
- gas := new(big.Int).Set(closure.Gas)
- closure.UseGas(closure.Gas)
-
- // Create the closure
- c := NewClosure(msg, closure, contract, initCode, gas, closure.Price)
- // Call the closure and set the return value as
- // main script.
- contract.Code, _, err = c.Call(self, nil)
- } else {
- err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
- }
+ closure.UseGas(closure.Gas)
+ msg := NewMessage(self, addr, input, gas, closure.Price, value)
+ ret, err := msg.Exec(addr, closure)
if err != nil {
stack.Push(ethutil.BigFalse)
@@ -765,17 +782,18 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf("CREATE err %v", err)
} else {
- stack.Push(ethutil.BigD(addr))
+ msg.object.Code = ret
- msg.Output = contract.Code
+ stack.Push(ethutil.BigD(addr))
}
+
self.Endl()
// Debug hook
if self.Dbg != nil {
self.Dbg.SetCode(closure.Code)
}
- case CALL:
+ case CALL, CALLSTATELESS:
require(7)
self.Endl()
@@ -791,51 +809,48 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
- msg := self.env.State().Manifest().AddMessage(&ethstate.Message{
- To: addr.Bytes(), From: closure.Address(),
- Input: args,
- Origin: self.env.Origin(),
- Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
- Value: value,
- })
-
- if closure.object.Balance.Cmp(value) < 0 {
- vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
+ snapshot := self.env.State().Copy()
- closure.ReturnGas(gas, nil)
+ var executeAddr []byte
+ if op == CALLSTATELESS {
+ executeAddr = closure.Address()
+ } else {
+ executeAddr = addr.Bytes()
+ }
+ msg := NewMessage(self, executeAddr, args, gas, closure.Price, value)
+ ret, err := msg.Exec(addr.Bytes(), closure)
+ if err != nil {
stack.Push(ethutil.BigFalse)
- } else {
- snapshot := self.env.State().Copy()
- stateObject := self.env.State().GetOrNewStateObject(addr.Bytes())
+ self.env.State().Set(snapshot)
+ } else {
+ stack.Push(ethutil.BigTrue)
- closure.object.SubAmount(value)
- stateObject.AddAmount(value)
+ mem.Set(retOffset.Int64(), retSize.Int64(), ret)
+ }
- // Create a new callable closure
- c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price)
- // Executer the closure and get the return value (if any)
- ret, _, err := c.Call(self, args)
- if err != nil {
- stack.Push(ethutil.BigFalse)
+ // Debug hook
+ if self.Dbg != nil {
+ self.Dbg.SetCode(closure.Code)
+ }
- vmlogger.Debugf("Closure execution failed. %v\n", err)
+ case POST:
+ require(5)
- self.env.State().Set(snapshot)
- } else {
- stack.Push(ethutil.BigTrue)
+ self.Endl()
- mem.Set(retOffset.Int64(), retSize.Int64(), ret)
- }
+ gas := stack.Pop()
+ // Pop gas and value of the stack.
+ value, addr := stack.Popn()
+ // Pop input size and offset
+ inSize, inOffset := stack.Popn()
+ // Get the arguments from the memory
+ args := mem.Get(inOffset.Int64(), inSize.Int64())
- msg.Output = ret
+ msg := NewMessage(self, addr.Bytes(), args, gas, closure.Price, value)
- // Debug hook
- if self.Dbg != nil {
- self.Dbg.SetCode(closure.Code)
- }
- }
+ msg.Postpone()
case RETURN:
require(2)
size, offset := stack.Popn()
@@ -861,6 +876,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
default:
vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op)
+ //panic(fmt.Sprintf("Invalid opcode %x", op))
+
return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op)
}
@@ -887,6 +904,10 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
}
}
+func (self *Vm) Queue() *list.List {
+ return self.queue
+}
+
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
if self.Verbose && self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
@@ -918,3 +939,83 @@ func ensure256(x *big.Int) {
x.SetInt64(0)
}
}
+
+type Message struct {
+ vm *Vm
+ closure *Closure
+ address, input []byte
+ gas, price, value *big.Int
+ object *ethstate.StateObject
+}
+
+func NewMessage(vm *Vm, address, input []byte, gas, gasPrice, value *big.Int) *Message {
+ return &Message{vm: vm, address: address, input: input, gas: gas, price: gasPrice, value: value}
+}
+
+func (self *Message) Postpone() {
+ self.vm.queue.PushBack(self)
+}
+
+func (self *Message) Addr() []byte {
+ return self.address
+}
+
+func (self *Message) Exec(codeAddr []byte, caller ClosureRef) (ret []byte, err error) {
+ fmt.Printf("%x %x\n", codeAddr[0:4], self.address[0:4])
+ queue := self.vm.queue
+ self.vm.queue = list.New()
+
+ defer func() {
+ if err == nil {
+ queue.PushBackList(self.vm.queue)
+ }
+
+ self.vm.queue = queue
+ }()
+
+ msg := self.vm.env.State().Manifest().AddMessage(&ethstate.Message{
+ To: self.address, From: caller.Address(),
+ Input: self.input,
+ Origin: self.vm.env.Origin(),
+ Block: self.vm.env.BlockHash(), Timestamp: self.vm.env.Time(), Coinbase: self.vm.env.Coinbase(), Number: self.vm.env.BlockNumber(),
+ Value: self.value,
+ })
+
+ object := caller.Object()
+ if object.Balance.Cmp(self.value) < 0 {
+ caller.ReturnGas(self.gas, self.price)
+
+ err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance)
+ } else {
+ stateObject := self.vm.env.State().GetOrNewStateObject(self.address)
+ self.object = stateObject
+
+ caller.Object().SubAmount(self.value)
+ stateObject.AddAmount(self.value)
+
+ // Retrieve the executing code
+ code := self.vm.env.State().GetCode(codeAddr)
+
+ // Create a new callable closure
+ c := NewClosure(msg, caller, stateObject, code, self.gas, self.price)
+ // Executer the closure and get the return value (if any)
+ ret, _, err = c.Call(self.vm, self.input)
+
+ msg.Output = ret
+
+ return ret, err
+ }
+
+ return
+}
+
+// Mainly used for print variables and passing to Print*
+func toValue(val *big.Int) interface{} {
+ // Let's assume a string on right padded zero's
+ b := val.Bytes()
+ if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 {
+ return string(b)
+ }
+
+ return val
+}
diff --git a/ethwire/client_identity.go b/ethwire/client_identity.go
index e803406d8..ceaa9fe83 100644
--- a/ethwire/client_identity.go
+++ b/ethwire/client_identity.go
@@ -11,7 +11,6 @@ type ClientIdentity interface {
}
type SimpleClientIdentity struct {
- clientString string
clientIdentifier string
version string
customIdentifier string
@@ -25,28 +24,31 @@ func NewSimpleClientIdentity(clientIdentifier string, version string, customIden
version: version,
customIdentifier: customIdentifier,
os: runtime.GOOS,
- implementation: "Go",
+ implementation: runtime.Version(),
}
- clientIdentity.init()
+
return clientIdentity
}
func (c *SimpleClientIdentity) init() {
- c.clientString = fmt.Sprintf("%s/v%s/%s/%s/%s",
+}
+
+func (c *SimpleClientIdentity) String() string {
+ var id string
+ if len(c.customIdentifier) > 0 {
+ id = "/" + c.customIdentifier
+ }
+
+ return fmt.Sprintf("%s/v%s%s/%s/%s",
c.clientIdentifier,
c.version,
- c.customIdentifier,
+ id,
c.os,
c.implementation)
}
-func (c *SimpleClientIdentity) String() string {
- return c.clientString
-}
-
func (c *SimpleClientIdentity) SetCustomIdentifier(customIdentifier string) {
c.customIdentifier = customIdentifier
- c.init()
}
func (c *SimpleClientIdentity) GetCustomIdentifier() string {
diff --git a/ethwire/messages2.go b/ethwire/messages2.go
new file mode 100644
index 000000000..a52b79bd7
--- /dev/null
+++ b/ethwire/messages2.go
@@ -0,0 +1,199 @@
+package ethwire
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "net"
+ "time"
+
+ "github.com/ethereum/eth-go/ethutil"
+)
+
+// The connection object allows you to set up a connection to the Ethereum network.
+// The Connection object takes care of all encoding and sending objects properly over
+// the network.
+type Connection struct {
+ conn net.Conn
+ nTimeout time.Duration
+ pendingMessages Messages
+}
+
+// Create a new connection to the Ethereum network
+func New(conn net.Conn) *Connection {
+ return &Connection{conn: conn, nTimeout: 500}
+}
+
+// Read, reads from the network. It will block until the next message is received.
+func (self *Connection) Read() *Msg {
+ if len(self.pendingMessages) == 0 {
+ self.readMessages()
+ }
+
+ ret := self.pendingMessages[0]
+ self.pendingMessages = self.pendingMessages[1:]
+
+ return ret
+
+}
+
+// Write to the Ethereum network specifying the type of the message and
+// the data. Data can be of type RlpEncodable or []interface{}. Returns
+// nil or if something went wrong an error.
+func (self *Connection) Write(typ MsgType, v ...interface{}) error {
+ var pack []byte
+
+ slice := [][]interface{}{[]interface{}{byte(typ)}}
+ for _, value := range v {
+ if encodable, ok := value.(ethutil.RlpEncodeDecode); ok {
+ slice = append(slice, encodable.RlpValue())
+ } else if raw, ok := value.([]interface{}); ok {
+ slice = append(slice, raw)
+ } else {
+ panic(fmt.Sprintf("Unable to 'write' object of type %T", value))
+ }
+ }
+
+ // Encode the type and the (RLP encoded) data for sending over the wire
+ encoded := ethutil.NewValue(slice).Encode()
+ payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32)
+
+ // Write magic token and payload length (first 8 bytes)
+ pack = append(MagicToken, payloadLength...)
+ pack = append(pack, encoded...)
+
+ // Write to the connection
+ _, err := self.conn.Write(pack)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (self *Connection) readMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) {
+ if len(data) == 0 {
+ return nil, nil, true, nil
+ }
+
+ if len(data) <= 8 {
+ return nil, remaining, false, errors.New("Invalid message")
+ }
+
+ // Check if the received 4 first bytes are the magic token
+ if bytes.Compare(MagicToken, data[:4]) != 0 {
+ return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4])
+ }
+
+ messageLength := ethutil.BytesToNumber(data[4:8])
+ remaining = data[8+messageLength:]
+ if int(messageLength) > len(data[8:]) {
+ return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength)
+ }
+
+ message := data[8 : 8+messageLength]
+ decoder := ethutil.NewValueFromBytes(message)
+ // Type of message
+ t := decoder.Get(0).Uint()
+ // Actual data
+ d := decoder.SliceFrom(1)
+
+ msg = &Msg{
+ Type: MsgType(t),
+ Data: d,
+ }
+
+ return
+}
+
+// The basic message reader waits for data on the given connection, decoding
+// and doing a few sanity checks such as if there's a data type and
+// unmarhals the given data
+func (self *Connection) readMessages() (err error) {
+ // The recovering function in case anything goes horribly wrong
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("ethwire.ReadMessage error: %v", r)
+ }
+ }()
+
+ // Buff for writing network message to
+ //buff := make([]byte, 1440)
+ var buff []byte
+ var totalBytes int
+ for {
+ // Give buffering some time
+ self.conn.SetReadDeadline(time.Now().Add(self.nTimeout * time.Millisecond))
+ // Create a new temporarily buffer
+ b := make([]byte, 1440)
+ // Wait for a message from this peer
+ n, _ := self.conn.Read(b)
+ if err != nil && n == 0 {
+ if err.Error() != "EOF" {
+ fmt.Println("err now", err)
+ return err
+ } else {
+ break
+ }
+
+ // Messages can't be empty
+ } else if n == 0 {
+ break
+ }
+
+ buff = append(buff, b[:n]...)
+ totalBytes += n
+ }
+
+ // Reslice buffer
+ buff = buff[:totalBytes]
+ msg, remaining, done, err := self.readMessage(buff)
+ for ; done != true; msg, remaining, done, err = self.readMessage(remaining) {
+ //log.Println("rx", msg)
+
+ if msg != nil {
+ self.pendingMessages = append(self.pendingMessages, msg)
+ }
+ }
+
+ return
+}
+
+func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) {
+ if len(data) == 0 {
+ return nil, nil, true, nil
+ }
+
+ if len(data) <= 8 {
+ return nil, remaining, false, errors.New("Invalid message")
+ }
+
+ // Check if the received 4 first bytes are the magic token
+ if bytes.Compare(MagicToken, data[:4]) != 0 {
+ return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4])
+ }
+
+ messageLength := ethutil.BytesToNumber(data[4:8])
+ remaining = data[8+messageLength:]
+ if int(messageLength) > len(data[8:]) {
+ return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength)
+ }
+
+ message := data[8 : 8+messageLength]
+ decoder := ethutil.NewValueFromBytes(message)
+ // Type of message
+ t := decoder.Get(0).Uint()
+ // Actual data
+ d := decoder.SliceFrom(1)
+
+ msg = &Msg{
+ Type: MsgType(t),
+ Data: d,
+ }
+
+ return
+}
+
+func bufferedRead(conn net.Conn) ([]byte, error) {
+ return nil, nil
+}
diff --git a/ethwire/messaging.go b/ethwire/messaging.go
index 7ac0188a1..2ef53c003 100644
--- a/ethwire/messaging.go
+++ b/ethwire/messaging.go
@@ -4,7 +4,6 @@ package ethwire
import (
"bytes"
- "errors"
"fmt"
"net"
"time"
@@ -27,24 +26,20 @@ const (
// Values are given explicitly instead of by iota because these values are
// defined by the wire protocol spec; it is easier for humans to ensure
// correctness when values are explicit.
- MsgHandshakeTy = 0x00
- MsgDiscTy = 0x01
- MsgPingTy = 0x02
- MsgPongTy = 0x03
- MsgGetPeersTy = 0x10
- MsgPeersTy = 0x11
+ MsgHandshakeTy = 0x00
+ MsgDiscTy = 0x01
+ MsgPingTy = 0x02
+ MsgPongTy = 0x03
+ MsgGetPeersTy = 0x04
+ MsgPeersTy = 0x05
+
+ MsgStatusTy = 0x10
+ MsgGetTxsTy = 0x11
MsgTxTy = 0x12
- MsgGetChainTy = 0x14
- MsgNotInChainTy = 0x15
- MsgGetTxsTy = 0x16
- MsgGetBlockHashesTy = 0x17
- MsgBlockHashesTy = 0x18
- MsgGetBlocksTy = 0x19
- MsgBlockTy = 0x13
-
- MsgOldBlockTy = 0xbb
-
- MsgTalkTy = 0xff
+ MsgGetBlockHashesTy = 0x13
+ MsgBlockHashesTy = 0x14
+ MsgGetBlocksTy = 0x15
+ MsgBlockTy = 0x16
)
var msgTypeToString = map[MsgType]string{
@@ -53,12 +48,11 @@ var msgTypeToString = map[MsgType]string{
MsgPingTy: "Ping",
MsgPongTy: "Pong",
MsgGetPeersTy: "Get peers",
+ MsgStatusTy: "Status",
MsgPeersTy: "Peers",
MsgTxTy: "Transactions",
MsgBlockTy: "Blocks",
- MsgGetChainTy: "Get chain",
MsgGetTxsTy: "Get Txs",
- MsgNotInChainTy: "Not in chain",
MsgGetBlockHashesTy: "Get block hashes",
MsgBlockHashesTy: "Block hashes",
MsgGetBlocksTy: "Get blocks",
@@ -83,106 +77,10 @@ func NewMessage(msgType MsgType, data interface{}) *Msg {
type Messages []*Msg
-// The connection object allows you to set up a connection to the Ethereum network.
-// The Connection object takes care of all encoding and sending objects properly over
-// the network.
-type Connection struct {
- conn net.Conn
- nTimeout time.Duration
- pendingMessages Messages
-}
-
-// Create a new connection to the Ethereum network
-func New(conn net.Conn) *Connection {
- return &Connection{conn: conn, nTimeout: 500}
-}
-
-// Read, reads from the network. It will block until the next message is received.
-func (self *Connection) Read() *Msg {
- if len(self.pendingMessages) == 0 {
- self.readMessages()
- }
-
- ret := self.pendingMessages[0]
- self.pendingMessages = self.pendingMessages[1:]
-
- return ret
-
-}
-
-// Write to the Ethereum network specifying the type of the message and
-// the data. Data can be of type RlpEncodable or []interface{}. Returns
-// nil or if something went wrong an error.
-func (self *Connection) Write(typ MsgType, v ...interface{}) error {
- var pack []byte
-
- slice := [][]interface{}{[]interface{}{byte(typ)}}
- for _, value := range v {
- if encodable, ok := value.(ethutil.RlpEncodeDecode); ok {
- slice = append(slice, encodable.RlpValue())
- } else if raw, ok := value.([]interface{}); ok {
- slice = append(slice, raw)
- } else {
- panic(fmt.Sprintf("Unable to 'write' object of type %T", value))
- }
- }
-
- // Encode the type and the (RLP encoded) data for sending over the wire
- encoded := ethutil.NewValue(slice).Encode()
- payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32)
-
- // Write magic token and payload length (first 8 bytes)
- pack = append(MagicToken, payloadLength...)
- pack = append(pack, encoded...)
-
- // Write to the connection
- _, err := self.conn.Write(pack)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (self *Connection) readMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) {
- if len(data) == 0 {
- return nil, nil, true, nil
- }
-
- if len(data) <= 8 {
- return nil, remaining, false, errors.New("Invalid message")
- }
-
- // Check if the received 4 first bytes are the magic token
- if bytes.Compare(MagicToken, data[:4]) != 0 {
- return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4])
- }
-
- messageLength := ethutil.BytesToNumber(data[4:8])
- remaining = data[8+messageLength:]
- if int(messageLength) > len(data[8:]) {
- return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength)
- }
-
- message := data[8 : 8+messageLength]
- decoder := ethutil.NewValueFromBytes(message)
- // Type of message
- t := decoder.Get(0).Uint()
- // Actual data
- d := decoder.SliceFrom(1)
-
- msg = &Msg{
- Type: MsgType(t),
- Data: d,
- }
-
- return
-}
-
// The basic message reader waits for data on the given connection, decoding
// and doing a few sanity checks such as if there's a data type and
// unmarhals the given data
-func (self *Connection) readMessages() (err error) {
+func ReadMessages(conn net.Conn) (msgs []*Msg, err error) {
// The recovering function in case anything goes horribly wrong
defer func() {
if r := recover(); r != nil {
@@ -190,135 +88,67 @@ func (self *Connection) readMessages() (err error) {
}
}()
- // Buff for writing network message to
- //buff := make([]byte, 1440)
- var buff []byte
- var totalBytes int
+ var (
+ buff []byte
+ messages [][]byte
+ msgLength int
+ )
+
for {
// Give buffering some time
- self.conn.SetReadDeadline(time.Now().Add(self.nTimeout * time.Millisecond))
+ conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond))
// Create a new temporarily buffer
b := make([]byte, 1440)
- // Wait for a message from this peer
- n, _ := self.conn.Read(b)
+ n, _ := conn.Read(b)
if err != nil && n == 0 {
if err.Error() != "EOF" {
fmt.Println("err now", err)
- return err
+ return nil, err
} else {
break
}
-
- // Messages can't be empty
- } else if n == 0 {
- break
}
- buff = append(buff, b[:n]...)
- totalBytes += n
- }
+ if n == 0 && len(buff) == 0 {
+ // If there's nothing on the wire wait for a bit
+ time.Sleep(200 * time.Millisecond)
- // Reslice buffer
- buff = buff[:totalBytes]
- msg, remaining, done, err := self.readMessage(buff)
- for ; done != true; msg, remaining, done, err = self.readMessage(remaining) {
- //log.Println("rx", msg)
-
- if msg != nil {
- self.pendingMessages = append(self.pendingMessages, msg)
+ continue
}
- }
-
- return
-}
-
-func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) {
- if len(data) == 0 {
- return nil, nil, true, nil
- }
-
- if len(data) <= 8 {
- return nil, remaining, false, errors.New("Invalid message")
- }
- // Check if the received 4 first bytes are the magic token
- if bytes.Compare(MagicToken, data[:4]) != 0 {
- return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4])
- }
-
- messageLength := ethutil.BytesToNumber(data[4:8])
- remaining = data[8+messageLength:]
- if int(messageLength) > len(data[8:]) {
- return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength)
- }
-
- message := data[8 : 8+messageLength]
- decoder := ethutil.NewValueFromBytes(message)
- // Type of message
- t := decoder.Get(0).Uint()
- // Actual data
- d := decoder.SliceFrom(1)
-
- msg = &Msg{
- Type: MsgType(t),
- Data: d,
- }
-
- return
-}
+ buff = append(buff, b[:n]...)
+ if msgLength == 0 {
+ // Check if the received 4 first bytes are the magic token
+ if bytes.Compare(MagicToken, buff[:4]) != 0 {
+ return nil, fmt.Errorf("MagicToken mismatch. Received %v", buff[:4])
+ }
-func bufferedRead(conn net.Conn) ([]byte, error) {
- return nil, nil
-}
+ // Read the length of the message
+ msgLength = int(ethutil.BytesToNumber(buff[4:8]))
-// The basic message reader waits for data on the given connection, decoding
-// and doing a few sanity checks such as if there's a data type and
-// unmarhals the given data
-func ReadMessages(conn net.Conn) (msgs []*Msg, err error) {
- // The recovering function in case anything goes horribly wrong
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("ethwire.ReadMessage error: %v", r)
+ // Remove the token and length
+ buff = buff[8:]
}
- }()
- // Buff for writing network message to
- //buff := make([]byte, 1440)
- var buff []byte
- var totalBytes int
- for {
- // Give buffering some time
- conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
- // Create a new temporarily buffer
- b := make([]byte, 1440)
- // Wait for a message from this peer
- n, _ := conn.Read(b)
- if err != nil && n == 0 {
- if err.Error() != "EOF" {
- fmt.Println("err now", err)
- return nil, err
- } else {
+ if len(buff) >= msgLength {
+ messages = append(messages, buff[:msgLength])
+ buff = buff[msgLength:]
+ msgLength = 0
+
+ if len(buff) == 0 {
break
}
-
- // Messages can't be empty
- } else if n == 0 {
- break
}
-
- buff = append(buff, b[:n]...)
- totalBytes += n
}
- // Reslice buffer
- buff = buff[:totalBytes]
- msg, remaining, done, err := ReadMessage(buff)
- for ; done != true; msg, remaining, done, err = ReadMessage(remaining) {
- //log.Println("rx", msg)
+ for _, m := range messages {
+ decoder := ethutil.NewValueFromBytes(m)
+ // Type of message
+ t := decoder.Get(0).Uint()
+ // Actual data
+ d := decoder.SliceFrom(1)
- if msg != nil {
- msgs = append(msgs, msg)
- }
+ msgs = append(msgs, &Msg{Type: MsgType(t), Data: d})
}
return
diff --git a/natpmp.go b/natpmp.go
index badbaf9eb..489342a4b 100644
--- a/natpmp.go
+++ b/natpmp.go
@@ -1,7 +1,6 @@
package eth
import (
- //natpmp "code.google.com/p/go-nat-pmp"
"fmt"
"net"
diff --git a/peer.go b/peer.go
index ab17466e1..67bf4e555 100644
--- a/peer.go
+++ b/peer.go
@@ -24,7 +24,11 @@ const (
// The size of the output buffer for writing messages
outputBufferSize = 50
// Current protocol version
- ProtocolVersion = 28
+ ProtocolVersion = 33
+ // Current P2P version
+ P2PVersion = 0
+ // Ethereum network version
+ NetVersion = 0
// Interval for ping/pong message
pingPongTimer = 2 * time.Second
)
@@ -70,7 +74,7 @@ func (d DiscReason) String() string {
type Caps byte
const (
- CapPeerDiscTy = 1 << iota
+ CapPeerDiscTy Caps = 1 << iota
CapTxTy
CapChainTy
@@ -122,6 +126,7 @@ type Peer struct {
// This flag is used by writeMessage to check if messages are allowed
// to be send or not. If no version is known all messages are ignored.
versionKnown bool
+ statusKnown bool
// Last received pong message
lastPong int64
@@ -179,6 +184,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
inbound: false,
connected: 0,
disconnect: 0,
+ port: 30303,
caps: caps,
version: ethereum.ClientIdentity().String(),
}
@@ -271,9 +277,19 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
default: // Anything but ack is allowed
return
}
+ } else {
+ /*
+ if !p.statusKnown {
+ switch msg.Type {
+ case ethwire.MsgStatusTy: // Ok
+ default: // Anything but ack is allowed
+ return
+ }
+ }
+ */
}
- peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
+ peerlogger.DebugDetailf("(%v) <= %v\n", p.conn.RemoteAddr(), formatMessage(msg))
err := ethwire.WriteMessage(p.conn, msg)
if err != nil {
@@ -295,6 +311,14 @@ out:
select {
// Main message queue. All outbound messages are processed through here
case msg := <-p.outputQueue:
+ if !p.statusKnown {
+ switch msg.Type {
+ case ethwire.MsgGetTxsTy, ethwire.MsgGetBlockHashesTy, ethwire.MsgGetBlocksTy, ethwire.MsgBlockHashesTy, ethwire.MsgBlockTy:
+ peerlogger.Debugln("Blocked outgoing [eth] message to peer without the [eth] cap.")
+ break
+ }
+ }
+
p.writeMessage(msg)
p.lastSend = time.Now()
@@ -337,6 +361,29 @@ clean:
}
}
+func formatMessage(msg *ethwire.Msg) (ret string) {
+ ret = fmt.Sprintf("%v %v", msg.Type, msg.Data)
+
+ /*
+ XXX Commented out because I need the log level here to determine
+ if i should or shouldn't generate this message
+ */
+ /*
+ switch msg.Type {
+ case ethwire.MsgPeersTy:
+ ret += fmt.Sprintf("(%d entries)", msg.Data.Len())
+ case ethwire.MsgBlockTy:
+ b1, b2 := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)), ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len()-1))
+ ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), b1.Hash()[0:4], b2.Hash()[0:4])
+ case ethwire.MsgBlockHashesTy:
+ h1, h2 := msg.Data.Get(0).Bytes(), msg.Data.Get(msg.Data.Len()-1).Bytes()
+ ret += fmt.Sprintf("(%d entries) %x - %x", msg.Data.Len(), h1, h2)
+ }
+ */
+
+ return
+}
+
// Inbound handler. Inbound messages are received here and passed to the appropriate methods
func (p *Peer) HandleInbound() {
for atomic.LoadInt32(&p.disconnect) == 0 {
@@ -349,16 +396,16 @@ func (p *Peer) HandleInbound() {
peerlogger.Debugln(err)
}
for _, msg := range msgs {
- peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
+ peerlogger.DebugDetailf("(%v) => %v\n", p.conn.RemoteAddr(), formatMessage(msg))
switch msg.Type {
case ethwire.MsgHandshakeTy:
// Version message
p.handleHandshake(msg)
- if p.caps.IsCap(CapPeerDiscTy) {
- p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, ""))
- }
+ //if p.caps.IsCap(CapPeerDiscTy) {
+ p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, ""))
+ //}
case ethwire.MsgDiscTy:
p.Stop()
@@ -396,95 +443,111 @@ func (p *Peer) HandleInbound() {
// Connect to the list of peers
p.ethereum.ProcessPeerList(peers)
- case ethwire.MsgGetTxsTy:
- // Get the current transactions of the pool
- txs := p.ethereum.TxPool().CurrentTransactions()
- // Get the RlpData values from the txs
- txsInterface := make([]interface{}, len(txs))
- for i, tx := range txs {
- txsInterface[i] = tx.RlpData()
- }
- // Broadcast it back to the peer
- p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface))
- case ethwire.MsgGetBlockHashesTy:
- if msg.Data.Len() < 2 {
- peerlogger.Debugln("err: argument length invalid ", msg.Data.Len())
- }
+ case ethwire.MsgStatusTy:
+ // Handle peer's status msg
+ p.handleStatus(msg)
+ }
- hash := msg.Data.Get(0).Bytes()
- amount := msg.Data.Get(1).Uint()
+ // TMP
+ if p.statusKnown {
+ switch msg.Type {
+ case ethwire.MsgGetTxsTy:
+ // Get the current transactions of the pool
+ txs := p.ethereum.TxPool().CurrentTransactions()
+ // Get the RlpData values from the txs
+ txsInterface := make([]interface{}, len(txs))
+ for i, tx := range txs {
+ txsInterface[i] = tx.RlpData()
+ }
+ // Broadcast it back to the peer
+ p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface))
- hashes := p.ethereum.BlockChain().GetChainHashesFromHash(hash, amount)
+ case ethwire.MsgGetBlockHashesTy:
+ if msg.Data.Len() < 2 {
+ peerlogger.Debugln("err: argument length invalid ", msg.Data.Len())
+ }
- p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockHashesTy, ethutil.ByteSliceToInterface(hashes)))
+ hash := msg.Data.Get(0).Bytes()
+ amount := msg.Data.Get(1).Uint()
- case ethwire.MsgGetBlocksTy:
- // Limit to max 300 blocks
- max := int(math.Min(float64(msg.Data.Len()), 300.0))
- var blocks []interface{}
+ hashes := p.ethereum.BlockChain().GetChainHashesFromHash(hash, amount)
- for i := 0; i < max; i++ {
- hash := msg.Data.Get(i).Bytes()
- block := p.ethereum.BlockChain().GetBlock(hash)
- if block != nil {
- blocks = append(blocks, block.Value().Raw())
- }
- }
+ p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockHashesTy, ethutil.ByteSliceToInterface(hashes)))
- p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks))
+ case ethwire.MsgGetBlocksTy:
+ // Limit to max 300 blocks
+ max := int(math.Min(float64(msg.Data.Len()), 300.0))
+ var blocks []interface{}
- case ethwire.MsgBlockHashesTy:
- p.catchingUp = true
+ for i := 0; i < max; i++ {
+ hash := msg.Data.Get(i).Bytes()
+ block := p.ethereum.BlockChain().GetBlock(hash)
+ if block != nil {
+ blocks = append(blocks, block.Value().Raw())
+ }
+ }
- blockPool := p.ethereum.blockPool
+ p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, blocks))
- foundCommonHash := false
+ case ethwire.MsgBlockHashesTy:
+ p.catchingUp = true
- it := msg.Data.NewIterator()
- for it.Next() {
- hash := it.Value().Bytes()
+ blockPool := p.ethereum.blockPool
- if blockPool.HasCommonHash(hash) {
- foundCommonHash = true
+ foundCommonHash := false
- break
- }
+ it := msg.Data.NewIterator()
+ for it.Next() {
+ hash := it.Value().Bytes()
- blockPool.AddHash(hash)
+ if blockPool.HasCommonHash(hash) {
+ foundCommonHash = true
- p.lastReceivedHash = hash
+ break
+ }
- p.lastBlockReceived = time.Now()
- }
+ blockPool.AddHash(hash)
- if foundCommonHash {
- p.FetchBlocks()
- } else {
- p.FetchHashes()
- }
+ p.lastReceivedHash = hash
- case ethwire.MsgBlockTy:
- p.catchingUp = true
+ p.lastBlockReceived = time.Now()
+ }
- blockPool := p.ethereum.blockPool
+ if foundCommonHash || msg.Data.Len() == 0 {
+ p.FetchBlocks()
+ } else {
+ p.FetchHashes()
+ }
- it := msg.Data.NewIterator()
+ case ethwire.MsgBlockTy:
+ p.catchingUp = true
- for it.Next() {
- block := ethchain.NewBlockFromRlpValue(it.Value())
+ blockPool := p.ethereum.blockPool
- blockPool.SetBlock(block)
+ it := msg.Data.NewIterator()
+ for it.Next() {
+ block := ethchain.NewBlockFromRlpValue(it.Value())
+ //fmt.Printf("%v %x - %x\n", block.Number, block.Hash()[0:4], block.PrevHash[0:4])
- p.lastBlockReceived = time.Now()
- }
+ blockPool.SetBlock(block, p)
- linked := blockPool.CheckLinkAndProcess(func(block *ethchain.Block) {
- p.ethereum.StateManager().Process(block, false)
- })
+ p.lastBlockReceived = time.Now()
+ }
- if !linked {
- p.FetchBlocks()
+ var err error
+ blockPool.CheckLinkAndProcess(func(block *ethchain.Block) {
+ err = p.ethereum.StateManager().Process(block, false)
+ })
+
+ if err != nil {
+ peerlogger.Infoln(err)
+ } else {
+ // Don't trigger if there's just one block.
+ if blockPool.Len() != 0 && msg.Data.Len() > 1 {
+ p.FetchBlocks()
+ }
+ }
}
}
}
@@ -506,10 +569,10 @@ func (self *Peer) FetchHashes() {
blockPool := self.ethereum.blockPool
if self.td.Cmp(blockPool.td) >= 0 {
- peerlogger.Debugf("Requesting hashes from %x\n", self.lastReceivedHash)
+ blockPool.td = self.td
if !blockPool.HasLatestHash() {
- self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(200)}))
+ self.QueueMessage(ethwire.NewMessage(ethwire.MsgGetBlockHashesTy, []interface{}{self.lastReceivedHash, uint32(256)}))
}
}
}
@@ -580,18 +643,6 @@ func (p *Peer) Stop() {
p.ethereum.RemovePeer(p)
}
-func (p *Peer) pushHandshake() error {
- pubkey := p.ethereum.KeyManager().PublicKey()
- msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
- uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:],
- p.ethereum.BlockChain().TD.Uint64(), p.ethereum.BlockChain().CurrentBlock.Hash(),
- })
-
- p.QueueMessage(msg)
-
- return nil
-}
-
func (p *Peer) peersMessage() *ethwire.Msg {
outPeers := make([]interface{}, len(p.ethereum.InOutPeers()))
// Serialise each peer
@@ -611,13 +662,93 @@ func (p *Peer) pushPeers() {
p.QueueMessage(p.peersMessage())
}
+func (self *Peer) pushStatus() {
+ msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{
+ uint32(ProtocolVersion),
+ uint32(NetVersion),
+ self.ethereum.BlockChain().TD,
+ self.ethereum.BlockChain().CurrentBlock.Hash(),
+ self.ethereum.BlockChain().Genesis().Hash(),
+ })
+
+ self.QueueMessage(msg)
+}
+
+func (self *Peer) handleStatus(msg *ethwire.Msg) {
+ c := msg.Data
+
+ var (
+ protoVersion = c.Get(0).Uint()
+ netVersion = c.Get(1).Uint()
+ td = c.Get(2).BigInt()
+ bestHash = c.Get(3).Bytes()
+ genesis = c.Get(4).Bytes()
+ )
+
+ if bytes.Compare(self.ethereum.BlockChain().Genesis().Hash(), genesis) != 0 {
+ ethlogger.Warnf("Invalid genisis hash %x. Disabling [eth]\n", genesis)
+ return
+ }
+
+ if netVersion != NetVersion {
+ ethlogger.Warnf("Invalid network version %d. Disabling [eth]\n", netVersion)
+ return
+ }
+
+ if protoVersion != ProtocolVersion {
+ ethlogger.Warnf("Invalid protocol version %d. Disabling [eth]\n", protoVersion)
+ return
+ }
+
+ // Get the td and last hash
+ self.td = td
+ self.bestHash = bestHash
+ self.lastReceivedHash = bestHash
+
+ self.statusKnown = true
+
+ // Compare the total TD with the blockchain TD. If remote is higher
+ // fetch hashes from highest TD node.
+ if self.td.Cmp(self.ethereum.BlockChain().TD) > 0 {
+ self.ethereum.blockPool.AddHash(self.lastReceivedHash)
+ self.FetchHashes()
+ }
+
+ ethlogger.Infof("Peer is [eth] capable. (TD = %v ~ %x) %d / %d", self.td, self.bestHash, protoVersion, netVersion)
+
+}
+
+func (p *Peer) pushHandshake() error {
+ pubkey := p.ethereum.KeyManager().PublicKey()
+ msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
+ P2PVersion, []byte(p.version), []interface{}{"eth"}, p.port, pubkey[1:],
+ })
+
+ p.QueueMessage(msg)
+
+ return nil
+}
+
func (p *Peer) handleHandshake(msg *ethwire.Msg) {
c := msg.Data
- // Set pubkey
- p.pubkey = c.Get(5).Bytes()
+ var (
+ p2pVersion = c.Get(0).Uint()
+ clientId = c.Get(1).Str()
+ caps = c.Get(2)
+ port = c.Get(3).Uint()
+ pub = c.Get(4).Bytes()
+ )
+
+ // Check correctness of p2p protocol version
+ if p2pVersion != P2PVersion {
+ peerlogger.Debugf("Invalid P2P version. Require protocol %d, received %d\n", P2PVersion, p2pVersion)
+ p.Stop()
+ return
+ }
- if p.pubkey == nil {
+ // Handle the pub key (validation, uniqueness)
+ if len(pub) == 0 {
peerlogger.Warnln("Pubkey required, not supplied in handshake.")
p.Stop()
return
@@ -625,9 +756,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
usedPub := 0
// This peer is already added to the peerlist so we expect to find a double pubkey at least once
-
eachPeer(p.ethereum.Peers(), func(peer *Peer, e *list.Element) {
- if bytes.Compare(p.pubkey, peer.pubkey) == 0 {
+ if bytes.Compare(pub, peer.pubkey) == 0 {
usedPub++
}
})
@@ -637,19 +767,11 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
p.Stop()
return
}
-
- if c.Get(0).Uint() != ProtocolVersion {
- peerlogger.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint())
- p.Stop()
- return
- }
-
- // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPS, PORT, PUBKEY]
- p.versionKnown = true
+ p.pubkey = pub
// If this is an inbound connection send an ack back
if p.inbound {
- p.port = uint16(c.Get(4).Uint())
+ p.port = uint16(port)
// Self connect detection
pubkey := p.ethereum.KeyManager().PublicKey()
@@ -660,40 +782,27 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
}
}
+ p.SetVersion(clientId)
- // Set the peer's caps
- p.caps = Caps(c.Get(3).Byte())
-
- // Get a reference to the peers version
- versionString := c.Get(2).Str()
- if len(versionString) > 0 {
- p.SetVersion(c.Get(2).Str())
- }
-
- // Get the td and last hash
- p.td = c.Get(6).BigInt()
- p.bestHash = c.Get(7).Bytes()
- p.lastReceivedHash = p.bestHash
+ p.versionKnown = true
p.ethereum.PushPeer(p)
p.ethereum.reactor.Post("peerList", p.ethereum.Peers())
- ethlogger.Infof("Added peer (%s) %d / %d (TD = %v ~ %x)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, p.td, p.bestHash)
-
- /*
- // Catch up with the connected peer
- if !p.ethereum.IsUpToDate() {
- peerlogger.Debugln("Already syncing up with a peer; sleeping")
- time.Sleep(10 * time.Second)
+ capsIt := caps.NewIterator()
+ var capsStrs []string
+ for capsIt.Next() {
+ cap := capsIt.Value().Str()
+ switch cap {
+ case "eth":
+ p.pushStatus()
}
- */
- //p.SyncWithPeerToLastKnown()
- if p.td.Cmp(p.ethereum.BlockChain().TD) > 0 {
- p.ethereum.blockPool.AddHash(p.lastReceivedHash)
- p.FetchHashes()
+ capsStrs = append(capsStrs, cap)
}
+ ethlogger.Infof("Added peer (%s) %d / %d (%v)\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers, capsStrs)
+
peerlogger.Debugln(p)
}
@@ -714,47 +823,6 @@ func (p *Peer) String() string {
return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.version, p.caps)
}
-func (p *Peer) SyncWithPeerToLastKnown() {
- p.catchingUp = false
- p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
-}
-
-func (p *Peer) FindCommonParentBlock() {
- if p.catchingUp {
- return
- }
-
- p.catchingUp = true
- if p.blocksRequested == 0 {
- p.blocksRequested = 20
- }
- blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested)
-
- var hashes []interface{}
- for _, block := range blocks {
- hashes = append(hashes, block.Hash())
- }
-
- msgInfo := append(hashes, uint64(len(hashes)))
-
- peerlogger.DebugDetailf("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String())
-
- msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo)
- p.QueueMessage(msg)
-}
-func (p *Peer) CatchupWithPeer(blockHash []byte) {
- if !p.catchingUp {
- // Make sure nobody else is catching up when you want to do this
- p.catchingUp = true
- msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(100)})
- p.QueueMessage(msg)
-
- peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())
-
- msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{})
- p.QueueMessage(msg)
- }
-}
func (p *Peer) RlpData() []interface{} {
return []interface{}{p.host, p.port, p.pubkey}