merge upstream
This commit is contained in:
commit
3d5db7288f
|
@ -24,6 +24,10 @@ func Disassemble(script []byte) (asm []string) {
|
||||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||||
pc.Add(pc, ethutil.Big1)
|
pc.Add(pc, ethutil.Big1)
|
||||||
a := int64(op) - int64(PUSH1) + 1
|
a := int64(op) - int64(PUSH1) + 1
|
||||||
|
if int(pc.Int64()+a) > len(script) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
data := script[pc.Int64() : pc.Int64()+a]
|
data := script[pc.Int64() : pc.Int64()+a]
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
data = []byte{0}
|
data = []byte{0}
|
||||||
|
|
|
@ -294,7 +294,6 @@ func (bc *BlockChain) setLastBlock() {
|
||||||
bc.LastBlockHash = block.Hash()
|
bc.LastBlockHash = block.Hash()
|
||||||
bc.LastBlockNumber = block.Number.Uint64()
|
bc.LastBlockNumber = block.Number.Uint64()
|
||||||
|
|
||||||
chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber)
|
|
||||||
} else {
|
} else {
|
||||||
AddTestNetFunds(bc.genesisBlock)
|
AddTestNetFunds(bc.genesisBlock)
|
||||||
|
|
||||||
|
@ -309,7 +308,7 @@ func (bc *BlockChain) setLastBlock() {
|
||||||
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
||||||
bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
|
bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
|
||||||
|
|
||||||
chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash())
|
chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
|
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
|
||||||
|
|
|
@ -84,13 +84,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) {
|
||||||
|
|
||||||
func (c *Closure) Return(ret []byte) []byte {
|
func (c *Closure) Return(ret []byte) []byte {
|
||||||
// Return the remaining gas to the caller
|
// Return the remaining gas to the caller
|
||||||
// If no caller is present return it to
|
c.caller.ReturnGas(c.Gas, c.Price, c.State)
|
||||||
// the origin (i.e. contract or tx)
|
|
||||||
if c.caller != nil {
|
|
||||||
c.caller.ReturnGas(c.Gas, c.Price, c.State)
|
|
||||||
} else {
|
|
||||||
c.object.ReturnGas(c.Gas, c.Price, c.State)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package ethchain
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/eth-go/ethcrypto"
|
"github.com/ethereum/eth-go/ethcrypto"
|
||||||
"github.com/ethereum/eth-go/ethlog"
|
"github.com/ethereum/eth-go/ethlog"
|
||||||
"github.com/ethereum/eth-go/ethreact"
|
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/obscuren/sha3"
|
"github.com/obscuren/sha3"
|
||||||
"hash"
|
"hash"
|
||||||
|
@ -15,7 +14,7 @@ import (
|
||||||
var powlogger = ethlog.NewLogger("POW")
|
var powlogger = ethlog.NewLogger("POW")
|
||||||
|
|
||||||
type PoW interface {
|
type PoW interface {
|
||||||
Search(block *Block, reactChan chan ethreact.Event) []byte
|
Search(block *Block, reactChan chan ethutil.React) []byte
|
||||||
Verify(hash []byte, diff *big.Int, nonce []byte) bool
|
Verify(hash []byte, diff *big.Int, nonce []byte) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +22,7 @@ type EasyPow struct {
|
||||||
hash *big.Int
|
hash *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte {
|
func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
hash := block.HashNoNonce()
|
hash := block.HashNoNonce()
|
||||||
diff := block.Difficulty
|
diff := block.Difficulty
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ethchain
|
package ethchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/ethereum/eth-go/ethcrypto"
|
"github.com/ethereum/eth-go/ethcrypto"
|
||||||
"github.com/ethereum/eth-go/ethtrie"
|
"github.com/ethereum/eth-go/ethtrie"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
|
@ -26,6 +27,131 @@ func NewState(trie *ethtrie.Trie) *State {
|
||||||
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
|
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate over each storage address and yield callback
|
||||||
|
func (s *State) EachStorage(cb ethtrie.EachCallback) {
|
||||||
|
it := s.trie.NewIterator()
|
||||||
|
it.Each(cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the balance from the given address or 0 if object not found
|
||||||
|
func (self *State) GetBalance(addr []byte) *big.Int {
|
||||||
|
stateObject := self.GetStateObject(addr)
|
||||||
|
if stateObject != nil {
|
||||||
|
return stateObject.Amount
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethutil.Big0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *State) GetNonce(addr []byte) uint64 {
|
||||||
|
stateObject := self.GetStateObject(addr)
|
||||||
|
if stateObject != nil {
|
||||||
|
return stateObject.Nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setting, updating & deleting state object methods
|
||||||
|
//
|
||||||
|
|
||||||
|
// Update the given state object and apply it to state trie
|
||||||
|
func (self *State) UpdateStateObject(stateObject *StateObject) {
|
||||||
|
addr := stateObject.Address()
|
||||||
|
|
||||||
|
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
|
||||||
|
|
||||||
|
self.trie.Update(string(addr), string(stateObject.RlpEncode()))
|
||||||
|
|
||||||
|
self.manifest.AddObjectChange(stateObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the given state object and delete it from the state trie
|
||||||
|
func (self *State) DeleteStateObject(stateObject *StateObject) {
|
||||||
|
self.trie.Delete(string(stateObject.Address()))
|
||||||
|
|
||||||
|
delete(self.stateObjects, string(stateObject.Address()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve a state object given my the address. Nil if not found
|
||||||
|
func (self *State) GetStateObject(addr []byte) *StateObject {
|
||||||
|
stateObject := self.stateObjects[string(addr)]
|
||||||
|
if stateObject != nil {
|
||||||
|
return stateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
data := self.trie.Get(string(addr))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
stateObject = NewStateObjectFromBytes(addr, []byte(data))
|
||||||
|
self.stateObjects[string(addr)] = stateObject
|
||||||
|
|
||||||
|
return stateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve a state object or create a new state object if nil
|
||||||
|
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
|
||||||
|
stateObject := self.GetStateObject(addr)
|
||||||
|
if stateObject == nil {
|
||||||
|
stateObject = self.NewStateObject(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a state object whether it exist in the trie or not
|
||||||
|
func (self *State) NewStateObject(addr []byte) *StateObject {
|
||||||
|
statelogger.Infof("(+) %x\n", addr)
|
||||||
|
|
||||||
|
stateObject := NewStateObject(addr)
|
||||||
|
self.stateObjects[string(addr)] = stateObject
|
||||||
|
|
||||||
|
return stateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
func (self *State) GetAccount(addr []byte) *StateObject {
|
||||||
|
return self.GetOrNewStateObject(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setting, copying of the state methods
|
||||||
|
//
|
||||||
|
|
||||||
|
func (s *State) Cmp(other *State) bool {
|
||||||
|
return s.trie.Cmp(other.trie)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *State) Copy() *State {
|
||||||
|
if self.trie != nil {
|
||||||
|
state := NewState(self.trie.Copy())
|
||||||
|
for k, stateObject := range self.stateObjects {
|
||||||
|
state.stateObjects[k] = stateObject.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *State) Set(state *State) {
|
||||||
|
if state == nil {
|
||||||
|
panic("Tried setting 'state' to nil through 'Set'")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.trie = state.trie
|
||||||
|
self.stateObjects = state.stateObjects
|
||||||
|
//*self = *state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) Root() interface{} {
|
||||||
|
return s.trie.Root
|
||||||
|
}
|
||||||
|
|
||||||
// Resets the trie and all siblings
|
// Resets the trie and all siblings
|
||||||
func (s *State) Reset() {
|
func (s *State) Reset() {
|
||||||
s.trie.Undo()
|
s.trie.Undo()
|
||||||
|
@ -36,7 +162,8 @@ func (s *State) Reset() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
stateObject.state.Reset()
|
//stateObject.state.Reset()
|
||||||
|
stateObject.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Empty()
|
s.Empty()
|
||||||
|
@ -67,109 +194,29 @@ func (self *State) Empty() {
|
||||||
func (self *State) Update() {
|
func (self *State) Update() {
|
||||||
for _, stateObject := range self.stateObjects {
|
for _, stateObject := range self.stateObjects {
|
||||||
if stateObject.remove {
|
if stateObject.remove {
|
||||||
self.trie.Delete(string(stateObject.Address()))
|
self.DeleteStateObject(stateObject)
|
||||||
} else {
|
} else {
|
||||||
|
stateObject.Sync()
|
||||||
|
|
||||||
self.UpdateStateObject(stateObject)
|
self.UpdateStateObject(stateObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Purges the current trie.
|
// FIXME trie delete is broken
|
||||||
func (s *State) Purge() int {
|
valid, t2 := ethtrie.ParanoiaCheck(self.trie)
|
||||||
return s.trie.NewIterator().Purge()
|
if !valid {
|
||||||
}
|
self.trie = t2
|
||||||
|
|
||||||
func (s *State) EachStorage(cb ethtrie.EachCallback) {
|
|
||||||
it := s.trie.NewIterator()
|
|
||||||
it.Each(cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) ResetStateObject(stateObject *StateObject) {
|
|
||||||
delete(self.stateObjects, string(stateObject.Address()))
|
|
||||||
|
|
||||||
stateObject.state.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) UpdateStateObject(stateObject *StateObject) {
|
|
||||||
addr := stateObject.Address()
|
|
||||||
|
|
||||||
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
|
|
||||||
|
|
||||||
self.trie.Update(string(addr), string(stateObject.RlpEncode()))
|
|
||||||
|
|
||||||
self.manifest.AddObjectChange(stateObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) GetStateObject(addr []byte) *StateObject {
|
|
||||||
stateObject := self.stateObjects[string(addr)]
|
|
||||||
if stateObject != nil {
|
|
||||||
return stateObject
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data := self.trie.Get(string(addr))
|
// Debug stuff
|
||||||
if len(data) == 0 {
|
func (self *State) CreateOutputForDiff() {
|
||||||
return nil
|
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)
|
||||||
|
stateObject.state.EachStorage(func(addr string, value *ethutil.Value) {
|
||||||
|
fmt.Printf("0x%x 0x%x\n", addr, value.Bytes())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
stateObject = NewStateObjectFromBytes(addr, []byte(data))
|
|
||||||
self.stateObjects[string(addr)] = stateObject
|
|
||||||
|
|
||||||
return stateObject
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
|
|
||||||
stateObject := self.GetStateObject(addr)
|
|
||||||
if stateObject == nil {
|
|
||||||
stateObject = self.NewStateObject(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return stateObject
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) NewStateObject(addr []byte) *StateObject {
|
|
||||||
statelogger.Infof("(+) %x\n", addr)
|
|
||||||
|
|
||||||
stateObject := NewStateObject(addr)
|
|
||||||
self.stateObjects[string(addr)] = stateObject
|
|
||||||
|
|
||||||
return stateObject
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) GetAccount(addr []byte) *StateObject {
|
|
||||||
return self.GetOrNewStateObject(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) Cmp(other *State) bool {
|
|
||||||
return s.trie.Cmp(other.trie)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) Copy() *State {
|
|
||||||
if self.trie != nil {
|
|
||||||
state := NewState(self.trie.Copy())
|
|
||||||
for k, stateObject := range self.stateObjects {
|
|
||||||
state.stateObjects[k] = stateObject.Copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *State) Set(state *State) {
|
|
||||||
if state == nil {
|
|
||||||
panic("Tried setting 'state' to nil through 'Set'")
|
|
||||||
}
|
|
||||||
|
|
||||||
*self = *state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) Put(key, object []byte) {
|
|
||||||
s.trie.Update(string(key), string(object))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) Root() interface{} {
|
|
||||||
return s.trie.Root
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object manifest
|
// Object manifest
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/eth-go/ethcrypto"
|
"github.com/ethereum/eth-go/ethcrypto"
|
||||||
"github.com/ethereum/eth-go/ethlog"
|
"github.com/ethereum/eth-go/ethlog"
|
||||||
"github.com/ethereum/eth-go/ethreact"
|
|
||||||
"github.com/ethereum/eth-go/ethtrie"
|
"github.com/ethereum/eth-go/ethtrie"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/ethereum/eth-go/ethwire"
|
"github.com/ethereum/eth-go/ethwire"
|
||||||
|
@ -37,7 +36,7 @@ type EthManager interface {
|
||||||
BlockChain() *BlockChain
|
BlockChain() *BlockChain
|
||||||
TxPool() *TxPool
|
TxPool() *TxPool
|
||||||
Broadcast(msgType ethwire.MsgType, data []interface{})
|
Broadcast(msgType ethwire.MsgType, data []interface{})
|
||||||
Reactor() *ethreact.ReactorEngine
|
Reactor() *ethutil.ReactorEngine
|
||||||
PeerCount() int
|
PeerCount() int
|
||||||
IsMining() bool
|
IsMining() bool
|
||||||
IsListening() bool
|
IsListening() bool
|
||||||
|
@ -67,6 +66,11 @@ type StateManager struct {
|
||||||
// Mining state. The mining state is used purely and solely by the mining
|
// Mining state. The mining state is used purely and solely by the mining
|
||||||
// operation.
|
// operation.
|
||||||
miningState *State
|
miningState *State
|
||||||
|
|
||||||
|
// The last attempted block is mainly used for debugging purposes
|
||||||
|
// This does not have to be a valid block and will be set during
|
||||||
|
// 'Process' & canonical validation.
|
||||||
|
lastAttemptedBlock *Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateManager(ethereum EthManager) *StateManager {
|
func NewStateManager(ethereum EthManager) *StateManager {
|
||||||
|
@ -146,6 +150,10 @@ done:
|
||||||
|
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
handled = append(handled, tx)
|
handled = append(handled, tx)
|
||||||
|
|
||||||
|
if ethutil.Config.Diff {
|
||||||
|
state.CreateOutputForDiff()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.GasUsed = totalUsedGas
|
parent.GasUsed = totalUsedGas
|
||||||
|
@ -166,6 +174,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
|
||||||
return ParentError(block.PrevHash)
|
return ParentError(block.PrevHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sm.lastAttemptedBlock = block
|
||||||
|
|
||||||
var (
|
var (
|
||||||
parent = sm.bc.GetBlock(block.PrevHash)
|
parent = sm.bc.GetBlock(block.PrevHash)
|
||||||
state = parent.State()
|
state = parent.State()
|
||||||
|
@ -177,6 +187,10 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
|
||||||
// before that.
|
// before that.
|
||||||
defer state.Reset()
|
defer state.Reset()
|
||||||
|
|
||||||
|
if ethutil.Config.Diff {
|
||||||
|
fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number)
|
||||||
|
}
|
||||||
|
|
||||||
receipts, err := sm.ApplyDiff(state, parent, block)
|
receipts, err := sm.ApplyDiff(state, parent, block)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -27,6 +27,8 @@ type StateObject struct {
|
||||||
script Code
|
script Code
|
||||||
initScript Code
|
initScript Code
|
||||||
|
|
||||||
|
storage map[string]*ethutil.Value
|
||||||
|
|
||||||
// Total gas pool is the total amount of gas currently
|
// Total gas pool is the total amount of gas currently
|
||||||
// left if this object is the coinbase. Gas is directly
|
// left if this object is the coinbase. Gas is directly
|
||||||
// purchased of the coinbase.
|
// purchased of the coinbase.
|
||||||
|
@ -38,6 +40,10 @@ type StateObject struct {
|
||||||
remove bool
|
remove bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StateObject) Reset() {
|
||||||
|
self.storage = make(map[string]*ethutil.Value)
|
||||||
|
}
|
||||||
|
|
||||||
// Converts an transaction in to a state object
|
// Converts an transaction in to a state object
|
||||||
func MakeContract(tx *Transaction, state *State) *StateObject {
|
func MakeContract(tx *Transaction, state *State) *StateObject {
|
||||||
// Create contract if there's no recipient
|
// Create contract if there's no recipient
|
||||||
|
@ -55,14 +61,19 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateObject(addr []byte) *StateObject {
|
func NewStateObject(addr []byte) *StateObject {
|
||||||
object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)}
|
// 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)
|
||||||
|
|
||||||
|
object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)}
|
||||||
object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
|
object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
|
||||||
|
object.storage = make(map[string]*ethutil.Value)
|
||||||
|
|
||||||
return object
|
return object
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
|
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
|
||||||
contract := &StateObject{address: address, Amount: Amount, Nonce: 0}
|
contract := NewStateObject(address)
|
||||||
|
contract.Amount = Amount
|
||||||
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
|
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
|
||||||
|
|
||||||
return contract
|
return contract
|
||||||
|
@ -84,6 +95,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject {
|
||||||
|
|
||||||
func (self *StateObject) MarkForDeletion() {
|
func (self *StateObject) MarkForDeletion() {
|
||||||
self.remove = true
|
self.remove = true
|
||||||
|
statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
|
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
|
||||||
|
@ -94,24 +106,43 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) {
|
||||||
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
|
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) {
|
func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value {
|
||||||
addr := ethutil.BigToBytes(num, 256)
|
return self.getStorage(key.Bytes())
|
||||||
|
}
|
||||||
|
func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) {
|
||||||
|
self.setStorage(key.Bytes(), value)
|
||||||
|
}
|
||||||
|
|
||||||
if val.BigInt().Cmp(ethutil.Big0) == 0 {
|
func (self *StateObject) getStorage(key []byte) *ethutil.Value {
|
||||||
c.state.trie.Delete(string(addr))
|
k := ethutil.LeftPadBytes(key, 32)
|
||||||
|
|
||||||
return
|
value := self.storage[string(k)]
|
||||||
|
if value == nil {
|
||||||
|
value = self.GetAddr(k)
|
||||||
|
|
||||||
|
self.storage[string(k)] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetAddr(addr, val)
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value {
|
func (self *StateObject) setStorage(key []byte, value *ethutil.Value) {
|
||||||
nb := ethutil.BigToBytes(num, 256)
|
k := ethutil.LeftPadBytes(key, 32)
|
||||||
|
|
||||||
return c.GetAddr(nb)
|
self.storage[string(k)] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StateObject) Sync() {
|
||||||
|
for key, value := range self.storage {
|
||||||
|
if value.BigInt().Cmp(ethutil.Big0) == 0 {
|
||||||
|
self.state.trie.Delete(string(key))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
self.SetAddr([]byte(key), value)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
|
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
|
||||||
if int64(len(c.script)-1) < pc.Int64() {
|
if int64(len(c.script)-1) < pc.Int64() {
|
||||||
return ethutil.NewValue(0)
|
return ethutil.NewValue(0)
|
||||||
|
@ -248,6 +279,7 @@ func (c *StateObject) RlpDecode(data []byte) {
|
||||||
c.Nonce = decoder.Get(0).Uint()
|
c.Nonce = decoder.Get(0).Uint()
|
||||||
c.Amount = decoder.Get(1).BigInt()
|
c.Amount = decoder.Get(1).BigInt()
|
||||||
c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
|
c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
|
||||||
|
c.storage = make(map[string]*ethutil.Value)
|
||||||
|
|
||||||
c.ScriptHash = decoder.Get(3).Bytes()
|
c.ScriptHash = decoder.Get(3).Bytes()
|
||||||
|
|
||||||
|
|
|
@ -164,8 +164,6 @@ func (self *StateTransition) TransitionState() (err error) {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
sender.Nonce += 1
|
sender.Nonce += 1
|
||||||
|
|
||||||
receiver = self.Receiver()
|
|
||||||
|
|
||||||
// Transaction gas
|
// Transaction gas
|
||||||
if err = self.UseGas(GasTx); err != nil {
|
if err = self.UseGas(GasTx); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -178,13 +176,23 @@ func (self *StateTransition) TransitionState() (err error) {
|
||||||
return
|
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 the receiver is nil it's a contract (\0*32).
|
// If the receiver is nil it's a contract (\0*32).
|
||||||
if receiver == nil {
|
if tx.CreatesContract() {
|
||||||
|
snapshot = self.state.Copy()
|
||||||
|
|
||||||
// Create a new state object for the contract
|
// Create a new state object for the contract
|
||||||
receiver = self.MakeStateObject(self.state, tx)
|
receiver = self.MakeStateObject(self.state, tx)
|
||||||
|
self.rec = receiver
|
||||||
if receiver == nil {
|
if receiver == nil {
|
||||||
return fmt.Errorf("Unable to create contract")
|
return fmt.Errorf("Unable to create contract")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
receiver = self.Receiver()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer value from sender to receiver
|
// Transfer value from sender to receiver
|
||||||
|
@ -192,7 +200,9 @@ func (self *StateTransition) TransitionState() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//snapshot := self.state.Copy()
|
if snapshot == nil {
|
||||||
|
snapshot = self.state.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
// Process the init code and create 'valid' contract
|
// Process the init code and create 'valid' contract
|
||||||
if IsContractAddr(self.receiver) {
|
if IsContractAddr(self.receiver) {
|
||||||
|
@ -203,8 +213,7 @@ func (self *StateTransition) TransitionState() (err error) {
|
||||||
|
|
||||||
code, err := self.Eval(receiver.Init(), receiver, "init")
|
code, err := self.Eval(receiver.Init(), receiver, "init")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//self.state.Set(snapshot)
|
self.state.Set(snapshot)
|
||||||
self.state.ResetStateObject(receiver)
|
|
||||||
|
|
||||||
return fmt.Errorf("Error during init execution %v", err)
|
return fmt.Errorf("Error during init execution %v", err)
|
||||||
}
|
}
|
||||||
|
@ -214,8 +223,7 @@ func (self *StateTransition) TransitionState() (err error) {
|
||||||
if len(receiver.Script()) > 0 {
|
if len(receiver.Script()) > 0 {
|
||||||
_, err = self.Eval(receiver.Script(), receiver, "code")
|
_, err = self.Eval(receiver.Script(), receiver, "code")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//self.state.Set(snapshot)
|
self.state.Set(snapshot)
|
||||||
self.state.ResetStateObject(receiver)
|
|
||||||
|
|
||||||
return fmt.Errorf("Error during code execution %v", err)
|
return fmt.Errorf("Error during code execution %v", err)
|
||||||
}
|
}
|
||||||
|
|
109
ethchain/vm.go
109
ethchain/vm.go
|
@ -22,12 +22,16 @@ var (
|
||||||
GasMemory = big.NewInt(1)
|
GasMemory = big.NewInt(1)
|
||||||
GasData = big.NewInt(5)
|
GasData = big.NewInt(5)
|
||||||
GasTx = big.NewInt(500)
|
GasTx = big.NewInt(500)
|
||||||
|
|
||||||
|
LogTyPretty byte = 0x1
|
||||||
|
LogTyDiff byte = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
type Debugger interface {
|
type Debugger interface {
|
||||||
BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
||||||
StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
|
||||||
BreakPoints() []int64
|
BreakPoints() []int64
|
||||||
|
SetCode(byteCode []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
|
@ -44,6 +48,7 @@ type Vm struct {
|
||||||
|
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
|
||||||
|
logTy byte
|
||||||
logStr string
|
logStr string
|
||||||
|
|
||||||
err error
|
err error
|
||||||
|
@ -69,7 +74,7 @@ type RuntimeVars struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
|
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
|
||||||
if self.Verbose {
|
if self.Verbose && self.logTy == LogTyPretty {
|
||||||
self.logStr += fmt.Sprintf(format, v...)
|
self.logStr += fmt.Sprintf(format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +82,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Endl() *Vm {
|
func (self *Vm) Endl() *Vm {
|
||||||
if self.Verbose {
|
if self.Verbose && self.logTy == LogTyPretty {
|
||||||
vmlogger.Debugln(self.logStr)
|
vmlogger.Debugln(self.logStr)
|
||||||
self.logStr = ""
|
self.logStr = ""
|
||||||
}
|
}
|
||||||
|
@ -86,7 +91,12 @@ func (self *Vm) Endl() *Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
|
func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
|
||||||
return &Vm{vars: vars, state: state, stateManager: stateManager}
|
lt := LogTyPretty
|
||||||
|
if ethutil.Config.Diff {
|
||||||
|
lt = LogTyDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Pow256 = ethutil.BigPow(2, 256)
|
var Pow256 = ethutil.BigPow(2, 256)
|
||||||
|
@ -103,7 +113,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args)
|
// Debug hook
|
||||||
|
if vm.Dbg != nil {
|
||||||
|
vm.Dbg.SetCode(closure.Script)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't bother with the execution if there's no code.
|
||||||
|
if len(closure.Script) == 0 {
|
||||||
|
return closure.Return(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
op OpCode
|
op OpCode
|
||||||
|
@ -132,6 +152,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
// Get the opcode (it must be an opcode!)
|
// Get the opcode (it must be an opcode!)
|
||||||
op = OpCode(val.Uint())
|
op = OpCode(val.Uint())
|
||||||
|
|
||||||
|
// XXX Leave this Println intact. Don't change this to the log system.
|
||||||
|
// Used for creating diffs between implementations
|
||||||
|
if vm.logTy == LogTyDiff {
|
||||||
|
b := pc.Bytes()
|
||||||
|
if len(b) == 0 {
|
||||||
|
b = []byte{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
gas := new(big.Int)
|
gas := new(big.Int)
|
||||||
addStepGasUsage := func(amount *big.Int) {
|
addStepGasUsage := func(amount *big.Int) {
|
||||||
if amount.Cmp(ethutil.Big0) >= 0 {
|
if amount.Cmp(ethutil.Big0) >= 0 {
|
||||||
|
@ -167,7 +198,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
require(2)
|
require(2)
|
||||||
newMemSize = stack.Peek().Uint64() + 32
|
newMemSize = stack.Peek().Uint64() + 32
|
||||||
case MLOAD:
|
case MLOAD:
|
||||||
|
require(1)
|
||||||
|
|
||||||
|
newMemSize = stack.Peek().Uint64() + 32
|
||||||
case MSTORE8:
|
case MSTORE8:
|
||||||
require(2)
|
require(2)
|
||||||
newMemSize = stack.Peek().Uint64() + 1
|
newMemSize = stack.Peek().Uint64() + 1
|
||||||
|
@ -415,7 +448,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
require(2)
|
require(2)
|
||||||
val, th := stack.Popn()
|
val, th := stack.Popn()
|
||||||
if th.Cmp(big.NewInt(32)) < 0 {
|
if th.Cmp(big.NewInt(32)) < 0 {
|
||||||
stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64()))
|
byt := big.NewInt(int64(val.Bytes()[th.Int64()]))
|
||||||
|
stack.Push(byt)
|
||||||
|
|
||||||
|
vm.Printf(" => 0x%x", byt.Bytes())
|
||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
}
|
}
|
||||||
|
@ -427,13 +463,26 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64()))
|
data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64()))
|
||||||
|
|
||||||
stack.Push(ethutil.BigD(data))
|
stack.Push(ethutil.BigD(data))
|
||||||
|
|
||||||
|
vm.Printf(" => %x", data)
|
||||||
// 0x30 range
|
// 0x30 range
|
||||||
case ADDRESS:
|
case ADDRESS:
|
||||||
stack.Push(ethutil.BigD(closure.Object().Address()))
|
stack.Push(ethutil.BigD(closure.Address()))
|
||||||
|
|
||||||
|
vm.Printf(" => %x", closure.Address())
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
stack.Push(closure.object.Amount)
|
require(1)
|
||||||
|
|
||||||
|
addr := stack.Pop().Bytes()
|
||||||
|
balance := vm.state.GetBalance(addr)
|
||||||
|
|
||||||
|
stack.Push(balance)
|
||||||
|
|
||||||
|
vm.Printf(" => %v (%x)", balance, addr)
|
||||||
case ORIGIN:
|
case ORIGIN:
|
||||||
stack.Push(ethutil.BigD(vm.vars.Origin))
|
stack.Push(ethutil.BigD(vm.vars.Origin))
|
||||||
|
|
||||||
|
vm.Printf(" => %v", vm.vars.Origin)
|
||||||
case CALLER:
|
case CALLER:
|
||||||
caller := closure.caller.Address()
|
caller := closure.caller.Address()
|
||||||
stack.Push(ethutil.BigD(caller))
|
stack.Push(ethutil.BigD(caller))
|
||||||
|
@ -441,6 +490,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
vm.Printf(" => %x", caller)
|
vm.Printf(" => %x", caller)
|
||||||
case CALLVALUE:
|
case CALLVALUE:
|
||||||
stack.Push(vm.vars.Value)
|
stack.Push(vm.vars.Value)
|
||||||
|
|
||||||
|
vm.Printf(" => %v", vm.vars.Value)
|
||||||
case CALLDATALOAD:
|
case CALLDATALOAD:
|
||||||
require(1)
|
require(1)
|
||||||
offset := stack.Pop().Int64()
|
offset := stack.Pop().Int64()
|
||||||
|
@ -499,8 +550,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
code := closure.Script[cOff : cOff+l]
|
code := closure.Script[cOff : cOff+l]
|
||||||
|
fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff)
|
||||||
|
|
||||||
mem.Set(mOff, l, code)
|
mem.Set(mOff, l, code)
|
||||||
|
fmt.Println(Code(mem.Get(mOff, l)))
|
||||||
case GASPRICE:
|
case GASPRICE:
|
||||||
stack.Push(closure.Price)
|
stack.Push(closure.Price)
|
||||||
|
|
||||||
|
@ -562,8 +615,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
case MSTORE8:
|
case MSTORE8:
|
||||||
require(2)
|
require(2)
|
||||||
val, mStart := stack.Popn()
|
val, mStart := stack.Popn()
|
||||||
base.And(val, new(big.Int).SetInt64(0xff))
|
//base.And(val, new(big.Int).SetInt64(0xff))
|
||||||
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
|
//mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
|
||||||
|
mem.store[mStart.Int64()] = byte(val.Int64() & 0xff)
|
||||||
|
|
||||||
vm.Printf(" => 0x%x", val)
|
vm.Printf(" => 0x%x", val)
|
||||||
case SLOAD:
|
case SLOAD:
|
||||||
|
@ -623,9 +677,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generate a new address
|
// Generate a new address
|
||||||
addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce)
|
addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64())
|
||||||
for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ {
|
for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ {
|
||||||
ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i)
|
ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i)
|
||||||
}
|
}
|
||||||
closure.object.Nonce++
|
closure.object.Nonce++
|
||||||
|
|
||||||
|
@ -638,14 +692,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
contract.AddAmount(value)
|
contract.AddAmount(value)
|
||||||
|
|
||||||
// Set the init script
|
// Set the init script
|
||||||
contract.initScript = mem.Get(offset.Int64(), size.Int64())
|
initCode := mem.Get(offset.Int64(), size.Int64())
|
||||||
|
//fmt.Printf("%x\n", initCode)
|
||||||
// Transfer all remaining gas to the new
|
// Transfer all remaining gas to the new
|
||||||
// contract so it may run the init script
|
// contract so it may run the init script
|
||||||
gas := new(big.Int).Set(closure.Gas)
|
gas := new(big.Int).Set(closure.Gas)
|
||||||
closure.UseGas(closure.Gas)
|
closure.UseGas(closure.Gas)
|
||||||
|
|
||||||
// Create the closure
|
// Create the closure
|
||||||
c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price)
|
c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price)
|
||||||
// Call the closure and set the return value as
|
// Call the closure and set the return value as
|
||||||
// main script.
|
// main script.
|
||||||
contract.script, err = Call(vm, c, nil)
|
contract.script, err = Call(vm, c, nil)
|
||||||
|
@ -665,6 +720,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
vm.Printf("CREATE success")
|
vm.Printf("CREATE success")
|
||||||
}
|
}
|
||||||
vm.Endl()
|
vm.Endl()
|
||||||
|
|
||||||
|
// Debug hook
|
||||||
|
if vm.Dbg != nil {
|
||||||
|
vm.Dbg.SetCode(closure.Script)
|
||||||
|
}
|
||||||
case CALL:
|
case CALL:
|
||||||
require(7)
|
require(7)
|
||||||
|
|
||||||
|
@ -683,10 +743,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
|
|
||||||
if closure.object.Amount.Cmp(value) < 0 {
|
if closure.object.Amount.Cmp(value) < 0 {
|
||||||
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
|
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
|
||||||
|
closure.ReturnGas(gas, nil, nil)
|
||||||
|
|
||||||
stack.Push(ethutil.BigFalse)
|
stack.Push(ethutil.BigFalse)
|
||||||
} else {
|
} else {
|
||||||
//snapshot := vm.state.Copy()
|
snapshot := vm.state.Copy()
|
||||||
|
|
||||||
stateObject := vm.state.GetOrNewStateObject(addr.Bytes())
|
stateObject := vm.state.GetOrNewStateObject(addr.Bytes())
|
||||||
|
|
||||||
|
@ -702,13 +763,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
|
|
||||||
vmlogger.Debugf("Closure execution failed. %v\n", err)
|
vmlogger.Debugf("Closure execution failed. %v\n", err)
|
||||||
|
|
||||||
//vm.state.Set(snapshot)
|
vm.state.Set(snapshot)
|
||||||
vm.state.ResetStateObject(stateObject)
|
|
||||||
} else {
|
} else {
|
||||||
stack.Push(ethutil.BigTrue)
|
stack.Push(ethutil.BigTrue)
|
||||||
|
|
||||||
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug hook
|
||||||
|
if vm.Dbg != nil {
|
||||||
|
vm.Dbg.SetCode(closure.Script)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case RETURN:
|
case RETURN:
|
||||||
require(2)
|
require(2)
|
||||||
|
@ -721,18 +786,12 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
case SUICIDE:
|
case SUICIDE:
|
||||||
require(1)
|
require(1)
|
||||||
|
|
||||||
receiver := vm.state.GetAccount(stack.Pop().Bytes())
|
receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes())
|
||||||
|
|
||||||
receiver.AddAmount(closure.object.Amount)
|
receiver.AddAmount(closure.object.Amount)
|
||||||
|
|
||||||
closure.object.MarkForDeletion()
|
closure.object.MarkForDeletion()
|
||||||
|
|
||||||
/*
|
|
||||||
trie := closure.object.state.trie
|
|
||||||
trie.NewIterator().Each(func(key string, v *ethutil.Value) {
|
|
||||||
trie.Delete(key)
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case STOP: // Stop the closure
|
case STOP: // Stop the closure
|
||||||
vm.Endl()
|
vm.Endl()
|
||||||
|
@ -752,6 +811,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
|
||||||
if vm.Dbg != nil {
|
if vm.Dbg != nil {
|
||||||
for _, instrNo := range vm.Dbg.BreakPoints() {
|
for _, instrNo := range vm.Dbg.BreakPoints() {
|
||||||
if pc.Cmp(big.NewInt(instrNo)) == 0 {
|
if pc.Cmp(big.NewInt(instrNo)) == 0 {
|
||||||
|
vm.Stepping = true
|
||||||
|
|
||||||
if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) {
|
if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package ethcrypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/go.crypto/ripemd160"
|
"code.google.com/p/go.crypto/ripemd160"
|
||||||
|
"code.google.com/p/go.crypto/sha3"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/obscuren/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Sha256Bin(data []byte) []byte {
|
func Sha256Bin(data []byte) []byte {
|
||||||
|
|
|
@ -3,7 +3,9 @@ package ethcrypto
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,6 +14,14 @@ import (
|
||||||
func InitWords() []string {
|
func InitWords() []string {
|
||||||
_, thisfile, _, _ := runtime.Caller(1)
|
_, thisfile, _, _ := runtime.Caller(1)
|
||||||
filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst")
|
filename := path.Join(path.Dir(thisfile), "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))
|
||||||
|
}
|
||||||
|
filename = path.Join(dir, "mnemonic.words.lst")
|
||||||
|
}
|
||||||
content, err := ioutil.ReadFile(filename)
|
content, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err))
|
panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err))
|
||||||
|
|
15
ethereum.go
15
ethereum.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/ethereum/eth-go/ethchain"
|
"github.com/ethereum/eth-go/ethchain"
|
||||||
"github.com/ethereum/eth-go/ethcrypto"
|
"github.com/ethereum/eth-go/ethcrypto"
|
||||||
"github.com/ethereum/eth-go/ethlog"
|
"github.com/ethereum/eth-go/ethlog"
|
||||||
"github.com/ethereum/eth-go/ethreact"
|
|
||||||
"github.com/ethereum/eth-go/ethrpc"
|
"github.com/ethereum/eth-go/ethrpc"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/ethereum/eth-go/ethwire"
|
"github.com/ethereum/eth-go/ethwire"
|
||||||
|
@ -21,6 +20,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const seedTextFileUri string = "http://www.ethereum.org/servers.poc3.txt"
|
||||||
|
|
||||||
var ethlogger = ethlog.NewLogger("SERV")
|
var ethlogger = ethlog.NewLogger("SERV")
|
||||||
|
|
||||||
func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) {
|
func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) {
|
||||||
|
@ -72,7 +73,7 @@ type Ethereum struct {
|
||||||
|
|
||||||
listening bool
|
listening bool
|
||||||
|
|
||||||
reactor *ethreact.ReactorEngine
|
reactor *ethutil.ReactorEngine
|
||||||
|
|
||||||
RpcServer *ethrpc.JsonRpcServer
|
RpcServer *ethrpc.JsonRpcServer
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
|
||||||
keyManager: keyManager,
|
keyManager: keyManager,
|
||||||
clientIdentity: clientIdentity,
|
clientIdentity: clientIdentity,
|
||||||
}
|
}
|
||||||
ethereum.reactor = ethreact.New()
|
ethereum.reactor = ethutil.NewReactorEngine()
|
||||||
|
|
||||||
ethereum.txPool = ethchain.NewTxPool(ethereum)
|
ethereum.txPool = ethchain.NewTxPool(ethereum)
|
||||||
ethereum.blockChain = ethchain.NewBlockChain(ethereum)
|
ethereum.blockChain = ethchain.NewBlockChain(ethereum)
|
||||||
|
@ -119,7 +120,7 @@ func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager
|
||||||
return ethereum, nil
|
return ethereum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ethereum) Reactor() *ethreact.ReactorEngine {
|
func (s *Ethereum) Reactor() *ethutil.ReactorEngine {
|
||||||
return s.reactor
|
return s.reactor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +352,6 @@ func (s *Ethereum) ReapDeadPeerHandler() {
|
||||||
|
|
||||||
// Start the ethereum
|
// Start the ethereum
|
||||||
func (s *Ethereum) Start(seed bool) {
|
func (s *Ethereum) Start(seed bool) {
|
||||||
s.reactor.Start()
|
|
||||||
// Bind to addr and port
|
// Bind to addr and port
|
||||||
ln, err := net.Listen("tcp", ":"+s.Port)
|
ln, err := net.Listen("tcp", ":"+s.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -418,7 +418,7 @@ func (s *Ethereum) Seed() {
|
||||||
s.ProcessPeerList(peers)
|
s.ProcessPeerList(peers)
|
||||||
} else {
|
} else {
|
||||||
// Fallback to servers.poc3.txt
|
// Fallback to servers.poc3.txt
|
||||||
resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
|
resp, err := http.Get(seedTextFileUri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ethlogger.Warnln("Fetching seed failed:", err)
|
ethlogger.Warnln("Fetching seed failed:", err)
|
||||||
return
|
return
|
||||||
|
@ -463,9 +463,6 @@ func (s *Ethereum) Stop() {
|
||||||
s.txPool.Stop()
|
s.txPool.Stop()
|
||||||
s.stateManager.Stop()
|
s.stateManager.Stop()
|
||||||
|
|
||||||
s.reactor.Flush()
|
|
||||||
s.reactor.Stop()
|
|
||||||
|
|
||||||
ethlogger.Infoln("Server stopped")
|
ethlogger.Infoln("Server stopped")
|
||||||
close(s.shutdownChan)
|
close(s.shutdownChan)
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,6 @@ func Reset() {
|
||||||
}
|
}
|
||||||
<-status
|
<-status
|
||||||
}
|
}
|
||||||
logSystems = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// waits until log messages are drained (dispatched to log writers)
|
// waits until log messages are drained (dispatched to log writers)
|
||||||
|
@ -116,6 +115,7 @@ func NewLogger(tag string) *Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddLogSystem(logSystem LogSystem) {
|
func AddLogSystem(logSystem LogSystem) {
|
||||||
|
var mutex = &sync.Mutex{}
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
if logSystems == nil {
|
if logSystems == nil {
|
||||||
|
@ -128,14 +128,16 @@ func AddLogSystem(logSystem LogSystem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) sendln(level LogLevel, v ...interface{}) {
|
func (logger *Logger) sendln(level LogLevel, v ...interface{}) {
|
||||||
if logSystems != nil {
|
if logMessages != nil {
|
||||||
send(newPrintlnLogMessage(level, logger.tag, v...))
|
msg := newPrintlnLogMessage(level, logger.tag, v...)
|
||||||
|
logMessages <- msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) sendf(level LogLevel, format string, v ...interface{}) {
|
func (logger *Logger) sendf(level LogLevel, format string, v ...interface{}) {
|
||||||
if logSystems != nil {
|
if logMessages != nil {
|
||||||
send(newPrintfLogMessage(level, logger.tag, format, v...))
|
msg := newPrintfLogMessage(level, logger.tag, format, v...)
|
||||||
|
logMessages <- msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,9 @@ func TestLoggerPrintln(t *testing.T) {
|
||||||
Flush()
|
Flush()
|
||||||
Reset()
|
Reset()
|
||||||
output := testLogSystem.Output
|
output := testLogSystem.Output
|
||||||
|
fmt.Println(quote(output))
|
||||||
if output != "[TEST] error\n[TEST] warn\n" {
|
if output != "[TEST] error\n[TEST] warn\n" {
|
||||||
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", testLogSystem.Output)
|
t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ func TestLoggerPrintf(t *testing.T) {
|
||||||
Reset()
|
Reset()
|
||||||
output := testLogSystem.Output
|
output := testLogSystem.Output
|
||||||
if output != "[TEST] error to { 2}\n[TEST] warn" {
|
if output != "[TEST] error to { 2}\n[TEST] warn" {
|
||||||
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", testLogSystem.Output)
|
t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,10 +89,10 @@ func TestMultipleLogSystems(t *testing.T) {
|
||||||
output0 := testLogSystem0.Output
|
output0 := testLogSystem0.Output
|
||||||
output1 := testLogSystem1.Output
|
output1 := testLogSystem1.Output
|
||||||
if output0 != "[TEST] error\n" {
|
if output0 != "[TEST] error\n" {
|
||||||
t.Error("Expected logger 0 output '[TEST] error\\n', got ", testLogSystem0.Output)
|
t.Error("Expected logger 0 output '[TEST] error\\n', got ", output0)
|
||||||
}
|
}
|
||||||
if output1 != "[TEST] error\n[TEST] warn\n" {
|
if output1 != "[TEST] error\n[TEST] warn\n" {
|
||||||
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", testLogSystem1.Output)
|
t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", output1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,6 @@ func TestFileLogSystem(t *testing.T) {
|
||||||
logger.Errorf("error to %s\n", filename)
|
logger.Errorf("error to %s\n", filename)
|
||||||
logger.Warnln("warn")
|
logger.Warnln("warn")
|
||||||
Flush()
|
Flush()
|
||||||
Reset()
|
|
||||||
contents, _ := ioutil.ReadFile(filename)
|
contents, _ := ioutil.ReadFile(filename)
|
||||||
output := string(contents)
|
output := string(contents)
|
||||||
if output != "[TEST] error to test.log\n[TEST] warn\n" {
|
if output != "[TEST] error to test.log\n[TEST] warn\n" {
|
||||||
|
@ -117,7 +117,5 @@ func TestFileLogSystem(t *testing.T) {
|
||||||
func TestNoLogSystem(t *testing.T) {
|
func TestNoLogSystem(t *testing.T) {
|
||||||
logger := NewLogger("TEST")
|
logger := NewLogger("TEST")
|
||||||
logger.Warnln("warn")
|
logger.Warnln("warn")
|
||||||
fmt.Println("1")
|
|
||||||
Flush()
|
Flush()
|
||||||
Reset()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/ethereum/eth-go/ethchain"
|
"github.com/ethereum/eth-go/ethchain"
|
||||||
"github.com/ethereum/eth-go/ethlog"
|
"github.com/ethereum/eth-go/ethlog"
|
||||||
"github.com/ethereum/eth-go/ethreact"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
"github.com/ethereum/eth-go/ethwire"
|
"github.com/ethereum/eth-go/ethwire"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
@ -15,19 +15,19 @@ type Miner struct {
|
||||||
pow ethchain.PoW
|
pow ethchain.PoW
|
||||||
ethereum ethchain.EthManager
|
ethereum ethchain.EthManager
|
||||||
coinbase []byte
|
coinbase []byte
|
||||||
reactChan chan ethreact.Event
|
reactChan chan ethutil.React
|
||||||
txs ethchain.Transactions
|
txs ethchain.Transactions
|
||||||
uncles []*ethchain.Block
|
uncles []*ethchain.Block
|
||||||
block *ethchain.Block
|
block *ethchain.Block
|
||||||
powChan chan []byte
|
powChan chan []byte
|
||||||
powQuitChan chan ethreact.Event
|
powQuitChan chan ethutil.React
|
||||||
quitChan chan bool
|
quitChan chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
|
func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
|
||||||
reactChan := make(chan ethreact.Event, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
|
reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
|
||||||
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
|
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
|
||||||
powQuitChan := make(chan ethreact.Event, 1) // This is the channel that can exit the miner thread
|
powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
|
||||||
quitChan := make(chan bool, 1)
|
quitChan := make(chan bool, 1)
|
||||||
|
|
||||||
ethereum.Reactor().Subscribe("newBlock", reactChan)
|
ethereum.Reactor().Subscribe("newBlock", reactChan)
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
# ethreact
|
|
||||||
|
|
||||||
ethereum event reactor. Component of the ethereum stack.
|
|
||||||
various events like state change on an account or new block found are broadcast to subscribers.
|
|
||||||
Broadcasting to subscribers is running on its own routine and globally order preserving.
|
|
||||||
|
|
||||||
## Clients
|
|
||||||
### subscribe
|
|
||||||
|
|
||||||
eventChannel := make(chan ethreact.Event)
|
|
||||||
reactor.Subscribe(event, eventChannel)
|
|
||||||
|
|
||||||
The same channel can be subscribed to multiple events but only once for each event. In order to allow order of events to be preserved, broadcast of events is synchronous within the main broadcast loop. Therefore any blocking subscriber channels will be skipped, i.e. missing broadcasting events while they are blocked.
|
|
||||||
|
|
||||||
### unsubscribe
|
|
||||||
|
|
||||||
reactor.Unsubscribe(event, eventChannel)
|
|
||||||
|
|
||||||
### Processing events
|
|
||||||
|
|
||||||
event.Resource is of type interface{}. The actual type of event.Resource depends on event.Name and may need to be cast for processing.
|
|
||||||
|
|
||||||
var event ethreact.Event
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event = <-eventChannel:
|
|
||||||
processTransaction(event.Resource.(Transaction))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
## Broadcast
|
|
||||||
|
|
||||||
reactor := ethreact.New()
|
|
||||||
reactor.Start()
|
|
||||||
reactor.Post(name, resource)
|
|
||||||
reactor.Flush() // wait till all broadcast messages are dispatched
|
|
||||||
reactor.Stop() // stop the main broadcast loop immediately (even if there are unbroadcast events left)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package ethreact
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReactorAdd(t *testing.T) {
|
|
||||||
reactor := New()
|
|
||||||
ch := make(chan Event)
|
|
||||||
reactor.Subscribe("test", ch)
|
|
||||||
if reactor.eventHandlers["test"] == nil {
|
|
||||||
t.Error("Expected new eventHandler to be created")
|
|
||||||
}
|
|
||||||
reactor.Unsubscribe("test", ch)
|
|
||||||
if reactor.eventHandlers["test"] != nil {
|
|
||||||
t.Error("Expected eventHandler to be removed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReactorEvent(t *testing.T) {
|
|
||||||
var name string
|
|
||||||
reactor := New()
|
|
||||||
// Buffer the channel, so it doesn't block for this test
|
|
||||||
cap := 20
|
|
||||||
ch := make(chan Event, cap)
|
|
||||||
reactor.Subscribe("even", ch)
|
|
||||||
reactor.Subscribe("odd", ch)
|
|
||||||
reactor.Post("even", "disappears") // should not broadcast if engine not started
|
|
||||||
reactor.Start()
|
|
||||||
for i := 0; i < cap; i++ {
|
|
||||||
if i%2 == 0 {
|
|
||||||
name = "even"
|
|
||||||
} else {
|
|
||||||
name = "odd"
|
|
||||||
}
|
|
||||||
reactor.Post(name, i)
|
|
||||||
}
|
|
||||||
reactor.Post("test", cap) // this should not block
|
|
||||||
i := 0
|
|
||||||
reactor.Flush()
|
|
||||||
close(ch)
|
|
||||||
for event := range ch {
|
|
||||||
fmt.Printf("%d: %v", i, event)
|
|
||||||
if i%2 == 0 {
|
|
||||||
name = "even"
|
|
||||||
} else {
|
|
||||||
name = "odd"
|
|
||||||
}
|
|
||||||
if val, ok := event.Resource.(int); ok {
|
|
||||||
if i != val || event.Name != name {
|
|
||||||
t.Error("Expected event %d to be of type %s and resource %d, got ", i, name, i, val)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Error("Unable to cast")
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i != cap {
|
|
||||||
t.Error("excpected exactly %d events, got ", i)
|
|
||||||
}
|
|
||||||
reactor.Stop()
|
|
||||||
}
|
|
|
@ -3,8 +3,20 @@ package ethutil
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsWindows() bool {
|
||||||
|
return runtime.GOOS == "windows"
|
||||||
|
}
|
||||||
|
|
||||||
|
func WindonizePath(path string) string {
|
||||||
|
if string(path[0]) == "/" && IsWindows() {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
// The different number of units
|
// The different number of units
|
||||||
var (
|
var (
|
||||||
Douglas = BigPow(10, 42)
|
Douglas = BigPow(10, 42)
|
||||||
|
|
|
@ -13,6 +13,7 @@ type ConfigManager struct {
|
||||||
|
|
||||||
ExecPath string
|
ExecPath string
|
||||||
Debug bool
|
Debug bool
|
||||||
|
Diff bool
|
||||||
Paranoia bool
|
Paranoia bool
|
||||||
|
|
||||||
conf *globalconf.GlobalConf
|
conf *globalconf.GlobalConf
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package ethutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReactorEvent struct {
|
||||||
|
mut sync.Mutex
|
||||||
|
event string
|
||||||
|
chans []chan React
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post the specified reactor resource on the channels
|
||||||
|
// currently subscribed
|
||||||
|
func (e *ReactorEvent) Post(react React) {
|
||||||
|
e.mut.Lock()
|
||||||
|
defer e.mut.Unlock()
|
||||||
|
|
||||||
|
for _, ch := range e.chans {
|
||||||
|
go func(ch chan React) {
|
||||||
|
ch <- react
|
||||||
|
}(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a subscriber to this event
|
||||||
|
func (e *ReactorEvent) Add(ch chan React) {
|
||||||
|
e.mut.Lock()
|
||||||
|
defer e.mut.Unlock()
|
||||||
|
|
||||||
|
e.chans = append(e.chans, ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a subscriber
|
||||||
|
func (e *ReactorEvent) Remove(ch chan React) {
|
||||||
|
e.mut.Lock()
|
||||||
|
defer e.mut.Unlock()
|
||||||
|
|
||||||
|
for i, c := range e.chans {
|
||||||
|
if c == ch {
|
||||||
|
e.chans = append(e.chans[:i], e.chans[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic reactor resource
|
||||||
|
type React struct {
|
||||||
|
Resource interface{}
|
||||||
|
Event string
|
||||||
|
}
|
||||||
|
|
||||||
|
// The reactor basic engine. Acts as bridge
|
||||||
|
// between the events and the subscribers/posters
|
||||||
|
type ReactorEngine struct {
|
||||||
|
patterns map[string]*ReactorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReactorEngine() *ReactorEngine {
|
||||||
|
return &ReactorEngine{patterns: make(map[string]*ReactorEvent)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe a channel to the specified event
|
||||||
|
func (reactor *ReactorEngine) Subscribe(event string, ch chan React) {
|
||||||
|
ev := reactor.patterns[event]
|
||||||
|
// Create a new event if one isn't available
|
||||||
|
if ev == nil {
|
||||||
|
ev = &ReactorEvent{event: event}
|
||||||
|
reactor.patterns[event] = ev
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the channel to reactor event handler
|
||||||
|
ev.Add(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) {
|
||||||
|
ev := reactor.patterns[event]
|
||||||
|
if ev != nil {
|
||||||
|
ev.Remove(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reactor *ReactorEngine) Post(event string, resource interface{}) {
|
||||||
|
ev := reactor.patterns[event]
|
||||||
|
if ev != nil {
|
||||||
|
ev.Post(React{Resource: resource, Event: event})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ethutil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestReactorAdd(t *testing.T) {
|
||||||
|
engine := NewReactorEngine()
|
||||||
|
ch := make(chan React)
|
||||||
|
engine.Subscribe("test", ch)
|
||||||
|
if len(engine.patterns) != 1 {
|
||||||
|
t.Error("Expected patterns to be 1, got", len(engine.patterns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReactorEvent(t *testing.T) {
|
||||||
|
engine := NewReactorEngine()
|
||||||
|
|
||||||
|
// Buffer 1, so it doesn't block for this test
|
||||||
|
ch := make(chan React, 1)
|
||||||
|
engine.Subscribe("test", ch)
|
||||||
|
engine.Post("test", "hello")
|
||||||
|
|
||||||
|
value := <-ch
|
||||||
|
if val, ok := value.Resource.(string); ok {
|
||||||
|
if val != "hello" {
|
||||||
|
t.Error("Expected Resource to be 'hello', got", val)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Error("Unable to cast")
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/obscuren/mutan"
|
"github.com/obscuren/mutan"
|
||||||
"github.com/obscuren/mutan/backends"
|
"github.com/obscuren/mutan/backends"
|
||||||
"github.com/obscuren/serpent-go"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,13 +14,15 @@ func Compile(script string, silent bool) (ret []byte, err error) {
|
||||||
|
|
||||||
if len(line) > 1 && line[0:2] == "#!" {
|
if len(line) > 1 && line[0:2] == "#!" {
|
||||||
switch line {
|
switch line {
|
||||||
case "#!serpent":
|
/*
|
||||||
byteCode, err := serpent.Compile(script)
|
case "#!serpent":
|
||||||
if err != nil {
|
byteCode, err := serpent.Compile(script)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return byteCode, nil
|
return byteCode, nil
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) {
|
||||||
var totalBytes int
|
var totalBytes int
|
||||||
for {
|
for {
|
||||||
// Give buffering some time
|
// Give buffering some time
|
||||||
conn.SetReadDeadline(time.Now().Add(50 * time.Millisecond))
|
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
||||||
// Create a new temporarily buffer
|
// Create a new temporarily buffer
|
||||||
b := make([]byte, 1440)
|
b := make([]byte, 1440)
|
||||||
// Wait for a message from this peer
|
// Wait for a message from this peer
|
||||||
|
|
18
peer.go
18
peer.go
|
@ -21,7 +21,7 @@ const (
|
||||||
// The size of the output buffer for writing messages
|
// The size of the output buffer for writing messages
|
||||||
outputBufferSize = 50
|
outputBufferSize = 50
|
||||||
// Current protocol version
|
// Current protocol version
|
||||||
ProtocolVersion = 21
|
ProtocolVersion = 23
|
||||||
// Interval for ping/pong message
|
// Interval for ping/pong message
|
||||||
pingPongTimer = 2 * time.Second
|
pingPongTimer = 2 * time.Second
|
||||||
)
|
)
|
||||||
|
@ -252,7 +252,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
peerlogger.DebugDetailln("<=", msg.Type, msg.Data)
|
peerlogger.DebugDetailf("(%v) <= %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
|
||||||
|
|
||||||
err := ethwire.WriteMessage(p.conn, msg)
|
err := ethwire.WriteMessage(p.conn, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -326,7 +326,7 @@ func (p *Peer) HandleInbound() {
|
||||||
peerlogger.Debugln(err)
|
peerlogger.Debugln(err)
|
||||||
}
|
}
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
peerlogger.DebugDetailln("=>", msg.Type, msg.Data)
|
peerlogger.DebugDetailf("(%v) => %v %v\n", p.conn.RemoteAddr(), msg.Type, msg.Data)
|
||||||
|
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case ethwire.MsgHandshakeTy:
|
case ethwire.MsgHandshakeTy:
|
||||||
|
@ -419,6 +419,16 @@ func (p *Peer) HandleInbound() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the parent is unknown try to catch up with this peer
|
// If the parent is unknown try to catch up with this peer
|
||||||
if ethchain.IsParentErr(err) {
|
if ethchain.IsParentErr(err) {
|
||||||
|
/*
|
||||||
|
b := ethchain.NewBlockFromRlpValue(msg.Data.Get(0))
|
||||||
|
|
||||||
|
peerlogger.Infof("Attempting to catch (%x). Parent known\n", b.Hash())
|
||||||
|
p.catchingUp = false
|
||||||
|
|
||||||
|
p.CatchupWithPeer(b.Hash())
|
||||||
|
|
||||||
|
peerlogger.Infoln(b)
|
||||||
|
*/
|
||||||
peerlogger.Infoln("Attempting to catch. Parent known")
|
peerlogger.Infoln("Attempting to catch. Parent known")
|
||||||
p.catchingUp = false
|
p.catchingUp = false
|
||||||
p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
|
p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
|
||||||
|
@ -744,7 +754,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) {
|
||||||
if !p.catchingUp {
|
if !p.catchingUp {
|
||||||
// Make sure nobody else is catching up when you want to do this
|
// Make sure nobody else is catching up when you want to do this
|
||||||
p.catchingUp = true
|
p.catchingUp = true
|
||||||
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)})
|
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(10)})
|
||||||
p.QueueMessage(msg)
|
p.QueueMessage(msg)
|
||||||
|
|
||||||
peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())
|
peerlogger.DebugDetailf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())
|
||||||
|
|
Loading…
Reference in New Issue