aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--block_pool.go24
-rw-r--r--ethchain/block.go7
-rw-r--r--ethchain/block_chain.go157
-rw-r--r--ethchain/state_manager.go2
-rw-r--r--ethchain/state_transition.go11
-rw-r--r--ethchain/transaction.go5
-rw-r--r--ethchain/transaction_pool.go2
-rw-r--r--ethcrypto/crypto_test.go17
-rw-r--r--ethdb/database.go13
-rw-r--r--ethereum.go12
-rw-r--r--ethpipe/js_pipe.go3
-rw-r--r--ethpipe/js_types.go33
-rw-r--r--ethreact/reactor.go5
-rw-r--r--ethstate/state.go11
-rw-r--r--ethstate/state_object.go12
-rw-r--r--ethutil/list.go42
-rw-r--r--ethutil/script.go18
-rw-r--r--ethutil/size.go15
-rw-r--r--ethutil/size_test.go12
-rw-r--r--ethutil/value.go12
-rw-r--r--ethutil/value_test.go6
-rw-r--r--ethvm/closure.go1
-rw-r--r--ethvm/types.go47
-rw-r--r--ethvm/vm.go230
-rw-r--r--ethwire/messaging.go33
-rw-r--r--natpmp.go1
-rw-r--r--peer.go180
28 files changed, 494 insertions, 419 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..25627eb5c 100644
--- a/block_pool.go
+++ b/block_pool.go
@@ -49,11 +49,11 @@ 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.pool[hash] = &block{peer, nil}
}
self.pool[hash].block = b
@@ -65,6 +65,10 @@ func (self *BlockPool) CheckLinkAndProcess(f func(block *ethchain.Block)) bool {
if self.IsLinked() {
for i, hash := range self.hashPool {
+ if self.pool[string(hash)] == nil {
+ continue
+ }
+
block := self.pool[string(hash)].block
if block != nil {
f(block)
@@ -88,9 +92,15 @@ func (self *BlockPool) IsLinked() bool {
return false
}
- block := self.pool[string(self.hashPool[0])].block
- if block != nil {
- return self.eth.BlockChain().HasBlock(block.PrevHash)
+ for i := 0; i < len(self.hashPool); i++ {
+ item := self.pool[string(self.hashPool[i])]
+ if item != nil && item.block != nil {
+ if self.eth.BlockChain().HasBlock(item.block.PrevHash) {
+ self.hashPool = self.hashPool[i:]
+
+ return true
+ }
+ }
}
return false
@@ -104,7 +114,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..d2d012e55 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -351,7 +351,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 +368,7 @@ func (block *Block) String() string {
NumTx: %v
`,
block.Hash(),
+ block.Size(),
block.PrevHash,
block.UncleSha,
block.Coinbase,
@@ -384,3 +385,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..74f47aa90 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")
@@ -110,99 +108,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 +133,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",
@@ -331,7 +176,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
}
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 08bd22d29..33af259cf 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -237,6 +237,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
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..bd8b27a6d 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),
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..4c5e13b6d 100644
--- a/ethereum.go
+++ b/ethereum.go
@@ -90,7 +90,6 @@ type Ethereum struct {
}
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 +100,8 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
}
}
+ bootstrapDb(db)
+
ethutil.Config.Db = db
nonce, _ := ethutil.RandomUint64()
@@ -534,3 +535,12 @@ out:
}
}
}
+
+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())
+ }
+}
diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go
index b32e94a10..eeece5179 100644
--- a/ethpipe/js_pipe.go
+++ b/ethpipe/js_pipe.go
@@ -99,7 +99,8 @@ 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) TxCountAt(address string) int {
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/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/ethstate/state.go b/ethstate/state.go
index cf060e795..42bbf021b 100644
--- a/ethstate/state.go
+++ b/ethstate/state.go
@@ -49,6 +49,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
//
@@ -103,7 +112,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..6fc0696a8 100644
--- a/ethstate/state_object.go
+++ b/ethstate/state_object.go
@@ -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)
@@ -291,8 +297,12 @@ func (c *StateObject) RlpEncode() []byte {
} else {
root = ""
}
+ var codeHash []byte
+ if len(c.Code) > 0 {
+ codeHash = ethcrypto.Sha3Bin(c.Code)
+ }
- return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)})
+ return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, codeHash})
}
func (c *StateObject) RlpDecode(data []byte) {
diff --git a/ethutil/list.go b/ethutil/list.go
new file mode 100644
index 000000000..18bf04792
--- /dev/null
+++ b/ethutil/list.go
@@ -0,0 +1,42 @@
+package ethutil
+
+import "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()}
+}
+
+// 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()
+}
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/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..e8148b990 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
@@ -141,6 +146,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 +251,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/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..fba8c4a0e 100644
--- a/ethvm/vm.go
+++ b/ethvm/vm.go
@@ -1,6 +1,7 @@
package ethvm
import (
+ "container/list"
"fmt"
"math"
"math/big"
@@ -18,11 +19,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 +36,8 @@ type Vm struct {
Fn string
Recoverable bool
+
+ queue *list.List
}
type Environment interface {
@@ -66,7 +64,7 @@ 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 (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
@@ -199,7 +197,11 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
require(3)
newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
- case CALL:
+ case EXTCODECOPY:
+ require(4)
+
+ newMemSize = stack.data[stack.Len()-1].Uint64() + stack.data[stack.Len()-4].Uint64()
+ case CALL, CALLSTATELESS:
require(7)
gas.Set(GasCall)
addStepGasUsage(stack.data[stack.Len()-1])
@@ -215,6 +217,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
}
+ // BUG This will break on overflows. https://github.com/ethereum/eth-go/issues/47
newMemSize = (newMemSize + 31) / 32 * 32
if newMemSize > uint64(mem.Len()) {
m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
@@ -551,14 +554,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 +592,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)
@@ -631,12 +652,12 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
require(1)
stack.Pop()
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
- n := int(op - DUP1 + 1)
+ n := int(op - DUP1)
stack.Dupn(n)
self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes())
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)
x, y := stack.Swapn(n)
self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes())
@@ -711,6 +732,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 +749,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 +761,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 +788,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(6)
- 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()
@@ -887,6 +881,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 +916,71 @@ 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) {
+ 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, object, 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
+}
diff --git a/ethwire/messaging.go b/ethwire/messaging.go
index 7ac0188a1..67a866f73 100644
--- a/ethwire/messaging.go
+++ b/ethwire/messaging.go
@@ -27,24 +27,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 +49,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",
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..5ca3ed641 100644
--- a/peer.go
+++ b/peer.go
@@ -25,6 +25,8 @@ const (
outputBufferSize = 50
// Current protocol version
ProtocolVersion = 28
+ // Current P2P version
+ P2PVersion = 0
// Interval for ping/pong message
pingPongTimer = 2 * time.Second
)
@@ -122,6 +124,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
@@ -271,6 +274,14 @@ 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)
@@ -356,9 +367,9 @@ func (p *Peer) HandleInbound() {
// 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,6 +407,10 @@ func (p *Peer) HandleInbound() {
// Connect to the list of peers
p.ethereum.ProcessPeerList(peers)
+
+ case ethwire.MsgStatusTy:
+ // Handle peer's status msg
+ p.handleStatus(msg)
case ethwire.MsgGetTxsTy:
// Get the current transactions of the pool
txs := p.ethereum.TxPool().CurrentTransactions()
@@ -474,7 +489,7 @@ func (p *Peer) HandleInbound() {
for it.Next() {
block := ethchain.NewBlockFromRlpValue(it.Value())
- blockPool.SetBlock(block)
+ blockPool.SetBlock(block, p)
p.lastBlockReceived = time.Now()
}
@@ -507,6 +522,7 @@ func (self *Peer) FetchHashes() {
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)}))
@@ -580,6 +596,7 @@ func (p *Peer) Stop() {
p.ethereum.RemovePeer(p)
}
+/*
func (p *Peer) pushHandshake() error {
pubkey := p.ethereum.KeyManager().PublicKey()
msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
@@ -591,6 +608,7 @@ func (p *Peer) pushHandshake() error {
return nil
}
+*/
func (p *Peer) peersMessage() *ethwire.Msg {
outPeers := make([]interface{}, len(p.ethereum.InOutPeers()))
@@ -611,13 +629,72 @@ func (p *Peer) pushPeers() {
p.QueueMessage(p.peersMessage())
}
+func (p *Peer) pushHandshake() error {
+ pubkey := p.ethereum.KeyManager().PublicKey()
+ msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{
+ uint32(0), []byte(p.version), []string{"eth"}, p.port, pubkey[1:],
+ })
+
+ p.QueueMessage(msg)
+
+ return nil
+}
+
+func (self *Peer) pushStatus() {
+ const netVersion = 0
+ msg := ethwire.NewMessage(ethwire.MsgStatusTy, []interface{}{
+ uint32(ProtocolVersion),
+ netVersion,
+ self.ethereum.BlockChain().TD.Uint64(),
+ self.ethereum.BlockChain().CurrentBlock.Hash(),
+ self.ethereum.BlockChain().Genesis().Hash(),
+ })
+
+ self.QueueMessage(msg)
+}
+
+func (self *Peer) handleStatus(msg *ethwire.Msg) {
+ c := msg.Data
+ // Set the peer's caps
+ //p.caps = Caps(c.Get(3).Byte())
+
+ // Get the td and last hash
+ self.td = c.Get(6).BigInt()
+ self.bestHash = c.Get(7).Bytes()
+ self.lastReceivedHash = self.bestHash
+
+ // 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", self.td, self.bestHash)
+}
+
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).Raw()
+ port = c.Get(3).Uint()
+ pub = c.Get(4).Bytes()
+ )
+
+ fmt.Println("PEER CAPS", caps)
+
+ // 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 +702,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 +713,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,41 +728,18 @@ 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)
- }
- */
- //p.SyncWithPeerToLastKnown()
-
- if p.td.Cmp(p.ethereum.BlockChain().TD) > 0 {
- p.ethereum.blockPool.AddHash(p.lastReceivedHash)
- p.FetchHashes()
- }
+ ethlogger.Infof("Added peer (%s) %d / %d \n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers)
peerlogger.Debugln(p)
+
+ p.pushStatus()
}
func (p *Peer) String() string {
@@ -714,47 +759,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}