merge upstream
This commit is contained in:
		@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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())
 | 
			
		||||
 
 | 
			
		||||
@@ -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())
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								ethereum.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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() {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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"))))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ type ConfigManager struct {
 | 
			
		||||
	ExecPath string
 | 
			
		||||
	Debug    bool
 | 
			
		||||
	Diff     bool
 | 
			
		||||
	DiffType string
 | 
			
		||||
	Paranoia bool
 | 
			
		||||
 | 
			
		||||
	conf *globalconf.GlobalConf
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								peer.go
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								peer.go
									
									
									
									
									
								
							@@ -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())
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user