diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | ethchain/dagger.go | 11 | ||||
-rw-r--r-- | ethchain/state.go | 11 | ||||
-rw-r--r-- | ethchain/state_manager.go | 58 | ||||
-rw-r--r-- | ethchain/state_object.go | 93 | ||||
-rw-r--r-- | ethchain/state_transition.go | 47 | ||||
-rw-r--r-- | ethchain/transaction.go | 8 | ||||
-rw-r--r-- | ethchain/vm.go | 22 | ||||
-rw-r--r-- | ethcrypto/mnemonic.go | 29 | ||||
-rw-r--r-- | ethereum.go | 26 | ||||
-rw-r--r-- | ethlog/loggers.go | 2 | ||||
-rw-r--r-- | ethminer/miner.go | 34 | ||||
-rw-r--r-- | ethpub/pub.go | 13 | ||||
-rw-r--r-- | ethpub/types.go | 6 | ||||
-rw-r--r-- | ethtrie/trie.go | 35 | ||||
-rw-r--r-- | ethtrie/trie_test.go | 115 | ||||
-rw-r--r-- | ethutil/bytes.go | 16 | ||||
-rw-r--r-- | ethutil/config.go | 1 | ||||
-rw-r--r-- | ethutil/value.go | 21 | ||||
-rw-r--r-- | peer.go | 13 |
20 files changed, 403 insertions, 160 deletions
@@ -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.5.16". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.5.20". 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/ethchain/dagger.go b/ethchain/dagger.go index adf1c2f05..917b3d722 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -17,10 +17,16 @@ var powlogger = ethlog.NewLogger("POW") type PoW interface { Search(block *Block, reactChan chan ethreact.Event) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool + GetHashrate() int64 } type EasyPow struct { - hash *big.Int + hash *big.Int + HashRate int64 +} + +func (pow *EasyPow) GetHashrate() int64 { + return pow.HashRate } func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { @@ -40,7 +46,8 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - powlogger.Infoln("Hashing @", int64(hashes), "khash") + pow.HashRate = int64(hashes) + powlogger.Infoln("Hashing @", int64(pow.HashRate), "khash") } sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/state.go b/ethchain/state.go index 8df79dcef..684b81102 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -76,6 +76,8 @@ func (self *State) DeleteStateObject(stateObject *StateObject) { // Retrieve a state object given my the address. Nil if not found func (self *State) GetStateObject(addr []byte) *StateObject { + addr = ethutil.Address(addr) + stateObject := self.stateObjects[string(addr)] if stateObject != nil { return stateObject @@ -145,7 +147,6 @@ func (self *State) Set(state *State) { self.trie = state.trie self.stateObjects = state.stateObjects - //*self = *state } func (s *State) Root() interface{} { @@ -173,7 +174,7 @@ func (s *State) Reset() { func (s *State) Sync() { // Sync all nested states for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) + //s.UpdateStateObject(stateObject) if stateObject.state == nil { continue @@ -205,6 +206,8 @@ func (self *State) Update() { // FIXME trie delete is broken valid, t2 := ethtrie.ParanoiaCheck(self.trie) if !valid { + statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root) + self.trie = t2 } } @@ -212,9 +215,9 @@ func (self *State) Update() { // Debug stuff func (self *State) CreateOutputForDiff() { for addr, stateObject := range self.stateObjects { - fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) + fmt.Printf("%x %x %x %x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { - fmt.Printf("0x%x 0x%x\n", addr, value.Bytes()) + fmt.Printf("%x %x\n", addr, value.Bytes()) }) } } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3eafd2d6e..6bd3edd0d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethreact" - "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -121,7 +120,10 @@ func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *Stat done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx, state, block) + + cb := state.GetStateObject(coinbase.Address()) + st := NewStateTransition(cb, tx, state, block) + //fmt.Printf("#%d\n", i+1) err = st.TransitionState() if err != nil { switch { @@ -149,10 +151,17 @@ done: accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + if i < len(block.Receipts()) { + original := block.Receipts()[i] + if !original.Cmp(receipt) { + 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()) + } + } + receipts = append(receipts, receipt) handled = append(handled, tx) - if ethutil.Config.Diff { + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { state.CreateOutputForDiff() } } @@ -188,36 +197,11 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // before that. defer state.Reset() - if ethutil.Config.Diff { - fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number) + if ethutil.Config.Diff && ethutil.Config.DiffType == "all" { + fmt.Printf("## %x %x ##\n", block.Hash(), block.Number) } - receipts, err := sm.ApplyDiff(state, parent, block) - defer func() { - if err != nil { - if len(receipts) == len(block.Receipts()) { - for i, receipt := range block.Receipts() { - statelogger.Infof("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) - } - } else { - statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) - } - } else { - /* - for i, receipt := range receipts { - gu := new(big.Int) - if i != 0 { - gu.Sub(receipt.CumulativeGasUsed, receipts[i-1].CumulativeGasUsed) - } else { - gu.Set(receipt.CumulativeGasUsed) - } - - statelogger.Infof("[r] %v ~ %x (%x)\n", gu, receipt.PostState[0:4], receipt.Tx.Hash()) - } - */ - } - }() - + _, err = sm.ApplyDiff(state, parent, block) if err != nil { return err } @@ -235,12 +219,14 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return err } - if ethutil.Config.Paranoia { - valid, _ := ethtrie.ParanoiaCheck(state.trie) - if !valid { - err = fmt.Errorf("PARANOIA: World state trie corruption") + /* + if ethutil.Config.Paranoia { + valid, _ := ethtrie.ParanoiaCheck(state.trie) + if !valid { + err = fmt.Errorf("PARANOIA: World state trie corruption") + } } - } + */ if !block.State().Cmp(state) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index ebc050863..8e7b5fece 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -15,6 +15,18 @@ func (self Code) String() string { return strings.Join(Disassemble(self), " ") } +type Storage map[string]*ethutil.Value + +func (self Storage) Copy() Storage { + cpy := make(Storage) + for key, value := range self { + // XXX Do we need a 'value' copy or is this sufficient? + cpy[key] = value + } + + return cpy +} + type StateObject struct { // Address of the object address []byte @@ -27,7 +39,7 @@ type StateObject struct { script Code initScript Code - storage map[string]*ethutil.Value + storage Storage // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly @@ -41,7 +53,8 @@ type StateObject struct { } func (self *StateObject) Reset() { - self.storage = make(map[string]*ethutil.Value) + self.storage = make(Storage) + self.state.Reset() } // Converts an transaction in to a state object @@ -62,11 +75,12 @@ func MakeContract(tx *Transaction, state *State) *StateObject { func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. - address := ethutil.LeftPadBytes(addr, 20) + address := ethutil.Address(addr) object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - object.storage = make(map[string]*ethutil.Value) + object.storage = make(Storage) + object.gasPool = new(big.Int) return object } @@ -79,13 +93,6 @@ func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { return contract } -// Returns a newly created account -func NewAccount(address []byte, amount *big.Int) *StateObject { - account := &StateObject{address: address, Amount: amount, Nonce: 0} - - return account -} - func NewStateObjectFromBytes(address, data []byte) *StateObject { object := &StateObject{address: address} object.RlpDecode(data) @@ -95,7 +102,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -113,36 +120,73 @@ func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { self.setStorage(key.Bytes(), value) } -func (self *StateObject) getStorage(key []byte) *ethutil.Value { - k := ethutil.LeftPadBytes(key, 32) +func (self *StateObject) getStorage(k []byte) *ethutil.Value { + key := ethutil.LeftPadBytes(k, 32) - value := self.storage[string(k)] + value := self.storage[string(key)] if value == nil { - value = self.GetAddr(k) + value = self.GetAddr(key) - self.storage[string(k)] = value + if !value.IsNil() { + self.storage[string(key)] = value + } } return value + + //return self.GetAddr(key) } -func (self *StateObject) setStorage(key []byte, value *ethutil.Value) { - k := ethutil.LeftPadBytes(key, 32) +func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { + key := ethutil.LeftPadBytes(k, 32) + self.storage[string(key)] = value.Copy() - self.storage[string(k)] = value + /* + if value.BigInt().Cmp(ethutil.Big0) == 0 { + self.state.trie.Delete(string(key)) + return + } + + self.SetAddr(key, value) + */ } func (self *StateObject) Sync() { + /* + fmt.Println("############# BEFORE ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) + fmt.Println("#####################################") + */ for key, value := range self.storage { - if value.BigInt().Cmp(ethutil.Big0) == 0 { + if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 { + //data := self.getStorage([]byte(key)) + //fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data) self.state.trie.Delete(string(key)) continue } self.SetAddr([]byte(key), value) + } + + valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) + if !valid { + statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root) + self.state.trie = t2 } + + /* + fmt.Println("############# AFTER ################") + self.state.EachStorage(func(key string, value *ethutil.Value) { + fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes()) + }) + */ + //fmt.Printf("%x @:%x\n", self.Address(), self.state.Root()) } + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) @@ -154,13 +198,13 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -222,6 +266,8 @@ func (self *StateObject) Copy() *StateObject { } stateObject.script = ethutil.CopyBytes(self.script) stateObject.initScript = ethutil.CopyBytes(self.initScript) + stateObject.storage = self.storage.Copy() + stateObject.gasPool.Set(self.gasPool) return stateObject } @@ -280,6 +326,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) + c.gasPool = new(big.Int) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 314d858f2..8ed528c9f 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,8 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethtrie" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -44,7 +42,7 @@ func (self *StateTransition) Coinbase() *StateObject { return self.cb } - self.cb = self.state.GetAccount(self.coinbase) + self.cb = self.state.GetOrNewStateObject(self.coinbase) return self.cb } func (self *StateTransition) Sender() *StateObject { @@ -52,7 +50,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } - self.sen = self.state.GetAccount(self.tx.Sender()) + self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) return self.sen } @@ -65,7 +63,7 @@ func (self *StateTransition) Receiver() *StateObject { return self.rec } - self.rec = self.state.GetAccount(self.tx.Recipient) + self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) return self.rec } @@ -176,13 +174,16 @@ func (self *StateTransition) TransitionState() (err error) { return } - /* FIXME - * If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever - */ - var snapshot *State + if sender.Amount.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) + } + var snapshot *State // If the receiver is nil it's a contract (\0*32). if tx.CreatesContract() { + // Subtract the (irreversible) amount from the senders account + sender.SubAmount(self.value) + snapshot = self.state.Copy() // Create a new state object for the contract @@ -191,16 +192,17 @@ func (self *StateTransition) TransitionState() (err error) { if receiver == nil { return fmt.Errorf("Unable to create contract") } + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) } else { receiver = self.Receiver() - } - // Transfer value from sender to receiver - if err = self.transferValue(sender, receiver); err != nil { - return - } + // Subtract the amount from the senders account + sender.SubAmount(self.value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.value) - if snapshot == nil { snapshot = self.state.Copy() } @@ -275,20 +277,5 @@ func (self *StateTransition) Eval(script []byte, context *StateObject, typ strin func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { ret, _, err = closure.Call(vm, data) - if ethutil.Config.Paranoia { - var ( - context = closure.object - trie = context.state.trie - ) - - valid, t2 := ethtrie.ParanoiaCheck(trie) - if !valid { - // TODO FIXME ASAP - context.state.trie = t2 - - statelogger.Infoln("Warn: PARANOIA: Different state object roots during copy") - } - } - return } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index da3f9bcf2..5686a7edb 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -227,6 +227,14 @@ func (self *Receipt) String() string { self.CumulativeGasUsed) } +func (self *Receipt) Cmp(other *Receipt) bool { + if bytes.Compare(self.PostState, other.PostState) != 0 { + return false + } + + return true +} + // Transaction slice type for basic sorting type Transactions []*Transaction diff --git a/ethchain/vm.go b/ethchain/vm.go index f1794ff77..4fdf8b31a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -155,6 +155,15 @@ func (vm *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 vm.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + closure.object.Sync() + closure.object.state.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 { b = []byte{0} @@ -184,9 +193,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) - if val.IsEmpty() && len(y.Bytes()) > 0 { + if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { mult = ethutil.Big2 - } else if !val.IsEmpty() && len(y.Bytes()) == 0 { + } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { mult = ethutil.Big0 } else { mult = ethutil.Big1 @@ -447,7 +456,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case BYTE: require(2) val, th := stack.Popn() - if th.Cmp(big.NewInt(32)) < 0 { + if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { byt := big.NewInt(int64(val.Bytes()[th.Int64()])) stack.Push(byt) @@ -482,7 +491,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) - vm.Printf(" => %v", vm.vars.Origin) + vm.Printf(" => %x", vm.vars.Origin) case CALLER: caller := closure.caller.Address() stack.Push(ethutil.BigD(caller)) @@ -550,10 +559,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] - fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) + //fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) - fmt.Println(Code(mem.Get(mOff, l))) + //fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -743,6 +752,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if closure.object.Amount.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + closure.ReturnGas(gas, nil, nil) stack.Push(ethutil.BigFalse) diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go index 725846792..b8df2ad6f 100644 --- a/ethcrypto/mnemonic.go +++ b/ethcrypto/mnemonic.go @@ -6,30 +6,35 @@ import ( "os" "path" "path/filepath" - "runtime" "strconv" "strings" ) -func InitWords() []string { - _, thisfile, _, _ := runtime.Caller(1) - filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst") +func InitWords(wordsPath string) { + filename := path.Join(wordsPath, "mnemonic.words.lst") if _, err := os.Stat(filename); os.IsNotExist(err) { - fmt.Printf("reading mnemonic word list file 'mnemonic.words.lst' from source folder failed, looking in current folder.") - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - panic(fmt.Errorf("problem getting current folder: ", err)) - } + fmt.Printf("reading mnemonic word list file from supplied path not found. Looked in %s. Trying next option.\n", filename) + + dir := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "eth-go", "ethcrypto") filename = path.Join(dir, "mnemonic.words.lst") + if _, err := os.Stat(filename); os.IsNotExist(err) { + fmt.Printf("reading mnemonic word list file 'mnemonic.words.lst' from source folder failed: %s.\n", filename) + dir, err := filepath.Abs(filepath.Dir(os.Args[0])) + if err != nil { + panic(fmt.Errorf("problem getting current folder: ", err)) + } + filename = path.Join(dir, "mnemonic.words.lst") + } } + content, err := ioutil.ReadFile(filename) if err != nil { - panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err)) + panic(fmt.Errorf("All options for finding the mnemonic word list file 'mnemonic.words.lst' failed: ", err)) } - return strings.Split(string(content), "\n") + words = strings.Split(string(content), "\n") } -var words = InitWords() +var words []string // TODO: See if we can refactor this into a shared util lib if we need it multiple times func IndexOf(slice []string, value string) int64 { diff --git a/ethereum.go b/ethereum.go index c2d2f5241..c48ac00e4 100644 --- a/ethereum.go +++ b/ethereum.go @@ -81,6 +81,8 @@ type Ethereum struct { keyManager *ethcrypto.KeyManager clientIdentity ethwire.ClientIdentity + + isUpToDate bool } func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { @@ -108,6 +110,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager nat: nat, keyManager: keyManager, clientIdentity: clientIdentity, + isUpToDate: true, } ethereum.reactor = ethreact.New() @@ -158,7 +161,7 @@ func (s *Ethereum) IsUpToDate() bool { upToDate := true eachPeer(s.peers, func(peer *Peer, e *list.Element) { if atomic.LoadInt32(&peer.connected) == 1 { - if peer.catchingUp == true { + if peer.catchingUp == true && peer.versionKnown { upToDate = false } } @@ -373,6 +376,7 @@ func (s *Ethereum) Start(seed bool) { // Start the reaping processes go s.ReapDeadPeerHandler() + go s.update() if seed { s.Seed() @@ -514,3 +518,23 @@ out: ethlogger.Debugln("succesfully disestablished UPnP port mapping") } } + +func (self *Ethereum) update() { + upToDateTimer := time.NewTicker(1 * time.Second) + +out: + for { + select { + case <-upToDateTimer.C: + if self.IsUpToDate() && !self.isUpToDate { + self.reactor.Post("chainSync", false) + self.isUpToDate = true + } else if !self.IsUpToDate() && self.isUpToDate { + self.reactor.Post("chainSync", true) + self.isUpToDate = false + } + case <-self.quit: + break out + } + } +} diff --git a/ethlog/loggers.go b/ethlog/loggers.go index 59021d169..b2760534b 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -119,7 +119,7 @@ func AddLogSystem(logSystem LogSystem) { mutex.Lock() defer mutex.Unlock() if logSystems == nil { - logMessages = make(chan *logMessage, 5) + logMessages = make(chan *logMessage, 10) quit = make(chan chan error, 1) drained = make(chan bool, 1) go start() diff --git a/ethminer/miner.go b/ethminer/miner.go index 5151ee885..602ab0f35 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -21,28 +21,32 @@ type Miner struct { block *ethchain.Block powChan chan []byte powQuitChan chan ethreact.Event - quitChan chan bool + quitChan chan chan error } -func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { +func (self *Miner) GetPow() ethchain.PoW { + return self.pow +} + +func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) *Miner { miner := Miner{ pow: ðchain.EasyPow{}, ethereum: ethereum, coinbase: coinbase, } - // Insert initial TXs in our little miner 'pool' - miner.txs = ethereum.TxPool().Flush() - miner.block = ethereum.BlockChain().NewBlock(miner.coinbase) - - return miner + return &miner } func (miner *Miner) Start() { miner.reactChan = make(chan ethreact.Event, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in miner.powChan = make(chan []byte, 1) // This is the channel that receives valid sha hashes for a given block miner.powQuitChan = make(chan ethreact.Event, 1) // This is the channel that can exit the miner thread - miner.quitChan = make(chan bool, 1) + miner.quitChan = make(chan chan error, 1) + + // Insert initial TXs in our little miner 'pool' + miner.txs = miner.ethereum.TxPool().Flush() + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase) // Prepare inital block //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) @@ -61,15 +65,17 @@ func (miner *Miner) Start() { reactor.Subscribe("newTx:pre", miner.powQuitChan) logger.Infoln("Started") + + reactor.Post("miner:start", miner) } func (miner *Miner) listener() { -out: for { select { - case <-miner.quitChan: + case status := <-miner.quitChan: logger.Infoln("Stopped") - break out + status <- nil + return case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { @@ -127,7 +133,9 @@ out: func (miner *Miner) Stop() { logger.Infoln("Stopping...") - miner.quitChan <- true + status := make(chan error) + miner.quitChan <- status + <-status reactor := miner.ethereum.Reactor() reactor.Unsubscribe("newBlock", miner.powQuitChan) @@ -137,6 +145,8 @@ func (miner *Miner) Stop() { close(miner.powQuitChan) close(miner.quitChan) + + reactor.Post("miner:stop", miner) } func (self *Miner) mineNewBlock() { diff --git a/ethpub/pub.go b/ethpub/pub.go index f409d136b..5d01a7a44 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -179,6 +179,19 @@ func FindAddressInNameReg(stateManager *ethchain.StateManager, name string) []by return nil } +func FindNameInNameReg(stateManager *ethchain.StateManager, addr []byte) string { + nameReg := EthereumConfig(stateManager).NameReg() + if nameReg != nil { + addr = ethutil.LeftPadBytes(addr, 32) + + reg := nameReg.GetStorage(ethutil.BigD(addr)) + + return strings.TrimRight(reg.Str(), "\x00") + } + + return "" +} + func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool diff --git a/ethpub/types.go b/ethpub/types.go index 5d41269c8..9e5159a4c 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "strings" ) @@ -46,6 +47,7 @@ type PBlock struct { Transactions string `json:"transactions"` Time int64 `json:"time"` Coinbase string `json:"coinbase"` + Name string `json:"name"` GasLimit string `json:"gasLimit"` GasUsed string `json:"gasUsed"` } @@ -212,6 +214,10 @@ func (c *PStateObject) IsContract() bool { return false } +func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) { + self.object.State().EachStorage(cb) +} + type KeyVal struct { Key string Value string diff --git a/ethtrie/trie.go b/ethtrie/trie.go index 38c78e7f4..f0f3fe5a8 100644 --- a/ethtrie/trie.go +++ b/ethtrie/trie.go @@ -5,10 +5,12 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" - "reflect" + _ "reflect" "sync" ) +func __ignore() { fmt.Println("") } + func ParanoiaCheck(t1 *Trie) (bool, *Trie) { t2 := NewTrie(ethutil.Config.Db, "") @@ -269,8 +271,7 @@ func (t *Trie) getState(node interface{}, key []int) interface{} { } // It shouldn't come this far - fmt.Println("getState unexpected return") - return "" + panic("unexpected return") } func (t *Trie) getNode(node interface{}) *ethutil.Value { @@ -287,7 +288,9 @@ func (t *Trie) getNode(node interface{}) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(str)) } - return t.cache.Get(n.Bytes()) + data := t.cache.Get(n.Bytes()) + + return data } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { @@ -323,7 +326,8 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter // New node n := ethutil.NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + if node == nil || n.Len() == 0 { + //if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { newNode := []interface{}{CompactEncode(key), value} return t.Put(newNode) @@ -385,17 +389,22 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter return t.Put(newNode) } - return "" + panic("unexpected end") } func (t *Trie) deleteState(node interface{}, key []int) interface{} { if len(key) == 0 { + println("<empty ret>") return "" } // New node n := ethutil.NewValue(node) - if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + //if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + if node == nil || n.Len() == 0 { + //return nil + //fmt.Printf("<empty ret> %x %d\n", n, len(n.Bytes())) + return "" } @@ -408,10 +417,17 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} { // Matching key pair (ie. there's already an object with this key) if CompareIntSlice(k, key) { + //fmt.Printf("<delete ret> %x\n", v) + return "" } else if CompareIntSlice(key[:len(k)], k) { hash := t.deleteState(v, key[len(k):]) child := t.getNode(hash) + /* + if child.IsNil() { + return node + } + */ var newNode []interface{} if child.Len() == 2 { @@ -421,6 +437,8 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} { newNode = []interface{}{currentNode.Get(0).Str(), hash} } + //fmt.Printf("%x\n", newNode) + return t.Put(newNode) } else { return node @@ -463,10 +481,11 @@ func (t *Trie) deleteState(node interface{}, key []int) interface{} { newNode = n } + //fmt.Printf("%x\n", newNode) return t.Put(newNode) } - return "" + panic("unexpected return") } type TrieIterator struct { diff --git a/ethtrie/trie_test.go b/ethtrie/trie_test.go index a3d4547d7..3989a8f45 100644 --- a/ethtrie/trie_test.go +++ b/ethtrie/trie_test.go @@ -1,16 +1,17 @@ package ethtrie import ( - "bytes" - "encoding/hex" - "encoding/json" + _ "bytes" + _ "encoding/hex" + _ "encoding/json" "fmt" - "io/ioutil" - "math/rand" - "net/http" - "reflect" + "github.com/ethereum/eth-go/ethutil" + _ "io/ioutil" + _ "math/rand" + _ "net/http" + _ "reflect" "testing" - "time" + _ "time" ) const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" @@ -42,6 +43,7 @@ func New() (*MemDatabase, *Trie) { return db, NewTrie(db, "") } +/* func TestTrieSync(t *testing.T) { db, trie := New() @@ -251,8 +253,8 @@ func TestRemote(t *testing.T) { trie.Update(get(key), get(value)) } - a := NewValue(h(test.Root)).Bytes() - b := NewValue(trie.Root).Bytes() + a := ethutil.NewValue(h(test.Root)).Bytes() + b := ethutil.NewValue(trie.Root).Bytes() if bytes.Compare(a, b) != 0 { t.Errorf("%-10s: %x %x", test.Name, a, b) } @@ -267,12 +269,12 @@ func TestTrieReplay(t *testing.T) { } _, trie2 := New() - trie.NewIterator().Each(func(key string, v *Value) { + trie.NewIterator().Each(func(key string, v *ethutil.Value) { trie2.Update(key, v.Str()) }) - a := NewValue(trie.Root).Bytes() - b := NewValue(trie2.Root).Bytes() + a := ethutil.NewValue(trie.Root).Bytes() + b := ethutil.NewValue(trie2.Root).Bytes() if bytes.Compare(a, b) != 0 { t.Errorf("%s %x %x\n", test.Name, trie.Root, trie2.Root) } @@ -329,3 +331,90 @@ func TestRegression(t *testing.T) { } } } + +func TestDelete(t *testing.T) { + _, trie := New() + + trie.Update("a", "jeffreytestlongstring") + trie.Update("aa", "otherstring") + trie.Update("aaa", "othermorestring") + trie.Update("aabbbbccc", "hithere") + trie.Update("abbcccdd", "hstanoehutnaheoustnh") + trie.Update("rnthaoeuabbcccdd", "hstanoehutnaheoustnh") + trie.Update("rneuabbcccdd", "hstanoehutnaheoustnh") + trie.Update("rneuabboeusntahoeucccdd", "hstanoehutnaheoustnh") + trie.Update("rnxabboeusntahoeucccdd", "hstanoehutnaheoustnh") + trie.Delete("aaboaestnuhbccc") + trie.Delete("a") + trie.Update("a", "nthaonethaosentuh") + trie.Update("c", "shtaosntehua") + trie.Delete("a") + trie.Update("aaaa", "testmegood") + + fmt.Println("aa =>", trie.Get("aa")) + _, t2 := New() + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + if key == "aaaa" { + t2.Update(key, v.Str()) + } else { + t2.Update(key, v.Str()) + } + }) + + a := ethutil.NewValue(trie.Root).Bytes() + b := ethutil.NewValue(t2.Root).Bytes() + + fmt.Printf("o: %x\nc: %x\n", a, b) +} +*/ + +func TestRndCase(t *testing.T) { + _, trie := New() + + data := []struct{ k, v string }{ + {"0000000000000000000000000000000000000000000000000000000000000001", "a07573657264617461000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000003", "8453bb5b31"}, + {"0000000000000000000000000000000000000000000000000000000000000004", "850218711a00"}, + {"0000000000000000000000000000000000000000000000000000000000000005", "9462d7705bd0b3ecbc51a8026a25597cb28a650c79"}, + {"0000000000000000000000000000000000000000000000000000000000000010", "947e70f9460402290a3e487dae01f610a1a8218fda"}, + {"0000000000000000000000000000000000000000000000000000000000000111", "01"}, + {"0000000000000000000000000000000000000000000000000000000000000112", "a053656e6174650000000000000000000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000113", "a053656e6174650000000000000000000000000000000000000000000000000000"}, + {"53656e6174650000000000000000000000000000000000000000000000000000", "94977e3f62f5e1ed7953697430303a3cfa2b5b736e"}, + } + for _, e := range data { + trie.Update(string(ethutil.Hex2Bytes(e.k)), string(ethutil.Hex2Bytes(e.v))) + } + + fmt.Printf("root after update %x\n", trie.Root) + trie.NewIterator().Each(func(k string, v *ethutil.Value) { + fmt.Printf("%x %x\n", k, v.Bytes()) + }) + + data = []struct{ k, v string }{ + {"0000000000000000000000000000000000000000000000000000000000000112", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000001", ""}, + {"436f757274000000000000000000000000000000000000000000000000000002", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000000", ""}, + {"436f757274000000000000000000000000000000000000000000000000000000", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000001", ""}, + {"0000000000000000000000000000000000000000000000000000000000000113", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000000", ""}, + {"436974697a656e73000000000000000000000000000000000000000000000002", ""}, + {"436f757274000000000000000000000000000000000000000000000000000001", ""}, + {"0000000000000000000000000000000000000000000000000000000000000111", ""}, + {"53656e6174650000000000000000000000000000000000000000000000000002", ""}, + } + + for _, e := range data { + trie.Delete(string(ethutil.Hex2Bytes(e.k))) + } + + fmt.Printf("root after delete %x\n", trie.Root) + + trie.NewIterator().Each(func(k string, v *ethutil.Value) { + fmt.Printf("%x %x\n", k, v.Bytes()) + }) + + fmt.Printf("%x\n", trie.Get(string(ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")))) +} diff --git a/ethutil/bytes.go b/ethutil/bytes.go index d68a69433..34fff7d42 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -118,7 +118,7 @@ func FormatData(data string) []byte { // Simple stupid d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { - return RightPadBytes([]byte(data), 32) + return RightPadBytes([]byte(data[1:len(data)-1]), 32) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { @@ -149,3 +149,17 @@ func LeftPadBytes(slice []byte, l int) []byte { return padded } + +func Address(slice []byte) (addr []byte) { + if len(slice) < 20 { + addr = LeftPadBytes(slice, 20) + } else if len(slice) > 20 { + addr = slice[len(slice)-20:] + } else { + addr = slice + } + + addr = CopyBytes(addr) + + return +} diff --git a/ethutil/config.go b/ethutil/config.go index 2f3d706fe..41bece21d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -14,6 +14,7 @@ type ConfigManager struct { ExecPath string Debug bool Diff bool + DiffType string Paranoia bool conf *globalconf.GlobalConf diff --git a/ethutil/value.go b/ethutil/value.go index b37b33c28..fba7426d1 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -40,13 +40,9 @@ func (val *Value) Len() int { //return val.kind.Len() if data, ok := val.Val.([]interface{}); ok { return len(data) - } else if data, ok := val.Val.([]byte); ok { - return len(data) - } else if data, ok := val.Val.(string); ok { - return len(data) } - return 0 + return len(val.Bytes()) } func (val *Value) Raw() interface{} { @@ -118,6 +114,8 @@ func (val *Value) Bytes() []byte { return []byte{s} } else if s, ok := val.Val.(string); ok { return []byte(s) + } else if s, ok := val.Val.(*big.Int); ok { + return s.Bytes() } return []byte{} @@ -190,6 +188,19 @@ func (val *Value) Get(idx int) *Value { return NewValue(nil) } +func (self *Value) Copy() *Value { + switch val := self.Val.(type) { + case *big.Int: + return NewValue(new(big.Int).Set(val)) + case []byte: + return NewValue(CopyBytes(val)) + default: + return NewValue(self.Val) + } + + return nil +} + func (val *Value) Cmp(o *Value) bool { return reflect.DeepEqual(val.Val, o.Val) } @@ -319,7 +319,7 @@ func (p *Peer) HandleInbound() { for atomic.LoadInt32(&p.disconnect) == 0 { // HMM? - time.Sleep(500 * time.Millisecond) + time.Sleep(50 * time.Millisecond) // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { @@ -328,6 +328,7 @@ func (p *Peer) HandleInbound() { for _, msg := range msgs { peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data) + nextMsg: switch msg.Type { case ethwire.MsgHandshakeTy: // Version message @@ -373,6 +374,7 @@ func (p *Peer) HandleInbound() { p.diverted = false if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { p.SyncWithPeerToLastKnown() + break nextMsg } break } @@ -385,10 +387,11 @@ func (p *Peer) HandleInbound() { p.blocksRequested = p.blocksRequested * 2 peerlogger.Infof("No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) - p.catchingUp = false p.FindCommonParentBlock() - break + break nextMsg } + + p.catchingUp = false } for i := msg.Data.Len() - 1; i >= 0; i-- { @@ -410,7 +413,7 @@ func (p *Peer) HandleInbound() { } } - if msg.Data.Len() == 0 { + if msg.Data.Len() <= 1 { // Set catching up to false if // the peer has nothing left to give p.catchingUp = false @@ -754,7 +757,7 @@ 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(10)}) + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(30)}) p.QueueMessage(msg) peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) |