From 2b32f47d2c17aaee655d56fd91c95798652b1116 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Jan 2014 20:14:01 +0100 Subject: [PATCH 0001/1237] Initial commit bootstrapping package --- .gitignore | 12 +++ ethereum.go | 213 ++++++++++++++++++++++++++++++++++++ peer.go | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 528 insertions(+) create mode 100644 .gitignore create mode 100644 ethereum.go create mode 100644 peer.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..f725d58d14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethereum.go b/ethereum.go new file mode 100644 index 0000000000..b1b675c88a --- /dev/null +++ b/ethereum.go @@ -0,0 +1,213 @@ +package eth + +import ( + "container/list" + "github.com/ethereum/ethchain-go" + "github.com/ethereum/ethdb-go" + "github.com/ethereum/ethutil-go" + "github.com/ethereum/ethwire-go" + "log" + "net" + "sync/atomic" + "time" +) + +func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) { + // Loop thru the peers and close them (if we had them) + for e := peers.Front(); e != nil; e = e.Next() { + if peer, ok := e.Value.(*Peer); ok { + callback(peer, e) + } + } +} + +const ( + processReapingTimeout = 60 // TODO increase +) + +type Ethereum struct { + // Channel for shutting down the ethereum + shutdownChan chan bool + // DB interface + //db *ethdb.LDBDatabase + db *ethdb.MemDatabase + // Block manager for processing new blocks and managing the block chain + BlockManager *ethchain.BlockManager + // The transaction pool. Transaction can be pushed on this pool + // for later including in the blocks + TxPool *ethchain.TxPool + // Peers (NYI) + peers *list.List + // Nonce + Nonce uint64 +} + +func New() (*Ethereum, error) { + //db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewMemDatabase() + if err != nil { + return nil, err + } + + ethutil.Config.Db = db + + nonce, _ := ethutil.RandomUint64() + ethereum := &Ethereum{ + shutdownChan: make(chan bool), + db: db, + peers: list.New(), + Nonce: nonce, + } + ethereum.TxPool = ethchain.NewTxPool() + ethereum.TxPool.Speaker = ethereum + ethereum.BlockManager = ethchain.NewBlockManager() + + ethereum.TxPool.BlockManager = ethereum.BlockManager + ethereum.BlockManager.TransactionPool = ethereum.TxPool + + return ethereum, nil +} + +func (s *Ethereum) AddPeer(conn net.Conn) { + peer := NewPeer(conn, s, true) + + if peer != nil { + s.peers.PushBack(peer) + peer.Start() + + log.Println("Peer connected ::", conn.RemoteAddr()) + } +} + +func (s *Ethereum) ProcessPeerList(addrs []string) { + for _, addr := range addrs { + // TODO Probably requires some sanity checks + s.ConnectToPeer(addr) + } +} + +func (s *Ethereum) ConnectToPeer(addr string) error { + peer := NewOutboundPeer(addr, s) + + s.peers.PushBack(peer) + + return nil +} + +func (s *Ethereum) OutboundPeers() []*Peer { + // Create a new peer slice with at least the length of the total peers + outboundPeers := make([]*Peer, s.peers.Len()) + length := 0 + eachPeer(s.peers, func(p *Peer, e *list.Element) { + if !p.inbound { + outboundPeers[length] = p + length++ + } + }) + + return outboundPeers[:length] +} + +func (s *Ethereum) InboundPeers() []*Peer { + // Create a new peer slice with at least the length of the total peers + inboundPeers := make([]*Peer, s.peers.Len()) + length := 0 + eachPeer(s.peers, func(p *Peer, e *list.Element) { + if p.inbound { + inboundPeers[length] = p + length++ + } + }) + + return inboundPeers[:length] +} + +func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data []byte) { + eachPeer(s.peers, func(p *Peer, e *list.Element) { + p.QueueMessage(ethwire.NewMessage(msgType, data)) + }) +} + +func (s *Ethereum) ReapDeadPeers() { + for { + eachPeer(s.peers, func(p *Peer, e *list.Element) { + if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { + log.Println("Dead peer found .. reaping") + + s.peers.Remove(e) + } + }) + + time.Sleep(processReapingTimeout * time.Second) + } +} + +// Start the ethereum +func (s *Ethereum) Start() { + // For now this function just blocks the main thread + ln, err := net.Listen("tcp", ":12345") + if err != nil { + // This is mainly for testing to create a "network" + if ethutil.Config.Debug { + log.Println("Connection listening disabled. Acting as client") + + err = s.ConnectToPeer("localhost:12345") + if err != nil { + log.Println("Error starting ethereum", err) + + s.Stop() + } + } else { + log.Fatal(err) + } + } else { + // Starting accepting connections + go func() { + for { + conn, err := ln.Accept() + if err != nil { + log.Println(err) + + continue + } + + go s.AddPeer(conn) + } + }() + } + + // Start the reaping processes + go s.ReapDeadPeers() + + // Start the tx pool + s.TxPool.Start() + + // TMP + /* + go func() { + for { + s.Broadcast("block", s.blockManager.bc.GenesisBlock().RlpEncode()) + + time.Sleep(1000 * time.Millisecond) + } + }() + */ +} + +func (s *Ethereum) Stop() { + // Close the database + defer s.db.Close() + + eachPeer(s.peers, func(p *Peer, e *list.Element) { + p.Stop() + }) + + s.shutdownChan <- true + + s.TxPool.Stop() +} + +// This function will wait for a shutdown and resumes main thread execution +func (s *Ethereum) WaitForShutdown() { + <-s.shutdownChan +} diff --git a/peer.go b/peer.go new file mode 100644 index 0000000000..ef9a05ed1b --- /dev/null +++ b/peer.go @@ -0,0 +1,303 @@ +package eth + +import ( + "github.com/ethereum/ethutil-go" + "github.com/ethereum/ethwire-go" + "log" + "net" + "strconv" + "sync/atomic" + "time" +) + +const ( + // The size of the output buffer for writing messages + outputBufferSize = 50 +) + +type Peer struct { + // Ethereum interface + ethereum *Ethereum + // Net connection + conn net.Conn + // Output queue which is used to communicate and handle messages + outputQueue chan *ethwire.Msg + // Quit channel + quit chan bool + // Determines whether it's an inbound or outbound peer + inbound bool + // Flag for checking the peer's connectivity state + connected int32 + disconnect int32 + // Last known message send + lastSend time.Time + // Indicated whether a verack has been send or not + // This flag is used by writeMessage to check if messages are allowed + // to be send or not. If no version is known all messages are ignored. + versionKnown bool + + // Last received pong message + lastPong int64 + // Indicates whether a MsgGetPeersTy was requested of the peer + // this to prevent receiving false peers. + requestedPeerList bool +} + +func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { + return &Peer{ + outputQueue: make(chan *ethwire.Msg, outputBufferSize), + quit: make(chan bool), + ethereum: ethereum, + conn: conn, + inbound: inbound, + disconnect: 0, + connected: 1, + } +} + +func NewOutboundPeer(addr string, ethereum *Ethereum) *Peer { + p := &Peer{ + outputQueue: make(chan *ethwire.Msg, outputBufferSize), + quit: make(chan bool), + ethereum: ethereum, + inbound: false, + connected: 0, + disconnect: 0, + } + + // Set up the connection in another goroutine so we don't block the main thread + go func() { + conn, err := net.Dial("tcp", addr) + if err != nil { + p.Stop() + } + p.conn = conn + + // Atomically set the connection state + atomic.StoreInt32(&p.connected, 1) + atomic.StoreInt32(&p.disconnect, 0) + + log.Println("Connected to peer ::", conn.RemoteAddr()) + + p.Start() + }() + + return p +} + +// Outputs any RLP encoded data to the peer +func (p *Peer) QueueMessage(msg *ethwire.Msg) { + p.outputQueue <- msg +} + +func (p *Peer) writeMessage(msg *ethwire.Msg) { + // Ignore the write if we're not connected + if atomic.LoadInt32(&p.connected) != 1 { + return + } + + if !p.versionKnown { + switch msg.Type { + case ethwire.MsgHandshakeTy: // Ok + default: // Anything but ack is allowed + return + } + } + + err := ethwire.WriteMessage(p.conn, msg) + if err != nil { + log.Println("Can't send message:", err) + // Stop the client if there was an error writing to it + p.Stop() + return + } +} + +// Outbound message handler. Outbound messages are handled here +func (p *Peer) HandleOutbound() { + // The ping timer. Makes sure that every 2 minutes a ping is send to the peer + tickleTimer := time.NewTicker(2 * time.Minute) +out: + for { + select { + // Main message queue. All outbound messages are processed through here + case msg := <-p.outputQueue: + p.writeMessage(msg) + + p.lastSend = time.Now() + + case <-tickleTimer.C: + p.writeMessage(ðwire.Msg{Type: ethwire.MsgPingTy}) + + // Break out of the for loop if a quit message is posted + case <-p.quit: + break out + } + } + +clean: + // This loop is for draining the output queue and anybody waiting for us + for { + select { + case <-p.outputQueue: + // TODO + default: + break clean + } + } +} + +// Inbound handler. Inbound messages are received here and passed to the appropriate methods +func (p *Peer) HandleInbound() { + +out: + for atomic.LoadInt32(&p.disconnect) == 0 { + // Wait for a message from the peer + msg, err := ethwire.ReadMessage(p.conn) + if err != nil { + log.Println(err) + + break out + } + + if ethutil.Config.Debug { + log.Printf("Received %s\n", msg.Type.String()) + } + + switch msg.Type { + case ethwire.MsgHandshakeTy: + // Version message + p.handleHandshake(msg) + case ethwire.MsgBlockTy: + err := p.ethereum.BlockManager.ProcessBlock(ethutil.NewBlock(msg.Data)) + if err != nil { + log.Println(err) + } + case ethwire.MsgTxTy: + p.ethereum.TxPool.QueueTransaction(ethutil.NewTransactionFromData(msg.Data)) + case ethwire.MsgInvTy: + case ethwire.MsgGetPeersTy: + p.requestedPeerList = true + // Peer asked for list of connected peers + p.pushPeers() + case ethwire.MsgPeersTy: + // Received a list of peers (probably because MsgGetPeersTy was send) + // Only act on message if we actually requested for a peers list + if p.requestedPeerList { + data := ethutil.Conv(msg.Data) + // Create new list of possible peers for the ethereum to process + peers := make([]string, data.Length()) + // Parse each possible peer + for i := 0; i < data.Length(); i++ { + peers[i] = data.Get(i).AsString() + strconv.Itoa(int(data.Get(i).AsUint())) + } + + // Connect to the list of peers + p.ethereum.ProcessPeerList(peers) + // Mark unrequested again + p.requestedPeerList = false + } + case ethwire.MsgPingTy: + // Respond back with pong + p.QueueMessage(ðwire.Msg{Type: ethwire.MsgPongTy}) + case ethwire.MsgPongTy: + p.lastPong = time.Now().Unix() + } + } + + p.Stop() +} + +func (p *Peer) Start() { + if !p.inbound { + err := p.pushHandshake() + if err != nil { + log.Printf("Peer can't send outbound version ack", err) + + p.Stop() + } + } + + // Run the outbound handler in a new goroutine + go p.HandleOutbound() + // Run the inbound handler in a new goroutine + go p.HandleInbound() +} + +func (p *Peer) Stop() { + if atomic.AddInt32(&p.disconnect, 1) != 1 { + return + } + + close(p.quit) + if atomic.LoadInt32(&p.connected) != 0 { + p.conn.Close() + } + + log.Println("Peer shutdown") +} + +func (p *Peer) pushHandshake() error { + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, ethutil.Encode([]interface{}{ + 1, 0, p.ethereum.Nonce, + })) + + p.QueueMessage(msg) + + return nil +} + +// Pushes the list of outbound peers to the client when requested +func (p *Peer) pushPeers() { + outPeers := make([]interface{}, len(p.ethereum.OutboundPeers())) + // Serialise each peer + for i, peer := range p.ethereum.OutboundPeers() { + outPeers[i] = peer.RlpEncode() + } + + // Send message to the peer with the known list of connected clients + msg := ethwire.NewMessage(ethwire.MsgPeersTy, ethutil.Encode(outPeers)) + + p.QueueMessage(msg) +} + +func (p *Peer) handleHandshake(msg *ethwire.Msg) { + c := ethutil.Conv(msg.Data) + // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID] + if c.Get(2).AsUint() == p.ethereum.Nonce { + //if msg.Nonce == p.ethereum.Nonce { + log.Println("Peer connected to self, disconnecting") + + p.Stop() + + return + } + + p.versionKnown = true + + // If this is an inbound connection send an ack back + if p.inbound { + err := p.pushHandshake() + if err != nil { + log.Println("Peer can't send ack back") + + p.Stop() + } + } +} + +func (p *Peer) RlpEncode() []byte { + host, prt, err := net.SplitHostPort(p.conn.RemoteAddr().String()) + if err != nil { + return nil + } + + i, err := strconv.Atoi(prt) + if err != nil { + return nil + } + + port := ethutil.NumberToBytes(uint16(i), 16) + + return ethutil.Encode([]interface{}{host, port}) +} From 878e796c0adaa608a3e5feacf89a6766b347c9c8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Jan 2014 20:55:23 +0100 Subject: [PATCH 0002/1237] Updated packages --- peer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index ef9a05ed1b..d294816540 100644 --- a/peer.go +++ b/peer.go @@ -1,6 +1,7 @@ package eth import ( + "github.com/ethereum/ethchain-go" "github.com/ethereum/ethutil-go" "github.com/ethereum/ethwire-go" "log" @@ -169,7 +170,7 @@ out: // Version message p.handleHandshake(msg) case ethwire.MsgBlockTy: - err := p.ethereum.BlockManager.ProcessBlock(ethutil.NewBlock(msg.Data)) + err := p.ethereum.BlockManager.ProcessBlock(ethchain.NewBlock(msg.Data)) if err != nil { log.Println(err) } From 233f5200ef77ee77b4d33b5ff277d0e524b1fb4d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Jan 2014 22:32:50 +0100 Subject: [PATCH 0003/1237] Data send over the wire shouldn't be RLPed more then once --- ethereum.go | 5 +++-- peer.go | 15 +++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ethereum.go b/ethereum.go index b1b675c88a..db66c3ce79 100644 --- a/ethereum.go +++ b/ethereum.go @@ -122,9 +122,10 @@ func (s *Ethereum) InboundPeers() []*Peer { return inboundPeers[:length] } -func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data []byte) { +func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data interface{}) { + msg := ethwire.NewMessage(msgType, data) eachPeer(s.peers, func(p *Peer, e *list.Element) { - p.QueueMessage(ethwire.NewMessage(msgType, data)) + p.QueueMessage(msg) }) } diff --git a/peer.go b/peer.go index d294816540..4f799e8900 100644 --- a/peer.go +++ b/peer.go @@ -170,12 +170,15 @@ out: // Version message p.handleHandshake(msg) case ethwire.MsgBlockTy: - err := p.ethereum.BlockManager.ProcessBlock(ethchain.NewBlock(msg.Data)) - if err != nil { - log.Println(err) - } + /* + err := p.ethereum.BlockManager.ProcessBlock(ethchain.NewBlock(msg.Data)) + if err != nil { + log.Println(err) + } + */ case ethwire.MsgTxTy: - p.ethereum.TxPool.QueueTransaction(ethutil.NewTransactionFromData(msg.Data)) + //p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data)) + p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(0))) case ethwire.MsgInvTy: case ethwire.MsgGetPeersTy: p.requestedPeerList = true @@ -263,7 +266,7 @@ func (p *Peer) pushPeers() { } func (p *Peer) handleHandshake(msg *ethwire.Msg) { - c := ethutil.Conv(msg.Data) + c := msg.Data // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID] if c.Get(2).AsUint() == p.ethereum.Nonce { //if msg.Nonce == p.ethereum.Nonce { From 1b7cba18781ddd6ff262801057930367ea397c9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 24 Jan 2014 17:48:21 +0100 Subject: [PATCH 0004/1237] Updated peers --- ethereum.go | 2 +- peer.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ethereum.go b/ethereum.go index db66c3ce79..74e47d7bfd 100644 --- a/ethereum.go +++ b/ethereum.go @@ -60,7 +60,7 @@ func New() (*Ethereum, error) { } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum - ethereum.BlockManager = ethchain.NewBlockManager() + ethereum.BlockManager = ethchain.NewBlockManager(ethereum) ethereum.TxPool.BlockManager = ethereum.BlockManager ethereum.BlockManager.TransactionPool = ethereum.TxPool diff --git a/peer.go b/peer.go index 4f799e8900..afbe728fee 100644 --- a/peer.go +++ b/peer.go @@ -128,7 +128,7 @@ out: p.lastSend = time.Now() case <-tickleTimer.C: - p.writeMessage(ðwire.Msg{Type: ethwire.MsgPingTy}) + p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) // Break out of the for loop if a quit message is posted case <-p.quit: @@ -170,12 +170,12 @@ out: // Version message p.handleHandshake(msg) case ethwire.MsgBlockTy: - /* - err := p.ethereum.BlockManager.ProcessBlock(ethchain.NewBlock(msg.Data)) - if err != nil { - log.Println(err) - } - */ + block := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)) + block.MakeContracts() + err := p.ethereum.BlockManager.ProcessBlock(block) + if err != nil { + log.Println(err) + } case ethwire.MsgTxTy: //p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data)) p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(0))) @@ -203,7 +203,7 @@ out: } case ethwire.MsgPingTy: // Respond back with pong - p.QueueMessage(ðwire.Msg{Type: ethwire.MsgPongTy}) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) case ethwire.MsgPongTy: p.lastPong = time.Now().Unix() } From 7931c6624cca041b373e97e17e43318633633250 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 25 Jan 2014 17:13:33 +0100 Subject: [PATCH 0005/1237] Graceful shutdown of peers --- peer.go | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/peer.go b/peer.go index afbe728fee..f370580cfd 100644 --- a/peer.go +++ b/peer.go @@ -169,17 +169,26 @@ out: case ethwire.MsgHandshakeTy: // Version message p.handleHandshake(msg) + case ethwire.MsgDiscTy: + p.Stop() + case ethwire.MsgPingTy: + // Respond back with pong + p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) + case ethwire.MsgPongTy: + p.lastPong = time.Now().Unix() case ethwire.MsgBlockTy: - block := ethchain.NewBlockFromRlpValue(msg.Data.Get(0)) - block.MakeContracts() - err := p.ethereum.BlockManager.ProcessBlock(block) - if err != nil { - log.Println(err) + for i := 0; i < msg.Data.Length(); i++ { + block := ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) + err := p.ethereum.BlockManager.ProcessBlock(block) + + if err != nil { + log.Println(err) + } } case ethwire.MsgTxTy: - //p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data)) - p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(0))) - case ethwire.MsgInvTy: + for i := 0; i < msg.Data.Length(); i++ { + p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(i))) + } case ethwire.MsgGetPeersTy: p.requestedPeerList = true // Peer asked for list of connected peers @@ -201,11 +210,8 @@ out: // Mark unrequested again p.requestedPeerList = false } - case ethwire.MsgPingTy: - // Respond back with pong - p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) - case ethwire.MsgPongTy: - p.lastPong = time.Now().Unix() + case ethwire.MsgGetChainTy: + } } @@ -235,6 +241,7 @@ func (p *Peer) Stop() { close(p.quit) if atomic.LoadInt32(&p.connected) != 0 { + p.writeMessage(ethwire.NewMessage(ethwire.MsgDiscTy, "")) p.conn.Close() } From 884f7928717394d631fbc8b721d8ee297f060e5b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 27 Jan 2014 15:34:50 +0100 Subject: [PATCH 0006/1237] Removed default connection --- ethereum.go | 12 +++++++----- peer.go | 28 +++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/ethereum.go b/ethereum.go index 74e47d7bfd..ac11903c02 100644 --- a/ethereum.go +++ b/ethereum.go @@ -152,12 +152,14 @@ func (s *Ethereum) Start() { if ethutil.Config.Debug { log.Println("Connection listening disabled. Acting as client") - err = s.ConnectToPeer("localhost:12345") - if err != nil { - log.Println("Error starting ethereum", err) + /* + err = s.ConnectToPeer("localhost:12345") + if err != nil { + log.Println("Error starting ethereum", err) - s.Stop() - } + s.Stop() + } + */ } else { log.Fatal(err) } diff --git a/peer.go b/peer.go index f370580cfd..d2328c393b 100644 --- a/peer.go +++ b/peer.go @@ -68,9 +68,12 @@ func NewOutboundPeer(addr string, ethereum *Ethereum) *Peer { // Set up the connection in another goroutine so we don't block the main thread go func() { - conn, err := net.Dial("tcp", addr) + conn, err := net.DialTimeout("tcp", addr, 30*time.Second) + if err != nil { + log.Println("Connection to peer failed", err) p.Stop() + return } p.conn = conn @@ -211,7 +214,30 @@ out: p.requestedPeerList = false } case ethwire.MsgGetChainTy: + blocksFound := 0 + l := msg.Data.Length() + // Check each SHA block hash from the message and determine whether + // the SHA is in the database + for i := 0; i < l; i++ { + if p.ethereum.BlockManager.BlockChain().HasBlock(msg.Data.Get(i).AsString()) { + blocksFound++ + // TODO send reply + } + } + // If no blocks are found we send back a reply with msg not in chain + // and the last hash from get chain + if blocksFound == 0 { + lastHash := msg.Data.Get(l - 1) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, lastHash)) + } + case ethwire.MsgNotInChainTy: + log.Println("Not in chain, not yet implemented") + // TODO + + // Unofficial but fun nonetheless + case ethwire.MsgTalkTy: + log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Get(0).AsString()) } } From 4a82230de58077b2f947dced27cce0e2abb6272e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 27 Jan 2014 22:13:46 +0100 Subject: [PATCH 0007/1237] Switched port and removed logging --- ethereum.go | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/ethereum.go b/ethereum.go index ac11903c02..5eaf31d128 100644 --- a/ethereum.go +++ b/ethereum.go @@ -133,8 +133,6 @@ func (s *Ethereum) ReapDeadPeers() { for { eachPeer(s.peers, func(p *Peer, e *list.Element) { if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { - log.Println("Dead peer found .. reaping") - s.peers.Remove(e) } }) @@ -145,8 +143,8 @@ func (s *Ethereum) ReapDeadPeers() { // Start the ethereum func (s *Ethereum) Start() { - // For now this function just blocks the main thread - ln, err := net.Listen("tcp", ":12345") + // Bind to addr and port + ln, err := net.Listen("tcp", ":30303") if err != nil { // This is mainly for testing to create a "network" if ethutil.Config.Debug { @@ -167,6 +165,7 @@ func (s *Ethereum) Start() { // Starting accepting connections go func() { for { + log.Println("Ready and accepting connections") conn, err := ln.Accept() if err != nil { log.Println(err) @@ -184,17 +183,6 @@ func (s *Ethereum) Start() { // Start the tx pool s.TxPool.Start() - - // TMP - /* - go func() { - for { - s.Broadcast("block", s.blockManager.bc.GenesisBlock().RlpEncode()) - - time.Sleep(1000 * time.Millisecond) - } - }() - */ } func (s *Ethereum) Stop() { From 3e400739a77c8d2555ea74ae1544b483b375a960 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Jan 2014 15:35:44 +0100 Subject: [PATCH 0008/1237] Implemented get chain msg --- peer.go | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/peer.go b/peer.go index d2328c393b..ab16575e74 100644 --- a/peer.go +++ b/peer.go @@ -178,9 +178,14 @@ out: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) case ethwire.MsgPongTy: + // If we received a pong back from a peer we set the + // last pong so the peer handler knows this peer is still + // active. p.lastPong = time.Now().Unix() case ethwire.MsgBlockTy: - for i := 0; i < msg.Data.Length(); i++ { + // Get all blocks and process them (TODO reverse order?) + msg.Data = msg.Data.Get(0) + for i := msg.Data.Length() - 1; i >= 0; i-- { block := ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) err := p.ethereum.BlockManager.ProcessBlock(block) @@ -189,10 +194,15 @@ out: } } case ethwire.MsgTxTy: + // If the message was a transaction queue the transaction + // in the TxPool where it will undergo validation and + // processing when a new block is found for i := 0; i < msg.Data.Length(); i++ { p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(i))) } case ethwire.MsgGetPeersTy: + // Flag this peer as a 'requested of new peers' this to + // prevent malicious peers being forced. p.requestedPeerList = true // Peer asked for list of connected peers p.pushPeers() @@ -214,22 +224,31 @@ out: p.requestedPeerList = false } case ethwire.MsgGetChainTy: - blocksFound := 0 - l := msg.Data.Length() + var parent *ethchain.Block + // FIXME + msg.Data = msg.Data.Get(0) + // Length minus one since the very last element in the array is a count + l := msg.Data.Length() - 1 + // Amount of parents in the canonical chain + amountOfBlocks := msg.Data.Get(l).AsUint() // Check each SHA block hash from the message and determine whether // the SHA is in the database for i := 0; i < l; i++ { - if p.ethereum.BlockManager.BlockChain().HasBlock(msg.Data.Get(i).AsString()) { - blocksFound++ - // TODO send reply + if data := msg.Data.Get(i).AsBytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { + parent = p.ethereum.BlockManager.BlockChain().GetBlock(data) + break } } - // If no blocks are found we send back a reply with msg not in chain - // and the last hash from get chain - if blocksFound == 0 { - lastHash := msg.Data.Get(l - 1) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, lastHash)) + // If a parent is found send back a reply + if parent != nil { + chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) + } else { + // If no blocks are found we send back a reply with msg not in chain + // and the last hash from get chain + lastHash := msg.Data.Get(l) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, lastHash.AsRaw())) } case ethwire.MsgNotInChainTy: log.Println("Not in chain, not yet implemented") @@ -320,6 +339,9 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.Stop() } + } else { + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) + p.QueueMessage(msg) } } From 7ccf51fd3035aaba8ed3eda0ca8e3b01edaaa2cf Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 30 Jan 2014 23:48:52 +0100 Subject: [PATCH 0009/1237] Updated seed peers --- ethereum.go | 14 +-- peer.go | 241 ++++++++++++++++++++++++++++------------------------ 2 files changed, 137 insertions(+), 118 deletions(-) diff --git a/ethereum.go b/ethereum.go index 5eaf31d128..72d023f5ca 100644 --- a/ethereum.go +++ b/ethereum.go @@ -72,10 +72,13 @@ func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) if peer != nil { - s.peers.PushBack(peer) - peer.Start() - - log.Println("Peer connected ::", conn.RemoteAddr()) + if s.peers.Len() > -1 { + log.Println("SEED") + peer.Start(true) + } else { + s.peers.PushBack(peer) + peer.Start(false) + } } } @@ -164,8 +167,9 @@ func (s *Ethereum) Start() { } else { // Starting accepting connections go func() { + log.Println("Ready and accepting connections") + for { - log.Println("Ready and accepting connections") conn, err := ln.Accept() if err != nil { log.Println(err) diff --git a/peer.go b/peer.go index ab16575e74..627e57b052 100644 --- a/peer.go +++ b/peer.go @@ -42,6 +42,9 @@ type Peer struct { // Indicates whether a MsgGetPeersTy was requested of the peer // this to prevent receiving false peers. requestedPeerList bool + + // Determines whether this is a seed peer + seed bool } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -81,9 +84,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum) *Peer { atomic.StoreInt32(&p.connected, 1) atomic.StoreInt32(&p.disconnect, 0) - log.Println("Connected to peer ::", conn.RemoteAddr()) - - p.Start() + p.Start(false) }() return p @@ -115,6 +116,14 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { p.Stop() return } + + // XXX TMP CODE FOR TESTNET + switch msg.Type { + case ethwire.MsgPeersTy: + if p.seed { + p.Stop() + } + } } // Outbound message handler. Outbound messages are handled here @@ -133,7 +142,7 @@ out: case <-tickleTimer.C: p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) - // Break out of the for loop if a quit message is posted + // Break out of the for loop if a quit message is posted case <-p.quit: break out } @@ -157,113 +166,118 @@ func (p *Peer) HandleInbound() { out: for atomic.LoadInt32(&p.disconnect) == 0 { // Wait for a message from the peer - msg, err := ethwire.ReadMessage(p.conn) - if err != nil { - log.Println(err) + msgs, err := ethwire.ReadMessages(p.conn) + for _, msg := range msgs { + if err != nil { + log.Println(err) - break out - } + break out + } - if ethutil.Config.Debug { - log.Printf("Received %s\n", msg.Type.String()) - } + switch msg.Type { + case ethwire.MsgHandshakeTy: + // Version message + p.handleHandshake(msg) + case ethwire.MsgDiscTy: + p.Stop() + case ethwire.MsgPingTy: + // Respond back with pong + p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) + case ethwire.MsgPongTy: + // If we received a pong back from a peer we set the + // last pong so the peer handler knows this peer is still + // active. + p.lastPong = time.Now().Unix() + case ethwire.MsgBlockTy: + // Get all blocks and process them + msg.Data = msg.Data + for i := msg.Data.Length() - 1; i >= 0; i-- { + block := ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) + err := p.ethereum.BlockManager.ProcessBlock(block) - switch msg.Type { - case ethwire.MsgHandshakeTy: - // Version message - p.handleHandshake(msg) - case ethwire.MsgDiscTy: - p.Stop() - case ethwire.MsgPingTy: - // Respond back with pong - p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) - case ethwire.MsgPongTy: - // If we received a pong back from a peer we set the - // last pong so the peer handler knows this peer is still - // active. - p.lastPong = time.Now().Unix() - case ethwire.MsgBlockTy: - // Get all blocks and process them (TODO reverse order?) - msg.Data = msg.Data.Get(0) - for i := msg.Data.Length() - 1; i >= 0; i-- { - block := ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - err := p.ethereum.BlockManager.ProcessBlock(block) - - if err != nil { - log.Println(err) + if err != nil { + log.Println(err) + } } - } - case ethwire.MsgTxTy: - // If the message was a transaction queue the transaction - // in the TxPool where it will undergo validation and - // processing when a new block is found - for i := 0; i < msg.Data.Length(); i++ { - p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(i))) - } - case ethwire.MsgGetPeersTy: - // Flag this peer as a 'requested of new peers' this to - // prevent malicious peers being forced. - p.requestedPeerList = true - // Peer asked for list of connected peers - p.pushPeers() - case ethwire.MsgPeersTy: - // Received a list of peers (probably because MsgGetPeersTy was send) - // Only act on message if we actually requested for a peers list - if p.requestedPeerList { - data := ethutil.Conv(msg.Data) - // Create new list of possible peers for the ethereum to process - peers := make([]string, data.Length()) - // Parse each possible peer - for i := 0; i < data.Length(); i++ { - peers[i] = data.Get(i).AsString() + strconv.Itoa(int(data.Get(i).AsUint())) + case ethwire.MsgTxTy: + // If the message was a transaction queue the transaction + // in the TxPool where it will undergo validation and + // processing when a new block is found + for i := 0; i < msg.Data.Length(); i++ { + p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(i))) } + case ethwire.MsgGetPeersTy: + // Flag this peer as a 'requested of new peers' this to + // prevent malicious peers being forced. + p.requestedPeerList = true + // Peer asked for list of connected peers + p.pushPeers() + case ethwire.MsgPeersTy: + // Received a list of peers (probably because MsgGetPeersTy was send) + // Only act on message if we actually requested for a peers list + if p.requestedPeerList { + data := ethutil.Conv(msg.Data) + // Create new list of possible peers for the ethereum to process + peers := make([]string, data.Length()) + // Parse each possible peer + for i := 0; i < data.Length(); i++ { + peers[i] = data.Get(i).AsString() + strconv.Itoa(int(data.Get(i).AsUint())) + } - // Connect to the list of peers - p.ethereum.ProcessPeerList(peers) - // Mark unrequested again - p.requestedPeerList = false - } - case ethwire.MsgGetChainTy: - var parent *ethchain.Block - // FIXME - msg.Data = msg.Data.Get(0) - // Length minus one since the very last element in the array is a count - l := msg.Data.Length() - 1 - // Amount of parents in the canonical chain - amountOfBlocks := msg.Data.Get(l).AsUint() - // Check each SHA block hash from the message and determine whether - // the SHA is in the database - for i := 0; i < l; i++ { - if data := msg.Data.Get(i).AsBytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { - parent = p.ethereum.BlockManager.BlockChain().GetBlock(data) + // Connect to the list of peers + p.ethereum.ProcessPeerList(peers) + // Mark unrequested again + p.requestedPeerList = false + + } + case ethwire.MsgGetChainTy: + var parent *ethchain.Block + // Length minus one since the very last element in the array is a count + l := msg.Data.Length() - 1 + // Ignore empty get chains + if l <= 1 { break } - } - // If a parent is found send back a reply - if parent != nil { - chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) - } else { - // If no blocks are found we send back a reply with msg not in chain - // and the last hash from get chain - lastHash := msg.Data.Get(l) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, lastHash.AsRaw())) - } - case ethwire.MsgNotInChainTy: - log.Println("Not in chain, not yet implemented") - // TODO + // Amount of parents in the canonical chain + amountOfBlocks := msg.Data.Get(l).AsUint() + // Check each SHA block hash from the message and determine whether + // the SHA is in the database + for i := 0; i < l; i++ { + if data := msg.Data.Get(i).AsBytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { + parent = p.ethereum.BlockManager.BlockChain().GetBlock(data) + break + } + } - // Unofficial but fun nonetheless - case ethwire.MsgTalkTy: - log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Get(0).AsString()) + // If a parent is found send back a reply + if parent != nil { + chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, append(chain, amountOfBlocks))) + } else { + // If no blocks are found we send back a reply with msg not in chain + // and the last hash from get chain + lastHash := msg.Data.Get(l - 1) + log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.AsRaw()})) + } + case ethwire.MsgNotInChainTy: + log.Printf("Not in chain %x\n", msg.Data) + // TODO + + // Unofficial but fun nonetheless + case ethwire.MsgTalkTy: + log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.AsString()) + } } } p.Stop() } -func (p *Peer) Start() { +func (p *Peer) Start(seed bool) { + p.seed = seed + if !p.inbound { err := p.pushHandshake() if err != nil { @@ -277,6 +291,7 @@ func (p *Peer) Start() { go p.HandleOutbound() // Run the inbound handler in a new goroutine go p.HandleInbound() + } func (p *Peer) Stop() { @@ -294,9 +309,9 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, ethutil.Encode([]interface{}{ - 1, 0, p.ethereum.Nonce, - })) + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ + uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", + }) p.QueueMessage(msg) @@ -305,6 +320,7 @@ func (p *Peer) pushHandshake() error { // Pushes the list of outbound peers to the client when requested func (p *Peer) pushPeers() { + outPeers := make([]interface{}, len(p.ethereum.OutboundPeers())) // Serialise each peer for i, peer := range p.ethereum.OutboundPeers() { @@ -312,7 +328,7 @@ func (p *Peer) pushPeers() { } // Send message to the peer with the known list of connected clients - msg := ethwire.NewMessage(ethwire.MsgPeersTy, ethutil.Encode(outPeers)) + msg := ethwire.NewMessage(ethwire.MsgPeersTy, outPeers) p.QueueMessage(msg) } @@ -320,29 +336,28 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID] - if c.Get(2).AsUint() == p.ethereum.Nonce { - //if msg.Nonce == p.ethereum.Nonce { - log.Println("Peer connected to self, disconnecting") - - p.Stop() - - return - } - p.versionKnown = true + var istr string // If this is an inbound connection send an ack back if p.inbound { - err := p.pushHandshake() - if err != nil { - log.Println("Peer can't send ack back") + /* + err := p.pushHandshake() + if err != nil { + log.Println("Peer can't send ack back") - p.Stop() - } + p.Stop() + } + */ + istr = "inbound" } else { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) p.QueueMessage(msg) + + istr = "outbound" } + + log.Printf("peer connect (%s) %v %s\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString()) } func (p *Peer) RlpEncode() []byte { From 7f100e96101a057cba7b2d5c58c12d2f7accf381 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 00:56:32 +0100 Subject: [PATCH 0010/1237] Self connect detect --- ethereum.go | 2 +- peer.go | 54 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/ethereum.go b/ethereum.go index 72d023f5ca..98316cf040 100644 --- a/ethereum.go +++ b/ethereum.go @@ -72,7 +72,7 @@ func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) if peer != nil { - if s.peers.Len() > -1 { + if s.peers.Len() > 25 { log.Println("SEED") peer.Start(true) } else { diff --git a/peer.go b/peer.go index 627e57b052..bd75a0039c 100644 --- a/peer.go +++ b/peer.go @@ -178,6 +178,8 @@ out: case ethwire.MsgHandshakeTy: // Version message p.handleHandshake(msg) + + p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) case ethwire.MsgDiscTy: p.Stop() case ethwire.MsgPingTy: @@ -216,12 +218,12 @@ out: // Received a list of peers (probably because MsgGetPeersTy was send) // Only act on message if we actually requested for a peers list if p.requestedPeerList { - data := ethutil.Conv(msg.Data) + data := msg.Data // Create new list of possible peers for the ethereum to process peers := make([]string, data.Length()) // Parse each possible peer for i := 0; i < data.Length(); i++ { - peers[i] = data.Get(i).AsString() + strconv.Itoa(int(data.Get(i).AsUint())) + peers[i] = data.Get(i).Get(0).AsString() + ":" + strconv.Itoa(int(data.Get(i).Get(1).AsUint())) } // Connect to the list of peers @@ -278,15 +280,28 @@ out: func (p *Peer) Start(seed bool) { p.seed = seed - if !p.inbound { - err := p.pushHandshake() - if err != nil { - log.Printf("Peer can't send outbound version ack", err) + peerHost, _, _ := net.SplitHostPort(p.conn.LocalAddr().String()) + servHost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) + log.Println(peerHost, servHost) + if peerHost == servHost { + log.Println("Connected to self") - p.Stop() - } + p.Stop() + + return } + //if !p.inbound { + err := p.pushHandshake() + if err != nil { + log.Printf("Peer can't send outbound version ack", err) + + p.Stop() + + return + } + //} + // Run the outbound handler in a new goroutine go p.HandleOutbound() // Run the inbound handler in a new goroutine @@ -320,11 +335,10 @@ func (p *Peer) pushHandshake() error { // Pushes the list of outbound peers to the client when requested func (p *Peer) pushPeers() { - outPeers := make([]interface{}, len(p.ethereum.OutboundPeers())) // Serialise each peer for i, peer := range p.ethereum.OutboundPeers() { - outPeers[i] = peer.RlpEncode() + outPeers[i] = peer.RlpData() } // Send message to the peer with the known list of connected clients @@ -351,8 +365,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { */ istr = "inbound" } else { - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) - p.QueueMessage(msg) + //msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) + //p.QueueMessage(msg) istr = "outbound" } @@ -360,6 +374,22 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { log.Printf("peer connect (%s) %v %s\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString()) } +func (p *Peer) RlpData() []interface{} { + host, prt, err := net.SplitHostPort(p.conn.RemoteAddr().String()) + if err != nil { + return nil + } + + port, err := strconv.Atoi(prt) + if err != nil { + return nil + } + + //port := ethutil.NumberToBytes(uint16(i), 16) + + return []interface{}{host, port} +} + func (p *Peer) RlpEncode() []byte { host, prt, err := net.SplitHostPort(p.conn.RemoteAddr().String()) if err != nil { From 36f221dbe7e66568fc3f1680208b73e4ea20c4ef Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 01:12:48 +0100 Subject: [PATCH 0011/1237] Don't connect to peers that are already connected --- ethereum.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethereum.go b/ethereum.go index 98316cf040..dd6256f4b4 100644 --- a/ethereum.go +++ b/ethereum.go @@ -90,6 +90,22 @@ func (s *Ethereum) ProcessPeerList(addrs []string) { } func (s *Ethereum) ConnectToPeer(addr string) error { + var alreadyConnected bool + + eachPeer(s.peers, func(p *Peer, v *list.Element) { + phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) + ahost, _, _ := net.SplitHostPort(addr) + + if phost == ahost { + alreadyConnected = true + return + } + }) + + if alreadyConnected { + return nil + } + peer := NewOutboundPeer(addr, s) s.peers.PushBack(peer) From dfa38b3f91d124f97350429c4664b62a5cb7dd08 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 11:18:10 +0100 Subject: [PATCH 0012/1237] Peer connection checking --- ethereum.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index dd6256f4b4..e1fb5945c5 100644 --- a/ethereum.go +++ b/ethereum.go @@ -93,6 +93,9 @@ func (s *Ethereum) ConnectToPeer(addr string) error { var alreadyConnected bool eachPeer(s.peers, func(p *Peer, v *list.Element) { + if p.conn == nil { + return + } phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) ahost, _, _ := net.SplitHostPort(addr) @@ -118,7 +121,7 @@ func (s *Ethereum) OutboundPeers() []*Peer { outboundPeers := make([]*Peer, s.peers.Len()) length := 0 eachPeer(s.peers, func(p *Peer, e *list.Element) { - if !p.inbound { + if !p.inbound && p.conn != nil { outboundPeers[length] = p length++ } From da66eddfccf86eb5dc036e023ddc2e0278105706 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 11:57:56 +0100 Subject: [PATCH 0013/1237] Get peers returns now both in and outbound peers --- ethereum.go | 16 ++++++++++++++++ peer.go | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index e1fb5945c5..b9fc94d509 100644 --- a/ethereum.go +++ b/ethereum.go @@ -144,6 +144,18 @@ func (s *Ethereum) InboundPeers() []*Peer { return inboundPeers[:length] } +func (s *Ethereum) InOutPeers() []*Peer { + // Create a new peer slice with at least the length of the total peers + inboundPeers := make([]*Peer, s.peers.Len()) + length := 0 + eachPeer(s.peers, func(p *Peer, e *list.Element) { + inboundPeers[length] = p + length++ + }) + + return inboundPeers[:length] +} + func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data interface{}) { msg := ethwire.NewMessage(msgType, data) eachPeer(s.peers, func(p *Peer, e *list.Element) { @@ -151,6 +163,10 @@ func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data interface{}) { }) } +func (s *Ethereum) Peers() *list.List { + return s.peers +} + func (s *Ethereum) ReapDeadPeers() { for { eachPeer(s.peers, func(p *Peer, e *list.Element) { diff --git a/peer.go b/peer.go index bd75a0039c..410e310f55 100644 --- a/peer.go +++ b/peer.go @@ -335,9 +335,9 @@ func (p *Peer) pushHandshake() error { // Pushes the list of outbound peers to the client when requested func (p *Peer) pushPeers() { - outPeers := make([]interface{}, len(p.ethereum.OutboundPeers())) + outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) // Serialise each peer - for i, peer := range p.ethereum.OutboundPeers() { + for i, peer := range p.ethereum.InOutPeers() { outPeers[i] = peer.RlpData() } From 8c09602a8b6dead7e03d0d4b9fe61cbd02d8a844 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 13:03:13 +0100 Subject: [PATCH 0014/1237] Self connect --- ethereum.go | 9 --------- peer.go | 1 - 2 files changed, 10 deletions(-) diff --git a/ethereum.go b/ethereum.go index b9fc94d509..0137f68de1 100644 --- a/ethereum.go +++ b/ethereum.go @@ -187,15 +187,6 @@ func (s *Ethereum) Start() { // This is mainly for testing to create a "network" if ethutil.Config.Debug { log.Println("Connection listening disabled. Acting as client") - - /* - err = s.ConnectToPeer("localhost:12345") - if err != nil { - log.Println("Error starting ethereum", err) - - s.Stop() - } - */ } else { log.Fatal(err) } diff --git a/peer.go b/peer.go index 410e310f55..2c442dc82a 100644 --- a/peer.go +++ b/peer.go @@ -282,7 +282,6 @@ func (p *Peer) Start(seed bool) { peerHost, _, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) - log.Println(peerHost, servHost) if peerHost == servHost { log.Println("Connected to self") From ce69334988bb42e5dd1e6cb6c81d8d311babcf04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 13:37:16 +0100 Subject: [PATCH 0015/1237] For the testnet always 30303 for now to make it easy --- peer.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 2c442dc82a..c4499a67fe 100644 --- a/peer.go +++ b/peer.go @@ -374,19 +374,21 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } func (p *Peer) RlpData() []interface{} { - host, prt, err := net.SplitHostPort(p.conn.RemoteAddr().String()) + host, _, err := net.SplitHostPort(p.conn.RemoteAddr().String()) if err != nil { return nil } + /* FIXME port, err := strconv.Atoi(prt) if err != nil { return nil } + */ //port := ethutil.NumberToBytes(uint16(i), 16) - return []interface{}{host, port} + return []interface{}{host, uint16(30303) /*port*/} } func (p *Peer) RlpEncode() []byte { From 8c4746a3dfed68603612bb0d702fe1f3aca1e26f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Jan 2014 20:01:28 +0100 Subject: [PATCH 0016/1237] (un)pack addr --- peer.go | 120 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 87 insertions(+), 33 deletions(-) diff --git a/peer.go b/peer.go index c4499a67fe..c91df79dbc 100644 --- a/peer.go +++ b/peer.go @@ -7,6 +7,7 @@ import ( "log" "net" "strconv" + "strings" "sync/atomic" "time" ) @@ -16,6 +17,36 @@ const ( outputBufferSize = 50 ) +// Peer capabillities +type Caps byte + +const ( + CapDiscoveryTy = 0x01 + CapTxTy = 0x02 + CapChainTy = 0x04 +) + +var capsToString = map[Caps]string{ + CapDiscoveryTy: "Peer discovery", + CapTxTy: "Transaction relaying", + CapChainTy: "Block chain relaying", +} + +func (c Caps) String() string { + var caps []string + if c&CapDiscoveryTy > 0 { + caps = append(caps, capsToString[CapDiscoveryTy]) + } + if c&CapChainTy > 0 { + caps = append(caps, capsToString[CapChainTy]) + } + if c&CapTxTy > 0 { + caps = append(caps, capsToString[CapTxTy]) + } + + return strings.Join(caps, " | ") +} + type Peer struct { // Ethereum interface ethereum *Ethereum @@ -45,6 +76,10 @@ type Peer struct { // Determines whether this is a seed peer seed bool + + host []byte + port uint16 + caps Caps } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -56,6 +91,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { inbound: inbound, disconnect: 0, connected: 1, + port: 30303, } } @@ -223,7 +259,8 @@ out: peers := make([]string, data.Length()) // Parse each possible peer for i := 0; i < data.Length(); i++ { - peers[i] = data.Get(i).Get(0).AsString() + ":" + strconv.Itoa(int(data.Get(i).Get(1).AsUint())) + peers[i] = unpackAddr(data.Get(i).Get(0).AsBytes(), data.Get(i).Get(1).AsUint()) + log.Println(peers[i]) } // Connect to the list of peers @@ -277,20 +314,52 @@ out: p.Stop() } +func packAddr(address, port string) ([]byte, uint16) { + addr := strings.Split(address, ".") + a, _ := strconv.Atoi(addr[0]) + b, _ := strconv.Atoi(addr[1]) + c, _ := strconv.Atoi(addr[2]) + d, _ := strconv.Atoi(addr[3]) + host := []byte{byte(a), byte(b), byte(c), byte(d)} + prt, _ := strconv.Atoi(port) + + return host, uint16(prt) +} + +func unpackAddr(h []byte, p uint64) string { + if len(h) != 4 { + return "" + } + + a := strconv.Itoa(int(h[0])) + b := strconv.Itoa(int(h[1])) + c := strconv.Itoa(int(h[2])) + d := strconv.Itoa(int(h[3])) + host := strings.Join([]string{a, b, c, d}, ".") + port := strconv.Itoa(int(p)) + + return net.JoinHostPort(host, port) +} + func (p *Peer) Start(seed bool) { p.seed = seed - peerHost, _, _ := net.SplitHostPort(p.conn.LocalAddr().String()) - servHost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) + peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) + servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) if peerHost == servHost { log.Println("Connected to self") - p.Stop() + //p.Stop() - return + //return + } + + if p.inbound { + p.host, p.port = packAddr(peerHost, peerPort) + } else { + p.host, p.port = packAddr(servHost, servPort) } - //if !p.inbound { err := p.pushHandshake() if err != nil { log.Printf("Peer can't send outbound version ack", err) @@ -299,7 +368,6 @@ func (p *Peer) Start(seed bool) { return } - //} // Run the outbound handler in a new goroutine go p.HandleOutbound() @@ -324,7 +392,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", + uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", CapChainTy | CapTxTy | CapDiscoveryTy, p.port, }) p.QueueMessage(msg) @@ -354,41 +422,27 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { var istr string // If this is an inbound connection send an ack back if p.inbound { - /* - err := p.pushHandshake() - if err != nil { - log.Println("Peer can't send ack back") + if port := c.Get(4).AsUint(); port != 0 { + p.port = uint16(port) + } - p.Stop() - } - */ istr = "inbound" } else { - //msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) - //p.QueueMessage(msg) + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) + p.QueueMessage(msg) istr = "outbound" } - log.Printf("peer connect (%s) %v %s\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString()) + if caps := Caps(c.Get(3).AsByte()); caps != 0 { + p.caps = caps + } + + log.Printf("peer connect (%s) %v %s [%s]\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString(), p.caps) } func (p *Peer) RlpData() []interface{} { - host, _, err := net.SplitHostPort(p.conn.RemoteAddr().String()) - if err != nil { - return nil - } - - /* FIXME - port, err := strconv.Atoi(prt) - if err != nil { - return nil - } - */ - - //port := ethutil.NumberToBytes(uint16(i), 16) - - return []interface{}{host, uint16(30303) /*port*/} + return []interface{}{p.host, p.port /*port*/} } func (p *Peer) RlpEncode() []byte { From dfa778fed684e97f868aab9b246646156a39e24a Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 1 Feb 2014 21:30:54 +0100 Subject: [PATCH 0017/1237] UPNP wip --- ethereum.go | 64 ++++++++- peer.go | 47 +++--- upnp.go | 405 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 485 insertions(+), 31 deletions(-) create mode 100644 upnp.go diff --git a/ethereum.go b/ethereum.go index 0137f68de1..b192b544d8 100644 --- a/ethereum.go +++ b/ethereum.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/ethwire-go" "log" "net" + "strconv" "sync/atomic" "time" ) @@ -40,6 +41,10 @@ type Ethereum struct { peers *list.List // Nonce Nonce uint64 + + Addr net.Addr + + nat NAT } func New() (*Ethereum, error) { @@ -51,12 +56,20 @@ func New() (*Ethereum, error) { ethutil.Config.Db = db + /* + nat, err := Discover() + if err != nil { + log.Printf("Can'them discover upnp: %v", err) + } + */ + nonce, _ := ethutil.RandomUint64() ethereum := &Ethereum{ shutdownChan: make(chan bool), db: db, peers: list.New(), Nonce: nonce, + //nat: nat, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -179,18 +192,59 @@ func (s *Ethereum) ReapDeadPeers() { } } +// FIXME +func (s *Ethereum) upnpUpdateThread() { + // Go off immediately to prevent code duplication, thereafter we renew + // lease every 15 minutes. + timer := time.NewTimer(0 * time.Second) + lport, _ := strconv.ParseInt("30303", 10, 16) + first := true +out: + for { + select { + case <-timer.C: + listenPort, err := s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) + if err != nil { + log.Printf("can't add UPnP port mapping: %v\n", err) + } + if first && err == nil { + externalip, err := s.nat.GetExternalAddress() + if err != nil { + log.Printf("UPnP can't get external address: %v\n", err) + continue out + } + // externalip, listenport + log.Println("Successfully bound via UPnP to", externalip, listenPort) + first = false + } + timer.Reset(time.Minute * 15) + case <-s.shutdownChan: + break out + } + } + + timer.Stop() + + if err := s.nat.DeletePortMapping("tcp", int(lport), int(lport)); err != nil { + log.Printf("unable to remove UPnP port mapping: %v\n", err) + } else { + log.Printf("succesfully disestablished UPnP port mapping\n") + } +} + // Start the ethereum func (s *Ethereum) Start() { // Bind to addr and port ln, err := net.Listen("tcp", ":30303") if err != nil { // This is mainly for testing to create a "network" - if ethutil.Config.Debug { - log.Println("Connection listening disabled. Acting as client") - } else { - log.Fatal(err) - } + //if ethutil.Config.Debug { + //log.Println("Connection listening disabled. Acting as client") + //} else { + log.Fatal(err) + //} } else { + s.Addr = ln.Addr() // Starting accepting connections go func() { log.Println("Ready and accepting connections") diff --git a/peer.go b/peer.go index c91df79dbc..5d22b545c7 100644 --- a/peer.go +++ b/peer.go @@ -253,22 +253,21 @@ out: case ethwire.MsgPeersTy: // Received a list of peers (probably because MsgGetPeersTy was send) // Only act on message if we actually requested for a peers list - if p.requestedPeerList { - data := msg.Data - // Create new list of possible peers for the ethereum to process - peers := make([]string, data.Length()) - // Parse each possible peer - for i := 0; i < data.Length(); i++ { - peers[i] = unpackAddr(data.Get(i).Get(0).AsBytes(), data.Get(i).Get(1).AsUint()) - log.Println(peers[i]) - } - - // Connect to the list of peers - p.ethereum.ProcessPeerList(peers) - // Mark unrequested again - p.requestedPeerList = false - + //if p.requestedPeerList { + data := msg.Data + // Create new list of possible peers for the ethereum to process + peers := make([]string, data.Length()) + // Parse each possible peer + for i := 0; i < data.Length(); i++ { + peers[i] = unpackAddr(data.Get(i).Get(0), data.Get(i).Get(1).AsUint()) } + + // Connect to the list of peers + p.ethereum.ProcessPeerList(peers) + // Mark unrequested again + p.requestedPeerList = false + + //} case ethwire.MsgGetChainTy: var parent *ethchain.Block // Length minus one since the very last element in the array is a count @@ -326,15 +325,11 @@ func packAddr(address, port string) ([]byte, uint16) { return host, uint16(prt) } -func unpackAddr(h []byte, p uint64) string { - if len(h) != 4 { - return "" - } - - a := strconv.Itoa(int(h[0])) - b := strconv.Itoa(int(h[1])) - c := strconv.Itoa(int(h[2])) - d := strconv.Itoa(int(h[3])) +func unpackAddr(value *ethutil.RlpValue, p uint64) string { + a := strconv.Itoa(int(value.Get(0).AsUint())) + b := strconv.Itoa(int(value.Get(1).AsUint())) + c := strconv.Itoa(int(value.Get(2).AsUint())) + d := strconv.Itoa(int(value.Get(3).AsUint())) host := strings.Join([]string{a, b, c, d}, ".") port := strconv.Itoa(int(p)) @@ -349,9 +344,9 @@ func (p *Peer) Start(seed bool) { if peerHost == servHost { log.Println("Connected to self") - //p.Stop() + p.Stop() - //return + return } if p.inbound { diff --git a/upnp.go b/upnp.go new file mode 100644 index 0000000000..c84ed04f8d --- /dev/null +++ b/upnp.go @@ -0,0 +1,405 @@ +package eth + +// Upnp code taken from Taipei Torrent license is below: +// Copyright (c) 2010 Jack Palevich. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Just enough UPnP to be able to forward ports +// + +import ( + "bytes" + "encoding/xml" + "errors" + "net" + "net/http" + "os" + "strconv" + "strings" + "time" +) + +// NAT is an interface representing a NAT traversal options for example UPNP or +// NAT-PMP. It provides methods to query and manipulate this traversal to allow +// access to services. +type NAT interface { + // Get the external address from outside the NAT. + GetExternalAddress() (addr net.IP, err error) + // Add a port mapping for protocol ("udp" or "tcp") from externalport to + // internal port with description lasting for timeout. + AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) + // Remove a previously added port mapping from externalport to + // internal port. + DeletePortMapping(protocol string, externalPort, internalPort int) (err error) +} + +type upnpNAT struct { + serviceURL string + ourIP string +} + +// Discover searches the local network for a UPnP router returning a NAT +// for the network if so, nil if not. +func Discover() (nat NAT, err error) { + ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900") + if err != nil { + return + } + conn, err := net.ListenPacket("udp4", ":0") + if err != nil { + return + } + socket := conn.(*net.UDPConn) + defer socket.Close() + + err = socket.SetDeadline(time.Now().Add(3 * time.Second)) + if err != nil { + return + } + + st := "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" + buf := bytes.NewBufferString( + "M-SEARCH * HTTP/1.1\r\n" + + "HOST: 239.255.255.250:1900\r\n" + + st + + "MAN: \"ssdp:discover\"\r\n" + + "MX: 2\r\n\r\n") + message := buf.Bytes() + answerBytes := make([]byte, 1024) + for i := 0; i < 3; i++ { + _, err = socket.WriteToUDP(message, ssdp) + if err != nil { + return + } + var n int + n, _, err = socket.ReadFromUDP(answerBytes) + if err != nil { + continue + // socket.Close() + // return + } + answer := string(answerBytes[0:n]) + if strings.Index(answer, "\r\n"+st) < 0 { + continue + } + // HTTP header field names are case-insensitive. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + locString := "\r\nlocation: " + answer = strings.ToLower(answer) + locIndex := strings.Index(answer, locString) + if locIndex < 0 { + continue + } + loc := answer[locIndex+len(locString):] + endIndex := strings.Index(loc, "\r\n") + if endIndex < 0 { + continue + } + locURL := loc[0:endIndex] + var serviceURL string + serviceURL, err = getServiceURL(locURL) + if err != nil { + return + } + var ourIP string + ourIP, err = getOurIP() + if err != nil { + return + } + nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP} + return + } + err = errors.New("UPnP port discovery failed") + return +} + +// service represents the Service type in an UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type service struct { + ServiceType string `xml:"serviceType"` + ControlURL string `xml:"controlURL"` +} + +// deviceList represents the deviceList type in an UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type deviceList struct { + XMLName xml.Name `xml:"deviceList"` + Device []device `xml:"device"` +} + +// serviceList represents the serviceList type in an UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type serviceList struct { + XMLName xml.Name `xml:"serviceList"` + Service []service `xml:"service"` +} + +// device represents the device type in an UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type device struct { + XMLName xml.Name `xml:"device"` + DeviceType string `xml:"deviceType"` + DeviceList deviceList `xml:"deviceList"` + ServiceList serviceList `xml:"serviceList"` +} + +// specVersion represents the specVersion in a UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type specVersion struct { + XMLName xml.Name `xml:"specVersion"` + Major int `xml:"major"` + Minor int `xml:"minor"` +} + +// root represents the Root document for a UPnP xml description. +// Only the parts we care about are present and thus the xml may have more +// fields than present in the structure. +type root struct { + XMLName xml.Name `xml:"root"` + SpecVersion specVersion + Device device +} + +// getChildDevice searches the children of device for a device with the given +// type. +func getChildDevice(d *device, deviceType string) *device { + for i := range d.DeviceList.Device { + if d.DeviceList.Device[i].DeviceType == deviceType { + return &d.DeviceList.Device[i] + } + } + return nil +} + +// getChildDevice searches the service list of device for a service with the +// given type. +func getChildService(d *device, serviceType string) *service { + for i := range d.ServiceList.Service { + if d.ServiceList.Service[i].ServiceType == serviceType { + return &d.ServiceList.Service[i] + } + } + return nil +} + +// getOurIP returns a best guess at what the local IP is. +func getOurIP() (ip string, err error) { + hostname, err := os.Hostname() + if err != nil { + return + } + return net.LookupCNAME(hostname) +} + +// getServiceURL parses the xml description at the given root url to find the +// url for the WANIPConnection service to be used for port forwarding. +func getServiceURL(rootURL string) (url string, err error) { + r, err := http.Get(rootURL) + if err != nil { + return + } + defer r.Body.Close() + if r.StatusCode >= 400 { + err = errors.New(string(r.StatusCode)) + return + } + var root root + err = xml.NewDecoder(r.Body).Decode(&root) + if err != nil { + return + } + a := &root.Device + if a.DeviceType != "urn:schemas-upnp-org:device:InternetGatewayDevice:1" { + err = errors.New("no InternetGatewayDevice") + return + } + b := getChildDevice(a, "urn:schemas-upnp-org:device:WANDevice:1") + if b == nil { + err = errors.New("no WANDevice") + return + } + c := getChildDevice(b, "urn:schemas-upnp-org:device:WANConnectionDevice:1") + if c == nil { + err = errors.New("no WANConnectionDevice") + return + } + d := getChildService(c, "urn:schemas-upnp-org:service:WANIPConnection:1") + if d == nil { + err = errors.New("no WANIPConnection") + return + } + url = combineURL(rootURL, d.ControlURL) + return +} + +// combineURL appends subURL onto rootURL. +func combineURL(rootURL, subURL string) string { + protocolEnd := "://" + protoEndIndex := strings.Index(rootURL, protocolEnd) + a := rootURL[protoEndIndex+len(protocolEnd):] + rootIndex := strings.Index(a, "/") + return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL +} + +// soapBody represents the element in a SOAP reply. +// fields we don't care about are elided. +type soapBody struct { + XMLName xml.Name `xml:"Body"` + Data []byte `xml:",innerxml"` +} + +// soapEnvelope represents the element in a SOAP reply. +// fields we don't care about are elided. +type soapEnvelope struct { + XMLName xml.Name `xml:"Envelope"` + Body soapBody `xml:"Body"` +} + +// soapRequests performs a soap request with the given parameters and returns +// the xml replied stripped of the soap headers. in the case that the request is +// unsuccessful the an error is returned. +func soapRequest(url, function, message string) (replyXML []byte, err error) { + fullMessage := "" + + "\r\n" + + "" + message + "" + + req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"") + req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3") + //req.Header.Set("Transfer-Encoding", "chunked") + req.Header.Set("SOAPAction", "\"urn:schemas-upnp-org:service:WANIPConnection:1#"+function+"\"") + req.Header.Set("Connection", "Close") + req.Header.Set("Cache-Control", "no-cache") + req.Header.Set("Pragma", "no-cache") + + r, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + if r.Body != nil { + defer r.Body.Close() + } + + if r.StatusCode >= 400 { + // log.Stderr(function, r.StatusCode) + err = errors.New("Error " + strconv.Itoa(r.StatusCode) + " for " + function) + r = nil + return + } + var reply soapEnvelope + err = xml.NewDecoder(r.Body).Decode(&reply) + if err != nil { + return nil, err + } + return reply.Body.Data, nil +} + +// getExternalIPAddressResponse represents the XML response to a +// GetExternalIPAddress SOAP request. +type getExternalIPAddressResponse struct { + XMLName xml.Name `xml:"GetExternalIPAddressResponse"` + ExternalIPAddress string `xml:"NewExternalIPAddress"` +} + +// GetExternalAddress implements the NAT interface by fetching the external IP +// from the UPnP router. +func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) { + message := "\r\n" + response, err := soapRequest(n.serviceURL, "GetExternalIPAddress", message) + if err != nil { + return nil, err + } + + var reply getExternalIPAddressResponse + err = xml.Unmarshal(response, &reply) + if err != nil { + return nil, err + } + + addr = net.ParseIP(reply.ExternalIPAddress) + if addr == nil { + return nil, errors.New("unable to parse ip address") + } + return addr, nil +} + +// AddPortMapping implements the NAT interface by setting up a port forwarding +// from the UPnP router to the local machine with the given ports and protocol. +func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) { + // A single concatenation would break ARM compilation. + message := "\r\n" + + "" + strconv.Itoa(externalPort) + message += "" + protocol + "" + message += "" + strconv.Itoa(internalPort) + "" + + "" + n.ourIP + "" + + "1" + message += description + + "" + strconv.Itoa(timeout) + + "" + + response, err := soapRequest(n.serviceURL, "AddPortMapping", message) + if err != nil { + return + } + + // TODO: check response to see if the port was forwarded + // If the port was not wildcard we don't get an reply with the port in + // it. Not sure about wildcard yet. miniupnpc just checks for error + // codes here. + mappedExternalPort = externalPort + _ = response + return +} + +// AddPortMapping implements the NAT interface by removing up a port forwarding +// from the UPnP router to the local machine with the given ports and. +func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) { + + message := "\r\n" + + "" + strconv.Itoa(externalPort) + + "" + protocol + "" + + "" + + response, err := soapRequest(n.serviceURL, "DeletePortMapping", message) + if err != nil { + return + } + + // TODO: check response to see if the port was deleted + // log.Println(message, response) + _ = response + return +} From b70fe3a9bea652c795fc75cf79ed21fc04ea0937 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 01:39:06 +0100 Subject: [PATCH 0018/1237] Reverted back to messages --- ethereum.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ethereum.go b/ethereum.go index b192b544d8..a7a2f6b8cf 100644 --- a/ethereum.go +++ b/ethereum.go @@ -169,7 +169,7 @@ func (s *Ethereum) InOutPeers() []*Peer { return inboundPeers[:length] } -func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data interface{}) { +func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data []interface{}) { msg := ethwire.NewMessage(msgType, data) eachPeer(s.peers, func(p *Peer, e *list.Element) { p.QueueMessage(msg) @@ -237,12 +237,7 @@ func (s *Ethereum) Start() { // Bind to addr and port ln, err := net.Listen("tcp", ":30303") if err != nil { - // This is mainly for testing to create a "network" - //if ethutil.Config.Debug { - //log.Println("Connection listening disabled. Acting as client") - //} else { - log.Fatal(err) - //} + log.Println("Connection listening disabled. Acting as client") } else { s.Addr = ln.Addr() // Starting accepting connections From cb8a7d979d1a4b2a32317ee0a77815ec2ea38b9f Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 16:15:39 +0100 Subject: [PATCH 0019/1237] upnp test --- ethereum.go | 107 ++++++++++++++++++++++++++++++++-------------------- peer.go | 35 ++++++++++++----- 2 files changed, 91 insertions(+), 51 deletions(-) diff --git a/ethereum.go b/ethereum.go index a7a2f6b8cf..eab40e93dc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -9,6 +9,7 @@ import ( "log" "net" "strconv" + "sync" "sync/atomic" "time" ) @@ -45,9 +46,14 @@ type Ethereum struct { Addr net.Addr nat NAT + + peerMut sync.Mutex + + // Capabilities for outgoing peers + serverCaps Caps } -func New() (*Ethereum, error) { +func New(caps Caps) (*Ethereum, error) { //db, err := ethdb.NewLDBDatabase() db, err := ethdb.NewMemDatabase() if err != nil { @@ -56,12 +62,11 @@ func New() (*Ethereum, error) { ethutil.Config.Db = db - /* - nat, err := Discover() - if err != nil { - log.Printf("Can'them discover upnp: %v", err) - } - */ + nat, err := Discover() + if err != nil { + log.Printf("Can't discover upnp: %v", err) + } + log.Println(nat) nonce, _ := ethutil.RandomUint64() ethereum := &Ethereum{ @@ -69,7 +74,8 @@ func New() (*Ethereum, error) { db: db, peers: list.New(), Nonce: nonce, - //nat: nat, + serverCaps: caps, + nat: nat, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -85,13 +91,8 @@ func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) if peer != nil { - if s.peers.Len() > 25 { - log.Println("SEED") - peer.Start(true) - } else { - s.peers.PushBack(peer) - peer.Start(false) - } + s.peers.PushBack(peer) + peer.Start(false) } } @@ -122,7 +123,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { return nil } - peer := NewOutboundPeer(addr, s) + peer := NewOutboundPeer(addr, s, s.serverCaps) s.peers.PushBack(peer) @@ -158,12 +159,18 @@ func (s *Ethereum) InboundPeers() []*Peer { } func (s *Ethereum) InOutPeers() []*Peer { + // Reap the dead peers first + s.reapPeers() + // Create a new peer slice with at least the length of the total peers inboundPeers := make([]*Peer, s.peers.Len()) length := 0 eachPeer(s.peers, func(p *Peer, e *list.Element) { - inboundPeers[length] = p - length++ + // Only return peers with an actual ip + if len(p.host) > 0 { + inboundPeers[length] = p + length++ + } }) return inboundPeers[:length] @@ -171,6 +178,10 @@ func (s *Ethereum) InOutPeers() []*Peer { func (s *Ethereum) Broadcast(msgType ethwire.MsgType, data []interface{}) { msg := ethwire.NewMessage(msgType, data) + s.BroadcastMsg(msg) +} + +func (s *Ethereum) BroadcastMsg(msg *ethwire.Msg) { eachPeer(s.peers, func(p *Peer, e *list.Element) { p.QueueMessage(msg) }) @@ -180,15 +191,25 @@ func (s *Ethereum) Peers() *list.List { return s.peers } -func (s *Ethereum) ReapDeadPeers() { - for { - eachPeer(s.peers, func(p *Peer, e *list.Element) { - if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { - s.peers.Remove(e) - } - }) +func (s *Ethereum) reapPeers() { + s.peerMut.Lock() + defer s.peerMut.Unlock() - time.Sleep(processReapingTimeout * time.Second) + eachPeer(s.peers, func(p *Peer, e *list.Element) { + if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { + s.peers.Remove(e) + } + }) +} + +func (s *Ethereum) ReapDeadPeerHandler() { + reapTimer := time.NewTicker(processReapingTimeout * time.Second) + + for { + select { + case <-reapTimer.C: + s.reapPeers() + } } } @@ -241,29 +262,33 @@ func (s *Ethereum) Start() { } else { s.Addr = ln.Addr() // Starting accepting connections - go func() { - log.Println("Ready and accepting connections") - - for { - conn, err := ln.Accept() - if err != nil { - log.Println(err) - - continue - } - - go s.AddPeer(conn) - } - }() + log.Println("Ready and accepting connections") + // Start the peer handler + go s.peerHandler(ln) } + go s.upnpUpdateThread() + // Start the reaping processes - go s.ReapDeadPeers() + go s.ReapDeadPeerHandler() // Start the tx pool s.TxPool.Start() } +func (s *Ethereum) peerHandler(listener net.Listener) { + for { + conn, err := listener.Accept() + if err != nil { + log.Println(err) + + continue + } + + go s.AddPeer(conn) + } +} + func (s *Ethereum) Stop() { // Close the database defer s.db.Close() diff --git a/peer.go b/peer.go index 5d22b545c7..a715e205de 100644 --- a/peer.go +++ b/peer.go @@ -24,6 +24,8 @@ const ( CapDiscoveryTy = 0x01 CapTxTy = 0x02 CapChainTy = 0x04 + + CapDefault = CapChainTy | CapTxTy | CapDiscoveryTy ) var capsToString = map[Caps]string{ @@ -95,7 +97,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { } } -func NewOutboundPeer(addr string, ethereum *Ethereum) *Peer { +func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { p := &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), quit: make(chan bool), @@ -103,6 +105,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum) *Peer { inbound: false, connected: 0, disconnect: 0, + caps: caps, } // Set up the connection in another goroutine so we don't block the main thread @@ -165,7 +168,8 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { // Outbound message handler. Outbound messages are handled here func (p *Peer) HandleOutbound() { // The ping timer. Makes sure that every 2 minutes a ping is send to the peer - tickleTimer := time.NewTicker(2 * time.Minute) + pingTimer := time.NewTicker(2 * time.Minute) + serviceTimer := time.NewTicker(5 * time.Second) out: for { select { @@ -175,11 +179,20 @@ out: p.lastSend = time.Now() - case <-tickleTimer.C: + // Ping timer sends a ping to the peer each 2 minutes + case <-pingTimer.C: p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) - // Break out of the for loop if a quit message is posted + // Service timer takes care of peer broadcasting, transaction + // posting or block posting + case <-serviceTimer.C: + if p.caps&CapDiscoveryTy > 0 { + msg := p.peersMessage() + p.ethereum.BroadcastMsg(msg) + } + case <-p.quit: + // Break out of the for loop if a quit message is posted break out } } @@ -387,7 +400,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", CapChainTy | CapTxTy | CapDiscoveryTy, p.port, + uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", p.caps, p.port, }) p.QueueMessage(msg) @@ -395,18 +408,20 @@ func (p *Peer) pushHandshake() error { return nil } -// Pushes the list of outbound peers to the client when requested -func (p *Peer) pushPeers() { +func (p *Peer) peersMessage() *ethwire.Msg { outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) // Serialise each peer for i, peer := range p.ethereum.InOutPeers() { outPeers[i] = peer.RlpData() } - // Send message to the peer with the known list of connected clients - msg := ethwire.NewMessage(ethwire.MsgPeersTy, outPeers) + // Return the message to the peer with the known list of connected clients + return ethwire.NewMessage(ethwire.MsgPeersTy, outPeers) +} - p.QueueMessage(msg) +// Pushes the list of outbound peers to the client when requested +func (p *Peer) pushPeers() { + p.QueueMessage(p.peersMessage()) } func (p *Peer) handleHandshake(msg *ethwire.Msg) { From ae0d4eb7aa644b4c295d7a7cd28c38e92777a52f Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 16:29:13 +0100 Subject: [PATCH 0020/1237] removed upnp --- ethereum.go | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/ethereum.go b/ethereum.go index eab40e93dc..ae0f2eed0f 100644 --- a/ethereum.go +++ b/ethereum.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/ethwire-go" "log" "net" - "strconv" "sync" "sync/atomic" "time" @@ -45,8 +44,6 @@ type Ethereum struct { Addr net.Addr - nat NAT - peerMut sync.Mutex // Capabilities for outgoing peers @@ -62,12 +59,6 @@ func New(caps Caps) (*Ethereum, error) { ethutil.Config.Db = db - nat, err := Discover() - if err != nil { - log.Printf("Can't discover upnp: %v", err) - } - log.Println(nat) - nonce, _ := ethutil.RandomUint64() ethereum := &Ethereum{ shutdownChan: make(chan bool), @@ -75,7 +66,6 @@ func New(caps Caps) (*Ethereum, error) { peers: list.New(), Nonce: nonce, serverCaps: caps, - nat: nat, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -213,46 +203,6 @@ func (s *Ethereum) ReapDeadPeerHandler() { } } -// FIXME -func (s *Ethereum) upnpUpdateThread() { - // Go off immediately to prevent code duplication, thereafter we renew - // lease every 15 minutes. - timer := time.NewTimer(0 * time.Second) - lport, _ := strconv.ParseInt("30303", 10, 16) - first := true -out: - for { - select { - case <-timer.C: - listenPort, err := s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) - if err != nil { - log.Printf("can't add UPnP port mapping: %v\n", err) - } - if first && err == nil { - externalip, err := s.nat.GetExternalAddress() - if err != nil { - log.Printf("UPnP can't get external address: %v\n", err) - continue out - } - // externalip, listenport - log.Println("Successfully bound via UPnP to", externalip, listenPort) - first = false - } - timer.Reset(time.Minute * 15) - case <-s.shutdownChan: - break out - } - } - - timer.Stop() - - if err := s.nat.DeletePortMapping("tcp", int(lport), int(lport)); err != nil { - log.Printf("unable to remove UPnP port mapping: %v\n", err) - } else { - log.Printf("succesfully disestablished UPnP port mapping\n") - } -} - // Start the ethereum func (s *Ethereum) Start() { // Bind to addr and port @@ -267,8 +217,6 @@ func (s *Ethereum) Start() { go s.peerHandler(ln) } - go s.upnpUpdateThread() - // Start the reaping processes go s.ReapDeadPeerHandler() From 3f503ffc7f85287fc3716afb704f90a1a4e7b21b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 19:22:39 +0100 Subject: [PATCH 0021/1237] Implemented support for UPnP --- ethereum.go | 62 +++++++++++++++ nat.go | 12 +++ natpmp.go | 54 +++++++++++++ upnp.go => natupnp.go | 179 +++++++++++++----------------------------- 4 files changed, 182 insertions(+), 125 deletions(-) create mode 100644 nat.go create mode 100644 natpmp.go rename upnp.go => natupnp.go (56%) diff --git a/ethereum.go b/ethereum.go index ae0f2eed0f..83243e23c4 100644 --- a/ethereum.go +++ b/ethereum.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/ethwire-go" "log" "net" + "strconv" "sync" "sync/atomic" "time" @@ -29,6 +30,7 @@ const ( type Ethereum struct { // Channel for shutting down the ethereum shutdownChan chan bool + quit chan bool // DB interface //db *ethdb.LDBDatabase db *ethdb.MemDatabase @@ -48,6 +50,8 @@ type Ethereum struct { // Capabilities for outgoing peers serverCaps Caps + + nat NAT } func New(caps Caps) (*Ethereum, error) { @@ -57,15 +61,30 @@ func New(caps Caps) (*Ethereum, error) { return nil, err } + /* + gateway := net.ParseIP("192.168.192.1") + nat := NewNatPMP(gateway) + port, err := nat.AddPortMapping("tcp", 30303, 30303, "", 60) + log.Println(port, err) + */ + + nat, err := Discover() + if err != nil { + log.Println("UPnP failed", err) + return nil, err + } + ethutil.Config.Db = db nonce, _ := ethutil.RandomUint64() ethereum := &Ethereum{ shutdownChan: make(chan bool), + quit: make(chan bool), db: db, peers: list.New(), Nonce: nonce, serverCaps: caps, + nat: nat, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -217,6 +236,8 @@ func (s *Ethereum) Start() { go s.peerHandler(ln) } + go s.upnpUpdateThread() + // Start the reaping processes go s.ReapDeadPeerHandler() @@ -245,6 +266,8 @@ func (s *Ethereum) Stop() { p.Stop() }) + close(s.quit) + s.shutdownChan <- true s.TxPool.Stop() @@ -254,3 +277,42 @@ func (s *Ethereum) Stop() { func (s *Ethereum) WaitForShutdown() { <-s.shutdownChan } + +func (s *Ethereum) upnpUpdateThread() { + // Go off immediately to prevent code duplication, thereafter we renew + // lease every 15 minutes. + timer := time.NewTimer(0 * time.Second) + lport, _ := strconv.ParseInt("30303", 10, 16) + first := true +out: + for { + select { + case <-timer.C: + listenPort, err := s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) + if err != nil { + log.Println("can't add UPnP port mapping:", err) + break out + } + if first && err == nil { + externalip, err := s.nat.GetExternalAddress() + if err != nil { + log.Println("UPnP can't get external address:", err) + continue out + } + log.Println("Successfully bound via UPnP to", externalip, listenPort) + first = false + } + timer.Reset(time.Minute * 15) + case <-s.quit: + break out + } + } + + timer.Stop() + + if err := s.nat.DeletePortMapping("TCP", int(lport), int(lport)); err != nil { + log.Println("unable to remove UPnP port mapping:", err) + } else { + log.Println("succesfully disestablished UPnP port mapping") + } +} diff --git a/nat.go b/nat.go new file mode 100644 index 0000000000..999308eb26 --- /dev/null +++ b/nat.go @@ -0,0 +1,12 @@ +package eth + +import ( + "net" +) + +// protocol is either "udp" or "tcp" +type NAT interface { + GetExternalAddress() (addr net.IP, err error) + AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) + DeletePortMapping(protocol string, externalPort, internalPort int) (err error) +} diff --git a/natpmp.go b/natpmp.go new file mode 100644 index 0000000000..9a1fb652b1 --- /dev/null +++ b/natpmp.go @@ -0,0 +1,54 @@ +package eth + +import ( + natpmp "code.google.com/p/go-nat-pmp" + "fmt" + "net" +) + +// Adapt the NAT-PMP protocol to the NAT interface + +// TODO: +// + Register for changes to the external address. +// + Re-register port mapping when router reboots. +// + A mechanism for keeping a port mapping registered. + +type natPMPClient struct { + client *natpmp.Client +} + +func NewNatPMP(gateway net.IP) (nat NAT) { + return &natPMPClient{natpmp.NewClient(gateway)} +} + +func (n *natPMPClient) GetExternalAddress() (addr net.IP, err error) { + response, err := n.client.GetExternalAddress() + if err != nil { + return + } + ip := response.ExternalIPAddress + addr = net.IPv4(ip[0], ip[1], ip[2], ip[3]) + return +} + +func (n *natPMPClient) AddPortMapping(protocol string, externalPort, internalPort int, + description string, timeout int) (mappedExternalPort int, err error) { + if timeout <= 0 { + err = fmt.Errorf("timeout must not be <= 0") + return + } + // Note order of port arguments is switched between our AddPortMapping and the client's AddPortMapping. + response, err := n.client.AddPortMapping(protocol, internalPort, externalPort, timeout) + if err != nil { + return + } + mappedExternalPort = int(response.MappedExternalPort) + return +} + +func (n *natPMPClient) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) { + // To destroy a mapping, send an add-port with + // an internalPort of the internal port to destroy, an external port of zero and a time of zero. + _, err = n.client.AddPortMapping(protocol, internalPort, 0, 0) + return +} diff --git a/upnp.go b/natupnp.go similarity index 56% rename from upnp.go rename to natupnp.go index c84ed04f8d..e4072d0ddb 100644 --- a/upnp.go +++ b/natupnp.go @@ -1,34 +1,5 @@ package eth -// Upnp code taken from Taipei Torrent license is below: -// Copyright (c) 2010 Jack Palevich. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Just enough UPnP to be able to forward ports // @@ -44,27 +15,11 @@ import ( "time" ) -// NAT is an interface representing a NAT traversal options for example UPNP or -// NAT-PMP. It provides methods to query and manipulate this traversal to allow -// access to services. -type NAT interface { - // Get the external address from outside the NAT. - GetExternalAddress() (addr net.IP, err error) - // Add a port mapping for protocol ("udp" or "tcp") from externalport to - // internal port with description lasting for timeout. - AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) - // Remove a previously added port mapping from externalport to - // internal port. - DeletePortMapping(protocol string, externalPort, internalPort int) (err error) -} - type upnpNAT struct { serviceURL string ourIP string } -// Discover searches the local network for a UPnP router returning a NAT -// for the network if so, nil if not. func Discover() (nat NAT, err error) { ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900") if err != nil { @@ -77,7 +32,7 @@ func Discover() (nat NAT, err error) { socket := conn.(*net.UDPConn) defer socket.Close() - err = socket.SetDeadline(time.Now().Add(3 * time.Second)) + err = socket.SetDeadline(time.Now().Add(10 * time.Second)) if err != nil { return } @@ -134,7 +89,7 @@ func Discover() (nat NAT, err error) { nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP} return } - err = errors.New("UPnP port discovery failed") + err = errors.New("UPnP port discovery failed.") return } @@ -190,39 +145,38 @@ type root struct { Device device } -// getChildDevice searches the children of device for a device with the given -// type. func getChildDevice(d *device, deviceType string) *device { - for i := range d.DeviceList.Device { - if d.DeviceList.Device[i].DeviceType == deviceType { - return &d.DeviceList.Device[i] + dl := d.DeviceList.Device + for i := 0; i < len(dl); i++ { + if dl[i].DeviceType == deviceType { + return &dl[i] } } return nil } -// getChildDevice searches the service list of device for a service with the -// given type. func getChildService(d *device, serviceType string) *service { - for i := range d.ServiceList.Service { - if d.ServiceList.Service[i].ServiceType == serviceType { - return &d.ServiceList.Service[i] + sl := d.ServiceList.Service + for i := 0; i < len(sl); i++ { + if sl[i].ServiceType == serviceType { + return &sl[i] } } return nil } -// getOurIP returns a best guess at what the local IP is. func getOurIP() (ip string, err error) { hostname, err := os.Hostname() if err != nil { return } - return net.LookupCNAME(hostname) + p, err := net.LookupIP(hostname) + if err != nil && len(p) > 0 { + return + } + return p[0].String(), nil } -// getServiceURL parses the xml description at the given root url to find the -// url for the WANIPConnection service to be used for port forwarding. func getServiceURL(rootURL string) (url string, err error) { r, err := http.Get(rootURL) if err != nil { @@ -235,34 +189,34 @@ func getServiceURL(rootURL string) (url string, err error) { } var root root err = xml.NewDecoder(r.Body).Decode(&root) + if err != nil { return } a := &root.Device if a.DeviceType != "urn:schemas-upnp-org:device:InternetGatewayDevice:1" { - err = errors.New("no InternetGatewayDevice") + err = errors.New("No InternetGatewayDevice") return } b := getChildDevice(a, "urn:schemas-upnp-org:device:WANDevice:1") if b == nil { - err = errors.New("no WANDevice") + err = errors.New("No WANDevice") return } c := getChildDevice(b, "urn:schemas-upnp-org:device:WANConnectionDevice:1") if c == nil { - err = errors.New("no WANConnectionDevice") + err = errors.New("No WANConnectionDevice") return } d := getChildService(c, "urn:schemas-upnp-org:service:WANIPConnection:1") if d == nil { - err = errors.New("no WANIPConnection") + err = errors.New("No WANIPConnection") return } url = combineURL(rootURL, d.ControlURL) return } -// combineURL appends subURL onto rootURL. func combineURL(rootURL, subURL string) string { protocolEnd := "://" protoEndIndex := strings.Index(rootURL, protocolEnd) @@ -271,24 +225,7 @@ func combineURL(rootURL, subURL string) string { return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL } -// soapBody represents the element in a SOAP reply. -// fields we don't care about are elided. -type soapBody struct { - XMLName xml.Name `xml:"Body"` - Data []byte `xml:",innerxml"` -} - -// soapEnvelope represents the element in a SOAP reply. -// fields we don't care about are elided. -type soapEnvelope struct { - XMLName xml.Name `xml:"Envelope"` - Body soapBody `xml:"Body"` -} - -// soapRequests performs a soap request with the given parameters and returns -// the xml replied stripped of the soap headers. in the case that the request is -// unsuccessful the an error is returned. -func soapRequest(url, function, message string) (replyXML []byte, err error) { +func soapRequest(url, function, message string) (r *http.Response, err error) { fullMessage := "" + "\r\n" + "" + message + "" @@ -305,10 +242,10 @@ func soapRequest(url, function, message string) (replyXML []byte, err error) { req.Header.Set("Cache-Control", "no-cache") req.Header.Set("Pragma", "no-cache") - r, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } + // log.Stderr("soapRequest ", req) + //fmt.Println(fullMessage) + + r, err = http.DefaultClient.Do(req) if r.Body != nil { defer r.Body.Close() } @@ -319,45 +256,39 @@ func soapRequest(url, function, message string) (replyXML []byte, err error) { r = nil return } - var reply soapEnvelope - err = xml.NewDecoder(r.Body).Decode(&reply) + return +} + +type statusInfo struct { + externalIpAddress string +} + +func (n *upnpNAT) getStatusInfo() (info statusInfo, err error) { + + message := "\r\n" + + "" + + var response *http.Response + response, err = soapRequest(n.serviceURL, "GetStatusInfo", message) if err != nil { - return nil, err + return } - return reply.Body.Data, nil + + // TODO: Write a soap reply parser. It has to eat the Body and envelope tags... + + response.Body.Close() + return } -// getExternalIPAddressResponse represents the XML response to a -// GetExternalIPAddress SOAP request. -type getExternalIPAddressResponse struct { - XMLName xml.Name `xml:"GetExternalIPAddressResponse"` - ExternalIPAddress string `xml:"NewExternalIPAddress"` -} - -// GetExternalAddress implements the NAT interface by fetching the external IP -// from the UPnP router. func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) { - message := "\r\n" - response, err := soapRequest(n.serviceURL, "GetExternalIPAddress", message) + info, err := n.getStatusInfo() if err != nil { - return nil, err + return } - - var reply getExternalIPAddressResponse - err = xml.Unmarshal(response, &reply) - if err != nil { - return nil, err - } - - addr = net.ParseIP(reply.ExternalIPAddress) - if addr == nil { - return nil, errors.New("unable to parse ip address") - } - return addr, nil + addr = net.ParseIP(info.externalIpAddress) + return } -// AddPortMapping implements the NAT interface by setting up a port forwarding -// from the UPnP router to the local machine with the given ports and protocol. func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) { // A single concatenation would break ARM compilation. message := "\r\n" + @@ -370,22 +301,19 @@ func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int "" + strconv.Itoa(timeout) + "" - response, err := soapRequest(n.serviceURL, "AddPortMapping", message) + var response *http.Response + response, err = soapRequest(n.serviceURL, "AddPortMapping", message) if err != nil { return } // TODO: check response to see if the port was forwarded - // If the port was not wildcard we don't get an reply with the port in - // it. Not sure about wildcard yet. miniupnpc just checks for error - // codes here. + // log.Println(message, response) mappedExternalPort = externalPort _ = response return } -// AddPortMapping implements the NAT interface by removing up a port forwarding -// from the UPnP router to the local machine with the given ports and. func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) { message := "\r\n" + @@ -393,7 +321,8 @@ func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort "" + protocol + "" + "" - response, err := soapRequest(n.serviceURL, "DeletePortMapping", message) + var response *http.Response + response, err = soapRequest(n.serviceURL, "DeletePortMapping", message) if err != nil { return } From 48b41862ef89e3d694b71d452e7f67bfb34ca17f Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 19:44:47 +0100 Subject: [PATCH 0022/1237] UPnP Support --- ethereum.go | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/ethereum.go b/ethereum.go index 83243e23c4..b178644cf3 100644 --- a/ethereum.go +++ b/ethereum.go @@ -54,24 +54,19 @@ type Ethereum struct { nat NAT } -func New(caps Caps) (*Ethereum, error) { - //db, err := ethdb.NewLDBDatabase() +func New(caps Caps, usePnp bool) (*Ethereum, error) { db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } - /* - gateway := net.ParseIP("192.168.192.1") - nat := NewNatPMP(gateway) - port, err := nat.AddPortMapping("tcp", 30303, 30303, "", 60) - log.Println(port, err) - */ - - nat, err := Discover() - if err != nil { - log.Println("UPnP failed", err) - return nil, err + var nat NAT + if usePnp { + nat, err = Discover() + if err != nil { + log.Println("UPnP failed", err) + return nil, err + } } ethutil.Config.Db = db @@ -229,14 +224,15 @@ func (s *Ethereum) Start() { if err != nil { log.Println("Connection listening disabled. Acting as client") } else { - s.Addr = ln.Addr() // Starting accepting connections log.Println("Ready and accepting connections") // Start the peer handler go s.peerHandler(ln) } - go s.upnpUpdateThread() + if s.nat != nil { + go s.upnpUpdateThread() + } // Start the reaping processes go s.ReapDeadPeerHandler() @@ -288,18 +284,18 @@ out: for { select { case <-timer.C: - listenPort, err := s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) + var err error + _, err = s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) if err != nil { log.Println("can't add UPnP port mapping:", err) break out } if first && err == nil { - externalip, err := s.nat.GetExternalAddress() + _, err = s.nat.GetExternalAddress() if err != nil { log.Println("UPnP can't get external address:", err) continue out } - log.Println("Successfully bound via UPnP to", externalip, listenPort) first = false } timer.Reset(time.Minute * 15) From f4a96ca588a4c7e1382e9c2265ca306a5b0d0adf Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 19:46:37 +0100 Subject: [PATCH 0023/1237] Removed the seed peer option from start --- ethereum.go | 2 +- peer.go | 17 ++--------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/ethereum.go b/ethereum.go index b178644cf3..fa7ce9ec78 100644 --- a/ethereum.go +++ b/ethereum.go @@ -96,7 +96,7 @@ func (s *Ethereum) AddPeer(conn net.Conn) { if peer != nil { s.peers.PushBack(peer) - peer.Start(false) + peer.Start() } } diff --git a/peer.go b/peer.go index a715e205de..e9a8f6c035 100644 --- a/peer.go +++ b/peer.go @@ -76,9 +76,6 @@ type Peer struct { // this to prevent receiving false peers. requestedPeerList bool - // Determines whether this is a seed peer - seed bool - host []byte port uint16 caps Caps @@ -123,7 +120,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { atomic.StoreInt32(&p.connected, 1) atomic.StoreInt32(&p.disconnect, 0) - p.Start(false) + p.Start() }() return p @@ -155,14 +152,6 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { p.Stop() return } - - // XXX TMP CODE FOR TESTNET - switch msg.Type { - case ethwire.MsgPeersTy: - if p.seed { - p.Stop() - } - } } // Outbound message handler. Outbound messages are handled here @@ -349,9 +338,7 @@ func unpackAddr(value *ethutil.RlpValue, p uint64) string { return net.JoinHostPort(host, port) } -func (p *Peer) Start(seed bool) { - p.seed = seed - +func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) if peerHost == servHost { From aa9341570b8e63c907c0f9d917508610c7daa1ae Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 20:00:09 +0100 Subject: [PATCH 0024/1237] Disconnection reasons --- peer.go | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/peer.go b/peer.go index e9a8f6c035..0f6afebfe8 100644 --- a/peer.go +++ b/peer.go @@ -17,27 +17,53 @@ const ( outputBufferSize = 50 ) -// Peer capabillities +type DiscReason byte + +const ( + DiscReRequested = 0x00 + DiscReTcpSysErr = 0x01 + DiscBadProto = 0x02 + DiscBadPeer = 0x03 + DiscTooManyPeers = 0x04 +) + +var discReasonToString = []string{ + "Disconnect requested", + "Disconnect TCP sys error", + "Disconnect Bad protocol", + "Disconnect Useless peer", + "Disconnect Too many peers", +} + +func (d DiscReason) String() string { + if len(discReasonToString) > int(d) { + return "Unknown" + } + + return discReasonToString[d] +} + +// Peer capabilities type Caps byte const ( - CapDiscoveryTy = 0x01 - CapTxTy = 0x02 - CapChainTy = 0x04 + CapPeerDiscTy = 0x01 + CapTxTy = 0x02 + CapChainTy = 0x04 - CapDefault = CapChainTy | CapTxTy | CapDiscoveryTy + CapDefault = CapChainTy | CapTxTy | CapPeerDiscTy ) var capsToString = map[Caps]string{ - CapDiscoveryTy: "Peer discovery", - CapTxTy: "Transaction relaying", - CapChainTy: "Block chain relaying", + CapPeerDiscTy: "Peer discovery", + CapTxTy: "Transaction relaying", + CapChainTy: "Block chain relaying", } func (c Caps) String() string { var caps []string - if c&CapDiscoveryTy > 0 { - caps = append(caps, capsToString[CapDiscoveryTy]) + if c&CapPeerDiscTy > 0 { + caps = append(caps, capsToString[CapPeerDiscTy]) } if c&CapChainTy > 0 { caps = append(caps, capsToString[CapChainTy]) @@ -175,7 +201,7 @@ out: // Service timer takes care of peer broadcasting, transaction // posting or block posting case <-serviceTimer.C: - if p.caps&CapDiscoveryTy > 0 { + if p.caps&CapPeerDiscTy > 0 { msg := p.peersMessage() p.ethereum.BroadcastMsg(msg) } @@ -220,6 +246,7 @@ out: p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) case ethwire.MsgDiscTy: p.Stop() + log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).AsUint())) case ethwire.MsgPingTy: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) @@ -381,8 +408,6 @@ func (p *Peer) Stop() { p.writeMessage(ethwire.NewMessage(ethwire.MsgDiscTy, "")) p.conn.Close() } - - log.Println("Peer shutdown") } func (p *Peer) pushHandshake() error { From 04b6e413d99c9d8c2fa4c06fa3e7822700209bc6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 20:06:37 +0100 Subject: [PATCH 0025/1237] Encode caps as byte --- peer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 0f6afebfe8..80cca50c05 100644 --- a/peer.go +++ b/peer.go @@ -184,7 +184,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { func (p *Peer) HandleOutbound() { // The ping timer. Makes sure that every 2 minutes a ping is send to the peer pingTimer := time.NewTicker(2 * time.Minute) - serviceTimer := time.NewTicker(5 * time.Second) + serviceTimer := time.NewTicker(5 * time.Minute) out: for { select { @@ -412,7 +412,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", p.caps, p.port, + uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, }) p.QueueMessage(msg) From a9a564c226bae04bc1939baf44884e7cd69ee924 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Feb 2014 20:54:13 +0100 Subject: [PATCH 0026/1237] removed self connect log --- peer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/peer.go b/peer.go index 80cca50c05..c67e407d15 100644 --- a/peer.go +++ b/peer.go @@ -369,8 +369,6 @@ func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) if peerHost == servHost { - log.Println("Connected to self") - p.Stop() return From 6292c5ad5a649c9c9c3dbe403c46fff960604f09 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Feb 2014 01:10:10 +0100 Subject: [PATCH 0027/1237] Transaction processing --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index c67e407d15..b4225998ed 100644 --- a/peer.go +++ b/peer.go @@ -271,7 +271,7 @@ out: // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Length(); i++ { - p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromRlpValue(msg.Data.Get(i))) + p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(ethutil.Encode(msg.Data.Get(i).AsRaw()))) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to From f995f5763bf58bc2455058fe40bd15a6aa46a65f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Feb 2014 01:12:44 +0100 Subject: [PATCH 0028/1237] Properly encode tx --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index b4225998ed..dc2427b323 100644 --- a/peer.go +++ b/peer.go @@ -271,7 +271,7 @@ out: // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Length(); i++ { - p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(ethutil.Encode(msg.Data.Get(i).AsRaw()))) + p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to From 9e9b7a520e33b0ddef66f9e5cd113ca75cc8dd4d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Feb 2014 17:26:37 +0100 Subject: [PATCH 0029/1237] Do not quit if upnp fails --- ethereum.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index fa7ce9ec78..2500892f0b 100644 --- a/ethereum.go +++ b/ethereum.go @@ -65,7 +65,6 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { nat, err = Discover() if err != nil { log.Println("UPnP failed", err) - return nil, err } } From 04c00f40f0c31e2c927d3a67e3e115a5cb5b539d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Feb 2014 13:27:57 +0100 Subject: [PATCH 0030/1237] Fixed value --- peer.go | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/peer.go b/peer.go index dc2427b323..940d0eefee 100644 --- a/peer.go +++ b/peer.go @@ -60,15 +60,19 @@ var capsToString = map[Caps]string{ CapChainTy: "Block chain relaying", } +func (c Caps) IsCap(cap Caps) bool { + return c&cap > 0 +} + func (c Caps) String() string { var caps []string - if c&CapPeerDiscTy > 0 { + if c.IsCap(CapPeerDiscTy) { caps = append(caps, capsToString[CapPeerDiscTy]) } - if c&CapChainTy > 0 { + if c.IsCap(CapChainTy) { caps = append(caps, capsToString[CapChainTy]) } - if c&CapTxTy > 0 { + if c.IsCap(CapTxTy) { caps = append(caps, capsToString[CapTxTy]) } @@ -243,7 +247,9 @@ out: // Version message p.handleHandshake(msg) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) + if p.caps.IsCap(CapPeerDiscTy) { + p.QueueMessage(ethwire.NewMessage(ethwire.MsgGetPeersTy, "")) + } case ethwire.MsgDiscTy: p.Stop() log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).AsUint())) @@ -259,7 +265,8 @@ out: // Get all blocks and process them msg.Data = msg.Data for i := msg.Data.Length() - 1; i >= 0; i-- { - block := ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) + // FIXME + block := ethchain.NewBlockFromRlpValue(ethutil.NewValue(msg.Data.Get(i).AsRaw())) err := p.ethereum.BlockManager.ProcessBlock(block) if err != nil { @@ -302,7 +309,7 @@ out: // Length minus one since the very last element in the array is a count l := msg.Data.Length() - 1 // Ignore empty get chains - if l <= 1 { + if l == 0 { break } @@ -369,9 +376,9 @@ func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) if peerHost == servHost { - p.Stop() + //p.Stop() - return + //return } if p.inbound { @@ -462,21 +469,5 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } func (p *Peer) RlpData() []interface{} { - return []interface{}{p.host, p.port /*port*/} -} - -func (p *Peer) RlpEncode() []byte { - host, prt, err := net.SplitHostPort(p.conn.RemoteAddr().String()) - if err != nil { - return nil - } - - i, err := strconv.Atoi(prt) - if err != nil { - return nil - } - - port := ethutil.NumberToBytes(uint16(i), 16) - - return ethutil.Encode([]interface{}{host, port}) + return []interface{}{p.host, p.port} } From 1f7b13ff4ec7e8cb0e81648fd37db5d867715915 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 8 Feb 2014 21:02:09 +0100 Subject: [PATCH 0031/1237] Switched over to leveldb instead of memdb --- ethereum.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ethereum.go b/ethereum.go index 2500892f0b..cc3f1695b3 100644 --- a/ethereum.go +++ b/ethereum.go @@ -33,7 +33,7 @@ type Ethereum struct { quit chan bool // DB interface //db *ethdb.LDBDatabase - db *ethdb.MemDatabase + db ethutil.Database // Block manager for processing new blocks and managing the block chain BlockManager *ethchain.BlockManager // The transaction pool. Transaction can be pushed on this pool @@ -52,10 +52,14 @@ type Ethereum struct { serverCaps Caps nat NAT + + // Specifies the desired amount of maximum peers + MaxPeers int } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewMemDatabase() + db, err := ethdb.NewLDBDatabase() + //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } @@ -79,6 +83,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { Nonce: nonce, serverCaps: caps, nat: nat, + MaxPeers: 5, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -93,7 +98,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) - if peer != nil { + if peer != nil && s.peers.Len() < s.MaxPeers { s.peers.PushBack(peer) peer.Start() } @@ -263,9 +268,10 @@ func (s *Ethereum) Stop() { close(s.quit) - s.shutdownChan <- true - s.TxPool.Stop() + s.BlockManager.Stop() + + s.shutdownChan <- true } // This function will wait for a shutdown and resumes main thread execution From 24349bc431d6ac69520b325650b1128c9125faf0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 8 Feb 2014 21:02:42 +0100 Subject: [PATCH 0032/1237] Changed peer format --- peer.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/peer.go b/peer.go index 940d0eefee..9b57e9bbbe 100644 --- a/peer.go +++ b/peer.go @@ -106,7 +106,7 @@ type Peer struct { // this to prevent receiving false peers. requestedPeerList bool - host []byte + host []interface{} port uint16 caps Caps } @@ -314,7 +314,8 @@ out: } // Amount of parents in the canonical chain - amountOfBlocks := msg.Data.Get(l).AsUint() + //amountOfBlocks := msg.Data.Get(l).AsUint() + amountOfBlocks := uint64(100) // Check each SHA block hash from the message and determine whether // the SHA is in the database for i := 0; i < l; i++ { @@ -326,8 +327,10 @@ out: // If a parent is found send back a reply if parent != nil { + log.Printf("HASH %x (len %d) Amount = %d)\n", parent.Hash(), l, amountOfBlocks) chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, append(chain, amountOfBlocks))) + //log.Printf("%q\n", chain) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain @@ -349,13 +352,13 @@ out: p.Stop() } -func packAddr(address, port string) ([]byte, uint16) { +func packAddr(address, port string) ([]interface{}, uint16) { addr := strings.Split(address, ".") a, _ := strconv.Atoi(addr[0]) b, _ := strconv.Atoi(addr[1]) c, _ := strconv.Atoi(addr[2]) d, _ := strconv.Atoi(addr[3]) - host := []byte{byte(a), byte(b), byte(c), byte(d)} + host := []interface{}{byte(a), byte(b), byte(c), byte(d)} prt, _ := strconv.Atoi(port) return host, uint16(prt) @@ -417,7 +420,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(0), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, + uint32(1), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, }) p.QueueMessage(msg) From 0de31a389803d05fb7eef776cbba922f019b6d9d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 9 Feb 2014 23:34:33 +0100 Subject: [PATCH 0033/1237] Fixed self connect through public key discovery. Bumped protocol version number --- ethereum.go | 4 ++-- peer.go | 48 +++++++++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/ethereum.go b/ethereum.go index cc3f1695b3..5658003614 100644 --- a/ethereum.go +++ b/ethereum.go @@ -58,8 +58,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase() - //db, err := ethdb.NewMemDatabase() + //db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } diff --git a/peer.go b/peer.go index 9b57e9bbbe..6257e32a4c 100644 --- a/peer.go +++ b/peer.go @@ -1,6 +1,7 @@ package eth import ( + "bytes" "github.com/ethereum/ethchain-go" "github.com/ethereum/ethutil-go" "github.com/ethereum/ethwire-go" @@ -109,6 +110,8 @@ type Peer struct { host []interface{} port uint16 caps Caps + + pubkey []byte } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -125,6 +128,8 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { } func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { + pubkey, _ := ethutil.Config.Db.Get([]byte("Pubkey")) + p := &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), quit: make(chan bool), @@ -133,6 +138,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, + pubkey: pubkey, } // Set up the connection in another goroutine so we don't block the main thread @@ -235,13 +241,12 @@ out: for atomic.LoadInt32(&p.disconnect) == 0 { // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) + if err != nil { + log.Println(err) + + break out + } for _, msg := range msgs { - if err != nil { - log.Println(err) - - break out - } - switch msg.Type { case ethwire.MsgHandshakeTy: // Version message @@ -327,9 +332,7 @@ out: // If a parent is found send back a reply if parent != nil { - log.Printf("HASH %x (len %d) Amount = %d)\n", parent.Hash(), l, amountOfBlocks) chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) - //log.Printf("%q\n", chain) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { // If no blocks are found we send back a reply with msg not in chain @@ -378,10 +381,13 @@ func unpackAddr(value *ethutil.RlpValue, p uint64) string { func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) - if peerHost == servHost { - //p.Stop() - //return + pubkey, _ := ethutil.Config.Db.Get([]byte("Pubkey")) + if bytes.Compare(pubkey, p.pubkey) == 0 { + log.Println("self connect") + p.Stop() + + return } if p.inbound { @@ -420,7 +426,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(1), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, + uint32(2), uint32(0), "/Ethereum(G) v0.0.1/", p.pubkey, byte(p.caps), p.port, }) p.QueueMessage(msg) @@ -446,15 +452,21 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data + + if c.Get(0).AsUint() != 2 { + log.Println("Invalid peer version. Require protocol v 2") + p.Stop() + return + } + // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID] p.versionKnown = true var istr string // If this is an inbound connection send an ack back if p.inbound { - if port := c.Get(4).AsUint(); port != 0 { - p.port = uint16(port) - } + p.pubkey = c.Get(3).AsBytes() + p.port = uint16(c.Get(5).AsUint()) istr = "inbound" } else { @@ -464,13 +476,11 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { istr = "outbound" } - if caps := Caps(c.Get(3).AsByte()); caps != 0 { - p.caps = caps - } + p.caps = Caps(c.Get(4).AsByte()) log.Printf("peer connect (%s) %v %s [%s]\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString(), p.caps) } func (p *Peer) RlpData() []interface{} { - return []interface{}{p.host, p.port} + return []interface{}{p.host, p.port, p.pubkey} } From c00b1dd508bb6ddcc25a70d6a9a3d40df0867ccb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 9 Feb 2014 23:58:59 +0100 Subject: [PATCH 0034/1237] Self connect on handshake --- peer.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/peer.go b/peer.go index 6257e32a4c..c5e0f9ac96 100644 --- a/peer.go +++ b/peer.go @@ -128,7 +128,8 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { } func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { - pubkey, _ := ethutil.Config.Db.Get([]byte("Pubkey")) + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() p := &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), @@ -382,14 +383,6 @@ func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) - pubkey, _ := ethutil.Config.Db.Get([]byte("Pubkey")) - if bytes.Compare(pubkey, p.pubkey) == 0 { - log.Println("self connect") - p.Stop() - - return - } - if p.inbound { p.host, p.port = packAddr(peerHost, peerPort) } else { @@ -468,6 +461,14 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.pubkey = c.Get(3).AsBytes() p.port = uint16(c.Get(5).AsUint()) + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + if bytes.Compare(pubkey, p.pubkey) == 0 { + p.Stop() + + return + } + istr = "inbound" } else { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) From 3c4fb01da36b0b0c0557bdc0a2b185ab8dcbbb4f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 01:09:12 +0100 Subject: [PATCH 0035/1237] Version 3 and added added catch up --- peer.go | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/peer.go b/peer.go index c5e0f9ac96..8d5a96d25f 100644 --- a/peer.go +++ b/peer.go @@ -112,6 +112,9 @@ type Peer struct { caps Caps pubkey []byte + + // Indicated whether the node is catching up or not + catchingUp bool } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -240,6 +243,9 @@ func (p *Peer) HandleInbound() { out: for atomic.LoadInt32(&p.disconnect) == 0 { + // HMM? + time.Sleep(500 * time.Millisecond) + // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { @@ -277,6 +283,11 @@ out: if err != nil { log.Println(err) + } else { + if p.catchingUp && msg.Data.Length() > 1 { + p.catchingUp = false + p.CatchupWithPeer() + } } } case ethwire.MsgTxTy: @@ -419,7 +430,7 @@ func (p *Peer) Stop() { func (p *Peer) pushHandshake() error { msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(2), uint32(0), "/Ethereum(G) v0.0.1/", p.pubkey, byte(p.caps), p.port, + uint32(3), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, p.pubkey, }) p.QueueMessage(msg) @@ -452,15 +463,16 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { return } - // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID] + // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPS, PORT, PUBKEY] p.versionKnown = true var istr string // If this is an inbound connection send an ack back if p.inbound { - p.pubkey = c.Get(3).AsBytes() - p.port = uint16(c.Get(5).AsUint()) + p.pubkey = c.Get(5).AsBytes() + p.port = uint16(c.Get(4).AsUint()) + // Self connect detection data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() if bytes.Compare(pubkey, p.pubkey) == 0 { @@ -471,17 +483,26 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { istr = "inbound" } else { - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(100)}) - p.QueueMessage(msg) + p.CatchupWithPeer() istr = "outbound" } - p.caps = Caps(c.Get(4).AsByte()) + p.caps = Caps(c.Get(3).AsByte()) log.Printf("peer connect (%s) %v %s [%s]\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString(), p.caps) } +func (p *Peer) CatchupWithPeer() { + if !p.catchingUp { + p.catchingUp = true + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)}) + p.QueueMessage(msg) + + log.Printf("Requesting blockchain up from %x\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()) + } +} + func (p *Peer) RlpData() []interface{} { return []interface{}{p.host, p.port, p.pubkey} } From 156495732ba2864feaf6725e770c07bd1c23a660 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 01:10:02 +0100 Subject: [PATCH 0036/1237] level db back in --- ethereum.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index 5658003614..cc3f1695b3 100644 --- a/ethereum.go +++ b/ethereum.go @@ -58,8 +58,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - //db, err := ethdb.NewLDBDatabase() - db, err := ethdb.NewMemDatabase() + db, err := ethdb.NewLDBDatabase() + //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } From a50b4f6b11d9299366a8026588cddae65fdbd085 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 01:15:14 +0100 Subject: [PATCH 0037/1237] Forgot to bump the version --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 8d5a96d25f..9848095cab 100644 --- a/peer.go +++ b/peer.go @@ -457,7 +457,7 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - if c.Get(0).AsUint() != 2 { + if c.Get(0).AsUint() != 3 { log.Println("Invalid peer version. Require protocol v 2") p.Stop() return From 8db7d791f0cee0fdcf574a9bcf34467dc00e313e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 11:20:42 +0100 Subject: [PATCH 0038/1237] Corrected version number in error log --- peer.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/peer.go b/peer.go index 9848095cab..6c2d6c8b5a 100644 --- a/peer.go +++ b/peer.go @@ -283,13 +283,14 @@ out: if err != nil { log.Println(err) - } else { - if p.catchingUp && msg.Data.Length() > 1 { - p.catchingUp = false - p.CatchupWithPeer() - } } } + + // If we're catching up, try to catch up further. + if p.catchingUp && msg.Data.Length() > 1 { + p.catchingUp = false + p.CatchupWithPeer() + } case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and @@ -458,7 +459,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data if c.Get(0).AsUint() != 3 { - log.Println("Invalid peer version. Require protocol v 2") + log.Println("Invalid peer version. Require protocol v3") p.Stop() return } From d2edc2bbf4641f3ca2ccf33e9014892d342ad021 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 11:36:49 +0100 Subject: [PATCH 0039/1237] Added some loggers --- peer.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/peer.go b/peer.go index 6c2d6c8b5a..e7be3bcb0f 100644 --- a/peer.go +++ b/peer.go @@ -26,14 +26,20 @@ const ( DiscBadProto = 0x02 DiscBadPeer = 0x03 DiscTooManyPeers = 0x04 + DiscConnDup = 0x05 + DiscGenesisErr = 0x06 + DiscProtoErr = 0x07 ) var discReasonToString = []string{ "Disconnect requested", "Disconnect TCP sys error", - "Disconnect Bad protocol", - "Disconnect Useless peer", - "Disconnect Too many peers", + "Disconnect bad protocol", + "Disconnect useless peer", + "Disconnect too many peers", + "Disconnect already connected", + "Disconnect wrong genesis block", + "Disconnect incompatible network", } func (d DiscReason) String() string { @@ -241,7 +247,6 @@ clean: // Inbound handler. Inbound messages are received here and passed to the appropriate methods func (p *Peer) HandleInbound() { -out: for atomic.LoadInt32(&p.disconnect) == 0 { // HMM? time.Sleep(500 * time.Millisecond) @@ -250,8 +255,6 @@ out: msgs, err := ethwire.ReadMessages(p.conn) if err != nil { log.Println(err) - - break out } for _, msg := range msgs { switch msg.Type { @@ -276,9 +279,10 @@ out: case ethwire.MsgBlockTy: // Get all blocks and process them msg.Data = msg.Data + var block *ethchain.Block for i := msg.Data.Length() - 1; i >= 0; i-- { // FIXME - block := ethchain.NewBlockFromRlpValue(ethutil.NewValue(msg.Data.Get(i).AsRaw())) + block = ethchain.NewBlockFromRlpValue(ethutil.NewValue(msg.Data.Get(i).AsRaw())) err := p.ethereum.BlockManager.ProcessBlock(block) if err != nil { @@ -288,6 +292,10 @@ out: // If we're catching up, try to catch up further. if p.catchingUp && msg.Data.Length() > 1 { + if ethutil.Config.Debug { + blockInfo := p.ethereum.BlockManager.BlockChain().BlockInfo(block) + log.Printf("Synced to block height #%d\n", blockInfo.Number) + } p.catchingUp = false p.CatchupWithPeer() } @@ -500,7 +508,7 @@ func (p *Peer) CatchupWithPeer() { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)}) p.QueueMessage(msg) - log.Printf("Requesting blockchain up from %x\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()) + log.Printf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) } } From 1d26ae2deaeb9e8995e923018db432eb64b764c5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 11:45:08 +0100 Subject: [PATCH 0040/1237] Changed client id --- peer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index e7be3bcb0f..04dd24e93d 100644 --- a/peer.go +++ b/peer.go @@ -2,11 +2,13 @@ package eth import ( "bytes" + "fmt" "github.com/ethereum/ethchain-go" "github.com/ethereum/ethutil-go" "github.com/ethereum/ethwire-go" "log" "net" + "runtime" "strconv" "strings" "sync/atomic" @@ -438,8 +440,9 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { + clientId := fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS) msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(3), uint32(0), "/Ethereum(G) v0.0.1/", byte(p.caps), p.port, p.pubkey, + uint32(3), uint32(0), clientId, byte(p.caps), p.port, p.pubkey, }) p.QueueMessage(msg) From 8ab6c53231deb92db1fe46bab263b1e2b12a8fb5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 13:59:05 +0100 Subject: [PATCH 0041/1237] Reversed back --- ethereum.go | 4 ++-- peer.go | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ethereum.go b/ethereum.go index cc3f1695b3..5658003614 100644 --- a/ethereum.go +++ b/ethereum.go @@ -58,8 +58,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase() - //db, err := ethdb.NewMemDatabase() + //db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } diff --git a/peer.go b/peer.go index 04dd24e93d..c592f275f2 100644 --- a/peer.go +++ b/peer.go @@ -1,7 +1,7 @@ package eth import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/ethchain-go" "github.com/ethereum/ethutil-go" @@ -139,8 +139,6 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { } func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() p := &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), @@ -150,7 +148,6 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, - pubkey: pubkey, } // Set up the connection in another goroutine so we don't block the main thread @@ -283,7 +280,6 @@ func (p *Peer) HandleInbound() { msg.Data = msg.Data var block *ethchain.Block for i := msg.Data.Length() - 1; i >= 0; i-- { - // FIXME block = ethchain.NewBlockFromRlpValue(ethutil.NewValue(msg.Data.Get(i).AsRaw())) err := p.ethereum.BlockManager.ProcessBlock(block) @@ -440,9 +436,12 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + clientId := fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS) msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(3), uint32(0), clientId, byte(p.caps), p.port, p.pubkey, + uint32(3), uint32(0), clientId, byte(p.caps), p.port, pubkey, }) p.QueueMessage(msg) @@ -485,13 +484,15 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.port = uint16(c.Get(4).AsUint()) // Self connect detection - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() - if bytes.Compare(pubkey, p.pubkey) == 0 { - p.Stop() + /* + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + if bytes.Compare(pubkey, p.pubkey) == 0 { + p.Stop() - return - } + return + } + */ istr = "inbound" } else { From 0ae6a3882523c7134a68f64e90fd8cc70f3c0807 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 16:04:57 +0100 Subject: [PATCH 0042/1237] Database --- ethereum.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index 5658003614..cc3f1695b3 100644 --- a/ethereum.go +++ b/ethereum.go @@ -58,8 +58,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - //db, err := ethdb.NewLDBDatabase() - db, err := ethdb.NewMemDatabase() + db, err := ethdb.NewLDBDatabase() + //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } From 42123b439683725b71bbec8ee9ec7443a1af1214 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 16:41:36 +0100 Subject: [PATCH 0043/1237] Fixed peer handling --- peer.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/peer.go b/peer.go index c592f275f2..6ec3c7ee76 100644 --- a/peer.go +++ b/peer.go @@ -319,7 +319,8 @@ func (p *Peer) HandleInbound() { peers := make([]string, data.Length()) // Parse each possible peer for i := 0; i < data.Length(); i++ { - peers[i] = unpackAddr(data.Get(i).Get(0), data.Get(i).Get(1).AsUint()) + value := ethutil.NewValue(data.Get(i).AsRaw()) + peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint()) } // Connect to the list of peers @@ -380,17 +381,17 @@ func packAddr(address, port string) ([]interface{}, uint16) { b, _ := strconv.Atoi(addr[1]) c, _ := strconv.Atoi(addr[2]) d, _ := strconv.Atoi(addr[3]) - host := []interface{}{byte(a), byte(b), byte(c), byte(d)} + host := []interface{}{int32(a), int32(b), int32(c), int32(d)} prt, _ := strconv.Atoi(port) return host, uint16(prt) } -func unpackAddr(value *ethutil.RlpValue, p uint64) string { - a := strconv.Itoa(int(value.Get(0).AsUint())) - b := strconv.Itoa(int(value.Get(1).AsUint())) - c := strconv.Itoa(int(value.Get(2).AsUint())) - d := strconv.Itoa(int(value.Get(3).AsUint())) +func unpackAddr(value *ethutil.Value, p uint64) string { + a := strconv.Itoa(int(value.Get(0).Uint())) + b := strconv.Itoa(int(value.Get(1).Uint())) + c := strconv.Itoa(int(value.Get(2).Uint())) + d := strconv.Itoa(int(value.Get(3).Uint())) host := strings.Join([]string{a, b, c, d}, ".") port := strconv.Itoa(int(p)) From 5a83114efd96bb8debeb3a3fccc3e054069e5400 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Feb 2014 20:59:31 +0100 Subject: [PATCH 0044/1237] Seed bootstrapping added --- ethereum.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethereum.go b/ethereum.go index cc3f1695b3..cac442dfc2 100644 --- a/ethereum.go +++ b/ethereum.go @@ -6,8 +6,10 @@ import ( "github.com/ethereum/ethdb-go" "github.com/ethereum/ethutil-go" "github.com/ethereum/ethwire-go" + "io/ioutil" "log" "net" + "net/http" "strconv" "sync" "sync/atomic" @@ -243,6 +245,20 @@ func (s *Ethereum) Start() { // Start the tx pool s.TxPool.Start() + + resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } + + s.ConnectToPeer(string(body)) } func (s *Ethereum) peerHandler(listener net.Listener) { From 02acef23d595dc2bc95295bab63658addf664aaf Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 11 Feb 2014 18:46:28 +0100 Subject: [PATCH 0045/1237] Interop! --- ethereum.go | 31 +++++++++++++++++-------------- peer.go | 7 ++++--- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ethereum.go b/ethereum.go index cac442dfc2..6ace583081 100644 --- a/ethereum.go +++ b/ethereum.go @@ -60,8 +60,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase() - //db, err := ethdb.NewMemDatabase() + //db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } @@ -246,19 +246,22 @@ func (s *Ethereum) Start() { // Start the tx pool s.TxPool.Start() - resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } + if ethutil.Config.Seed { + // Testnet seed bootstrapping + resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } - s.ConnectToPeer(string(body)) + s.ConnectToPeer(string(body)) + } } func (s *Ethereum) peerHandler(listener net.Listener) { diff --git a/peer.go b/peer.go index 6ec3c7ee76..5bfec1758a 100644 --- a/peer.go +++ b/peer.go @@ -204,6 +204,7 @@ func (p *Peer) HandleOutbound() { // The ping timer. Makes sure that every 2 minutes a ping is send to the peer pingTimer := time.NewTicker(2 * time.Minute) serviceTimer := time.NewTicker(5 * time.Minute) + out: for { select { @@ -442,7 +443,7 @@ func (p *Peer) pushHandshake() error { clientId := fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS) msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(3), uint32(0), clientId, byte(p.caps), p.port, pubkey, + uint32(4), uint32(0), clientId, byte(p.caps), p.port, pubkey, }) p.QueueMessage(msg) @@ -469,8 +470,8 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - if c.Get(0).AsUint() != 3 { - log.Println("Invalid peer version. Require protocol v3") + if c.Get(0).AsUint() != 4 { + log.Println("Invalid peer version. Require protocol v4") p.Stop() return } From 67de76c217f4ff4f2111e5f578b35fb162d64916 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 11 Feb 2014 20:09:58 +0100 Subject: [PATCH 0046/1237] Put leveldb --- ethereum.go | 4 ++-- peer.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index 6ace583081..c9da24bcff 100644 --- a/ethereum.go +++ b/ethereum.go @@ -60,8 +60,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - //db, err := ethdb.NewLDBDatabase() - db, err := ethdb.NewMemDatabase() + db, err := ethdb.NewLDBDatabase() + //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } diff --git a/peer.go b/peer.go index 5bfec1758a..3c36dfc585 100644 --- a/peer.go +++ b/peer.go @@ -496,6 +496,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } */ + p.CatchupWithPeer() + istr = "inbound" } else { p.CatchupWithPeer() From c2fb9f06ad018d01ce335c82b3542de16045a32d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 13 Feb 2014 15:12:16 +0100 Subject: [PATCH 0047/1237] Refactoring RlpValue => Value --- ethereum.go | 1 + peer.go | 127 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/ethereum.go b/ethereum.go index c9da24bcff..e1bc385421 100644 --- a/ethereum.go +++ b/ethereum.go @@ -247,6 +247,7 @@ func (s *Ethereum) Start() { s.TxPool.Start() if ethutil.Config.Seed { + log.Println("Seeding") // Testnet seed bootstrapping resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") if err != nil { diff --git a/peer.go b/peer.go index 3c36dfc585..cdb3bfcf59 100644 --- a/peer.go +++ b/peer.go @@ -1,7 +1,7 @@ package eth import ( - _ "bytes" + "bytes" "fmt" "github.com/ethereum/ethchain-go" "github.com/ethereum/ethutil-go" @@ -123,9 +123,14 @@ type Peer struct { // Indicated whether the node is catching up or not catchingUp bool + + Version string } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + return &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), quit: make(chan bool), @@ -135,6 +140,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { disconnect: 0, connected: 1, port: 30303, + pubkey: pubkey, } } @@ -148,6 +154,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, + Version: fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS), } // Set up the connection in another goroutine so we don't block the main thread @@ -267,7 +274,7 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgDiscTy: p.Stop() - log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).AsUint())) + log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) case ethwire.MsgPingTy: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) @@ -279,30 +286,47 @@ func (p *Peer) HandleInbound() { case ethwire.MsgBlockTy: // Get all blocks and process them msg.Data = msg.Data - var block *ethchain.Block - for i := msg.Data.Length() - 1; i >= 0; i-- { - block = ethchain.NewBlockFromRlpValue(ethutil.NewValue(msg.Data.Get(i).AsRaw())) - err := p.ethereum.BlockManager.ProcessBlock(block) + var block, lastBlock *ethchain.Block + var err error + for i := msg.Data.Len() - 1; i >= 0; i-- { + block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) + err = p.ethereum.BlockManager.ProcessBlock(block) if err != nil { log.Println(err) + break + } else { + lastBlock = block } } - // If we're catching up, try to catch up further. - if p.catchingUp && msg.Data.Length() > 1 { - if ethutil.Config.Debug { - blockInfo := p.ethereum.BlockManager.BlockChain().BlockInfo(block) - log.Printf("Synced to block height #%d\n", blockInfo.Number) + if err != nil { + // If the parent is unknown try to catch up with this peer + if ethchain.IsParentErr(err) { + log.Println("Attempting to catch up") + p.catchingUp = false + p.CatchupWithPeer() + } + if ethchain.IsValidationErr(err) { + // TODO + } + } else { + // XXX Do we want to catch up if there were errors? + // If we're catching up, try to catch up further. + if p.catchingUp && msg.Data.Len() > 1 { + if ethutil.Config.Debug && lastBlock != nil { + blockInfo := lastBlock.BlockInfo() + log.Printf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + } + p.catchingUp = false + p.CatchupWithPeer() } - p.catchingUp = false - p.CatchupWithPeer() } case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and // processing when a new block is found - for i := 0; i < msg.Data.Length(); i++ { + for i := 0; i < msg.Data.Len(); i++ { p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) } case ethwire.MsgGetPeersTy: @@ -317,10 +341,10 @@ func (p *Peer) HandleInbound() { //if p.requestedPeerList { data := msg.Data // Create new list of possible peers for the ethereum to process - peers := make([]string, data.Length()) + peers := make([]string, data.Len()) // Parse each possible peer - for i := 0; i < data.Length(); i++ { - value := ethutil.NewValue(data.Get(i).AsRaw()) + for i := 0; i < data.Len(); i++ { + value := data.Get(i) peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint()) } @@ -333,7 +357,7 @@ func (p *Peer) HandleInbound() { case ethwire.MsgGetChainTy: var parent *ethchain.Block // Length minus one since the very last element in the array is a count - l := msg.Data.Length() - 1 + l := msg.Data.Len() - 1 // Ignore empty get chains if l == 0 { break @@ -345,7 +369,7 @@ func (p *Peer) HandleInbound() { // Check each SHA block hash from the message and determine whether // the SHA is in the database for i := 0; i < l; i++ { - if data := msg.Data.Get(i).AsBytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { + if data := msg.Data.Get(i).Bytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { parent = p.ethereum.BlockManager.BlockChain().GetBlock(data) break } @@ -359,8 +383,8 @@ func (p *Peer) HandleInbound() { // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain lastHash := msg.Data.Get(l - 1) - log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.AsRaw()})) + //log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) } case ethwire.MsgNotInChainTy: log.Printf("Not in chain %x\n", msg.Data) @@ -368,7 +392,7 @@ func (p *Peer) HandleInbound() { // Unofficial but fun nonetheless case ethwire.MsgTalkTy: - log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.AsString()) + log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) } } } @@ -441,9 +465,8 @@ func (p *Peer) pushHandshake() error { data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() - clientId := fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS) msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(4), uint32(0), clientId, byte(p.caps), p.port, pubkey, + uint32(4), uint32(0), p.Version, byte(p.caps), p.port, pubkey, }) p.QueueMessage(msg) @@ -470,7 +493,7 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - if c.Get(0).AsUint() != 4 { + if c.Get(0).Uint() != 4 { log.Println("Invalid peer version. Require protocol v4") p.Stop() return @@ -479,35 +502,49 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { // [PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPS, PORT, PUBKEY] p.versionKnown = true - var istr string // If this is an inbound connection send an ack back if p.inbound { - p.pubkey = c.Get(5).AsBytes() - p.port = uint16(c.Get(4).AsUint()) + p.pubkey = c.Get(5).Bytes() + p.port = uint16(c.Get(4).Uint()) // Self connect detection - /* - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() - if bytes.Compare(pubkey, p.pubkey) == 0 { - p.Stop() + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + if bytes.Compare(pubkey, p.pubkey) == 0 { + p.Stop() - return - } - */ + return + } - p.CatchupWithPeer() - - istr = "inbound" - } else { - p.CatchupWithPeer() - - istr = "outbound" } - p.caps = Caps(c.Get(3).AsByte()) + // Catch up with the connected peer + p.CatchupWithPeer() + + // Set the peer's caps + p.caps = Caps(c.Get(3).Byte()) + // Get a reference to the peers version + p.Version = c.Get(2).Str() + + log.Println(p) +} + +func (p *Peer) String() string { + var strBoundType string + if p.inbound { + strBoundType = "inbound" + } else { + strBoundType = "outbound" + } + var strConnectType string + if atomic.LoadInt32(&p.disconnect) == 0 { + strConnectType = "connected" + } else { + strConnectType = "disconnected" + } + + return fmt.Sprintf("peer [%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) - log.Printf("peer connect (%s) %v %s [%s]\n", istr, p.conn.RemoteAddr(), c.Get(2).AsString(), p.caps) } func (p *Peer) CatchupWithPeer() { From f6d1bfe45bf3709d7bad40bf563b5c09228622e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 14 Feb 2014 23:56:09 +0100 Subject: [PATCH 0048/1237] The great merge --- ethchain/.gitignore | 12 + ethchain/block.go | 363 +++++++++++++++++++ ethchain/block_chain.go | 184 ++++++++++ ethchain/block_manager.go | 627 +++++++++++++++++++++++++++++++++ ethchain/block_manager_test.go | 75 ++++ ethchain/contract.go | 66 ++++ ethchain/dagger.go | 199 +++++++++++ ethchain/dagger_test.go | 18 + ethchain/error.go | 42 +++ ethchain/fees.go | 65 ++++ ethchain/genesis.go | 39 ++ ethchain/stack.go | 167 +++++++++ ethchain/transaction.go | 157 +++++++++ ethchain/transaction_pool.go | 219 ++++++++++++ ethchain/transaction_test.go | 54 +++ ethdb/.gitignore | 12 + ethdb/README.md | 11 + ethdb/database.go | 64 ++++ ethdb/database_test.go | 6 + ethdb/memory_database.go | 49 +++ ethereum.go | 12 +- ethutil/.gitignore | 12 + ethutil/.travil.yml | 3 + ethutil/README.md | 137 +++++++ ethutil/big.go | 37 ++ ethutil/bytes.go | 64 ++++ ethutil/config.go | 106 ++++++ ethutil/db.go | 10 + ethutil/encoding.go | 62 ++++ ethutil/encoding_test.go | 37 ++ ethutil/helpers.go | 61 ++++ ethutil/parsing.go | 108 ++++++ ethutil/parsing_test.go | 32 ++ ethutil/rand.go | 24 ++ ethutil/rlp.go | 418 ++++++++++++++++++++++ ethutil/rlp_test.go | 170 +++++++++ ethutil/trie.go | 354 +++++++++++++++++++ ethutil/trie_test.go | 40 +++ ethutil/value.go | 204 +++++++++++ ethwire/.gitignore | 12 + ethwire/README.md | 36 ++ ethwire/messaging.go | 180 ++++++++++ peer.go | 11 +- 43 files changed, 4547 insertions(+), 12 deletions(-) create mode 100644 ethchain/.gitignore create mode 100644 ethchain/block.go create mode 100644 ethchain/block_chain.go create mode 100644 ethchain/block_manager.go create mode 100644 ethchain/block_manager_test.go create mode 100644 ethchain/contract.go create mode 100644 ethchain/dagger.go create mode 100644 ethchain/dagger_test.go create mode 100644 ethchain/error.go create mode 100644 ethchain/fees.go create mode 100644 ethchain/genesis.go create mode 100644 ethchain/stack.go create mode 100644 ethchain/transaction.go create mode 100644 ethchain/transaction_pool.go create mode 100644 ethchain/transaction_test.go create mode 100644 ethdb/.gitignore create mode 100644 ethdb/README.md create mode 100644 ethdb/database.go create mode 100644 ethdb/database_test.go create mode 100644 ethdb/memory_database.go create mode 100644 ethutil/.gitignore create mode 100644 ethutil/.travil.yml create mode 100644 ethutil/README.md create mode 100644 ethutil/big.go create mode 100644 ethutil/bytes.go create mode 100644 ethutil/config.go create mode 100644 ethutil/db.go create mode 100644 ethutil/encoding.go create mode 100644 ethutil/encoding_test.go create mode 100644 ethutil/helpers.go create mode 100644 ethutil/parsing.go create mode 100644 ethutil/parsing_test.go create mode 100644 ethutil/rand.go create mode 100644 ethutil/rlp.go create mode 100644 ethutil/rlp_test.go create mode 100644 ethutil/trie.go create mode 100644 ethutil/trie_test.go create mode 100644 ethutil/value.go create mode 100644 ethwire/.gitignore create mode 100644 ethwire/README.md create mode 100644 ethwire/messaging.go diff --git a/ethchain/.gitignore b/ethchain/.gitignore new file mode 100644 index 0000000000..f725d58d14 --- /dev/null +++ b/ethchain/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethchain/block.go b/ethchain/block.go new file mode 100644 index 0000000000..a7a1f787b8 --- /dev/null +++ b/ethchain/block.go @@ -0,0 +1,363 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "time" +) + +type BlockInfo struct { + Number uint64 + Hash []byte + Parent []byte +} + +func (bi *BlockInfo) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + bi.Number = decoder.Get(0).Uint() + bi.Hash = decoder.Get(1).Bytes() + bi.Parent = decoder.Get(2).Bytes() +} + +func (bi *BlockInfo) RlpEncode() []byte { + return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent}) +} + +type Block struct { + // Hash to the previous block + PrevHash []byte + // Uncles of this block + Uncles []*Block + UncleSha []byte + // The coin base address + Coinbase []byte + // Block Trie state + state *ethutil.Trie + // Difficulty for the current block + Difficulty *big.Int + // Creation time + Time int64 + // Extra data + Extra string + // Block Nonce for verification + Nonce []byte + // List of transactions and/or contracts + transactions []*Transaction + TxSha []byte +} + +// New block takes a raw encoded string +// XXX DEPRICATED +func NewBlockFromData(raw []byte) *Block { + return NewBlockFromBytes(raw) +} + +func NewBlockFromBytes(raw []byte) *Block { + block := &Block{} + block.RlpDecode(raw) + + return block +} + +// New block takes a raw encoded string +func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { + block := &Block{} + block.RlpValueDecode(rlpValue) + + return block +} + +func CreateBlock(root interface{}, + prevHash []byte, + base []byte, + Difficulty *big.Int, + Nonce []byte, + extra string, + txes []*Transaction) *Block { + + block := &Block{ + // Slice of transactions to include in this block + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + } + block.SetTransactions(txes) + block.SetUncles([]*Block{}) + + block.state = ethutil.NewTrie(ethutil.Config.Db, root) + + for _, tx := range txes { + block.MakeContract(tx) + } + + return block +} + +// Returns a hash of the block +func (block *Block) Hash() []byte { + return ethutil.Sha3Bin(block.RlpValue().Encode()) +} + +func (block *Block) HashNoNonce() []byte { + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) +} + +func (block *Block) PrintHash() { + fmt.Println(block) + fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) +} + +func (block *Block) State() *ethutil.Trie { + return block.state +} + +func (block *Block) Transactions() []*Transaction { + return block.transactions +} + +func (block *Block) GetContract(addr []byte) *Contract { + data := block.state.Get(string(addr)) + if data == "" { + return nil + } + + contract := &Contract{} + contract.RlpDecode([]byte(data)) + + return contract +} +func (block *Block) UpdateContract(addr []byte, contract *Contract) { + // Make sure the state is synced + contract.State().Sync() + + block.state.Update(string(addr), string(contract.RlpEncode())) +} + +func (block *Block) GetAddr(addr []byte) *Address { + var address *Address + + data := block.State().Get(string(addr)) + if data == "" { + address = NewAddress(big.NewInt(0)) + } else { + address = NewAddressFromData([]byte(data)) + } + + return address +} +func (block *Block) UpdateAddr(addr []byte, address *Address) { + block.state.Update(string(addr), string(address.RlpEncode())) +} + +func (block *Block) PayFee(addr []byte, fee *big.Int) bool { + contract := block.GetContract(addr) + // If we can't pay the fee return + if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { + fmt.Println("Contract has insufficient funds", contract.Amount, fee) + + return false + } + + base := new(big.Int) + contract.Amount = base.Sub(contract.Amount, fee) + block.state.Update(string(addr), string(contract.RlpEncode())) + + data := block.state.Get(string(block.Coinbase)) + + // Get the ether (Coinbase) and add the fee (gief fee to miner) + ether := NewAddressFromData([]byte(data)) + + base = new(big.Int) + ether.Amount = base.Add(ether.Amount, fee) + + block.state.Update(string(block.Coinbase), string(ether.RlpEncode())) + + return true +} + +func (block *Block) BlockInfo() BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (block *Block) MakeContract(tx *Transaction) { + // Create contract if there's no recipient + if tx.IsContract() { + addr := tx.Hash() + + value := tx.Value + contract := NewContract(value, []byte("")) + block.state.Update(string(addr), string(contract.RlpEncode())) + for i, val := range tx.Data { + contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val) + } + block.UpdateContract(addr, contract) + } +} + +/////// Block Encoding +func (block *Block) encodedUncles() interface{} { + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + uncles[i] = uncle.RlpEncode() + } + + return uncles +} + +func (block *Block) encodedTxs() interface{} { + // Marshal the transactions of this block + encTx := make([]interface{}, len(block.transactions)) + for i, tx := range block.transactions { + // Cast it to a string (safe) + encTx[i] = tx.RlpData() + } + + return encTx +} + +func (block *Block) rlpTxs() interface{} { + // Marshal the transactions of this block + encTx := make([]interface{}, len(block.transactions)) + for i, tx := range block.transactions { + // Cast it to a string (safe) + encTx[i] = tx.RlpData() + } + + return encTx +} + +func (block *Block) rlpUncles() interface{} { + // Marshal the transactions of this block + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + // Cast it to a string (safe) + uncles[i] = uncle.header() + } + + return uncles +} + +func (block *Block) SetUncles(uncles []*Block) { + block.Uncles = uncles + + // Sha of the concatenated uncles + block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) +} + +func (block *Block) SetTransactions(txs []*Transaction) { + block.transactions = txs + + block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) +} + +func (block *Block) RlpValue() *ethutil.RlpValue { + return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) +} + +func (block *Block) RlpEncode() []byte { + // Encode a slice interface which contains the header and the list of + // transactions. + return block.RlpValue().Encode() +} + +func (block *Block) RlpDecode(data []byte) { + rlpValue := ethutil.NewValueFromBytes(data) + block.RlpValueDecode(rlpValue) +} + +func (block *Block) RlpValueDecode(decoder *ethutil.Value) { + header := decoder.Get(0) + + block.PrevHash = header.Get(0).Bytes() + block.UncleSha = header.Get(1).Bytes() + block.Coinbase = header.Get(2).Bytes() + block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.TxSha = header.Get(4).Bytes() + block.Difficulty = header.Get(5).BigInt() + block.Time = int64(header.Get(6).BigInt().Uint64()) + block.Extra = header.Get(7).Str() + block.Nonce = header.Get(8).Bytes() + + // Tx list might be empty if this is an uncle. Uncles only have their + // header set. + if decoder.Get(1).IsNil() == false { // Yes explicitness + txes := decoder.Get(1) + block.transactions = make([]*Transaction, txes.Len()) + for i := 0; i < txes.Len(); i++ { + tx := NewTransactionFromValue(txes.Get(i)) + + block.transactions[i] = tx + + /* + if ethutil.Config.Debug { + ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx)) + } + */ + } + + } + + if decoder.Get(2).IsNil() == false { // Yes explicitness + uncles := decoder.Get(2) + block.Uncles = make([]*Block, uncles.Len()) + for i := 0; i < uncles.Len(); i++ { + block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) + } + } + +} + +func NewUncleBlockFromValue(header *ethutil.Value) *Block { + block := &Block{} + + block.PrevHash = header.Get(0).Bytes() + block.UncleSha = header.Get(1).Bytes() + block.Coinbase = header.Get(2).Bytes() + block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.TxSha = header.Get(4).Bytes() + block.Difficulty = header.Get(5).BigInt() + block.Time = int64(header.Get(6).BigInt().Uint64()) + block.Extra = header.Get(7).Str() + block.Nonce = header.Get(8).Bytes() + + return block +} + +func (block *Block) String() string { + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce) +} + +//////////// UNEXPORTED ///////////////// +func (block *Block) header() []interface{} { + return []interface{}{ + // Sha of the previous block + block.PrevHash, + // Sha of uncles + block.UncleSha, + // Coinbase address + block.Coinbase, + // root state + block.state.Root, + // Sha of tx + block.TxSha, + // Current block Difficulty + block.Difficulty, + // Time the block was found? + block.Time, + // Extra data + block.Extra, + // Block's Nonce for validation + block.Nonce, + } +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go new file mode 100644 index 0000000000..56bc43a8e4 --- /dev/null +++ b/ethchain/block_chain.go @@ -0,0 +1,184 @@ +package ethchain + +import ( + "bytes" + "github.com/ethereum/eth-go/ethutil" + "log" + "math" + "math/big" +) + +type BlockChain struct { + // The famous, the fabulous Mister GENESIIIIIIS (block) + genesisBlock *Block + // Last known total difficulty + TD *big.Int + + LastBlockNumber uint64 + + CurrentBlock *Block + LastBlockHash []byte +} + +func NewBlockChain() *BlockChain { + bc := &BlockChain{} + bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + + bc.setLastBlock() + + return bc +} + +func (bc *BlockChain) Genesis() *Block { + return bc.genesisBlock +} + +func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { + var root interface{} + var lastBlockTime int64 + hash := ZeroHash256 + + if bc.CurrentBlock != nil { + root = bc.CurrentBlock.State().Root + hash = bc.LastBlockHash + lastBlockTime = bc.CurrentBlock.Time + } + + block := CreateBlock( + root, + hash, + coinbase, + ethutil.BigPow(2, 32), + nil, + "", + txs) + + if bc.CurrentBlock != nil { + var mul *big.Int + if block.Time < lastBlockTime+42 { + mul = big.NewInt(1) + } else { + mul = big.NewInt(-1) + } + + diff := new(big.Int) + diff.Add(diff, bc.CurrentBlock.Difficulty) + diff.Div(diff, big.NewInt(1024)) + diff.Mul(diff, mul) + diff.Add(diff, bc.CurrentBlock.Difficulty) + block.Difficulty = diff + } + + return block +} + +func (bc *BlockChain) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + +func (bc *BlockChain) GenesisBlock() *Block { + return bc.genesisBlock +} + +// Get chain return blocks from hash up to max in RLP format +func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { + var chain []interface{} + // Get the current hash to start with + currentHash := bc.CurrentBlock.Hash() + // Get the last number on the block chain + lastNumber := bc.BlockInfo(bc.CurrentBlock).Number + // Get the parents number + parentNumber := bc.BlockInfoByHash(hash).Number + // Get the min amount. We might not have max amount of blocks + count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) + startNumber := parentNumber + count + + num := lastNumber + for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash { + num-- + } + for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { + // Get the block of the chain + block := bc.GetBlock(currentHash) + currentHash = block.PrevHash + + chain = append(chain, block.RlpValue().Value) + //chain = append([]interface{}{block.RlpValue().Value}, chain...) + + num-- + } + + return chain +} + +func (bc *BlockChain) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + block := NewBlockFromBytes(data) + info := bc.BlockInfo(block) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = info.Number + + log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + } + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) +} + +func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LastKnownTotalDifficulty"), td.Bytes()) + bc.TD = td +} + +// Add a block to the chain and record addition information +func (bc *BlockChain) Add(block *Block) { + bc.writeBlockInfo(block) + + // Prepare the genesis block + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + + ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) +} + +func (bc *BlockChain) GetBlock(hash []byte) *Block { + data, _ := ethutil.Config.Db.Get(hash) + + return NewBlockFromData(data) +} + +func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (bc *BlockChain) BlockInfo(block *Block) BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +// Unexported method for writing extra non-essential block info to the db +func (bc *BlockChain) writeBlockInfo(block *Block) { + bc.LastBlockNumber++ + bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash} + + // For now we use the block hash with the words "info" appended as key + ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) +} + +func (bc *BlockChain) Stop() { + if bc.CurrentBlock != nil { + ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode()) + + log.Println("[CHAIN] Stopped") + } +} diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go new file mode 100644 index 0000000000..92f20e2532 --- /dev/null +++ b/ethchain/block_manager.go @@ -0,0 +1,627 @@ +package ethchain + +import ( + "bytes" + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "log" + "math" + "math/big" + "strconv" + "sync" + "time" +) + +type BlockProcessor interface { + ProcessBlock(block *Block) +} + +func CalculateBlockReward(block *Block, uncleLength int) *big.Int { + return BlockReward +} + +type BlockManager struct { + // Mutex for locking the block processor. Blocks can only be handled one at a time + mutex sync.Mutex + + // The block chain :) + bc *BlockChain + + // Stack for processing contracts + stack *Stack + // non-persistent key/value memory storage + mem map[string]*big.Int + + TransactionPool *TxPool + + Pow PoW + + Speaker PublicSpeaker + + SecondaryBlockProcessor BlockProcessor +} + +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin + "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit + "80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex + } { + //log.Println("2^200 Wei to", addr) + codedAddr, _ := hex.DecodeString(addr) + addr := block.GetAddr(codedAddr) + addr.Amount = ethutil.BigPow(2, 200) + block.UpdateAddr(codedAddr, addr) + } +} + +func NewBlockManager(speaker PublicSpeaker) *BlockManager { + bm := &BlockManager{ + //server: s, + bc: NewBlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Speaker: speaker, + } + + if bm.bc.CurrentBlock == nil { + AddTestNetFunds(bm.bc.genesisBlock) + // Prepare the genesis block + //bm.bc.genesisBlock.State().Sync() + bm.bc.Add(bm.bc.genesisBlock) + log.Println(bm.bc.genesisBlock) + + log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash()) + //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //bm.bc.genesisBlock.PrintHash() + } + + return bm +} + +func (bm *BlockManager) BlockChain() *BlockChain { + return bm.bc +} + +func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { + // Process each transaction/contract + for _, tx := range txs { + // If there's no recipient, it's a contract + if tx.IsContract() { + block.MakeContract(tx) + bm.ProcessContract(tx, block) + } else { + bm.TransactionPool.ProcessTransaction(tx, block) + } + } +} + +// Block processing and validating with a given (temporarily) state +func (bm *BlockManager) ProcessBlock(block *Block) error { + // Processing a blocks may never happen simultaneously + bm.mutex.Lock() + defer bm.mutex.Unlock() + + hash := block.Hash() + + if bm.bc.HasBlock(hash) { + return nil + } + + /* + if ethutil.Config.Debug { + log.Printf("[BMGR] Processing block(%x)\n", hash) + } + */ + + // Check if we have the parent hash, if it isn't known we discard it + // Reasons might be catching up or simply an invalid block + if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil { + return ParentError(block.PrevHash) + } + + // Process the transactions on to current block + bm.ApplyTransactions(bm.bc.CurrentBlock, block.Transactions()) + + // Block validation + if err := bm.ValidateBlock(block); err != nil { + return err + } + + // I'm not sure, but I don't know if there should be thrown + // any errors at this time. + if err := bm.AccumelateRewards(bm.bc.CurrentBlock, block); err != nil { + return err + } + + if !block.State().Cmp(bm.bc.CurrentBlock.State()) { + //if block.State().Root != state.Root { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root) + } + + // Calculate the new total difficulty and sync back to the db + if bm.CalculateTD(block) { + // Sync the current block's state to the database + bm.bc.CurrentBlock.State().Sync() + // Add the block to the chain + bm.bc.Add(block) + + /* + ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) + bm.bc.CurrentBlock = block + bm.LastBlockHash = block.Hash() + bm.writeBlockInfo(block) + */ + + /* + txs := bm.TransactionPool.Flush() + var coded = []interface{}{} + for _, tx := range txs { + err := bm.TransactionPool.ValidateTransaction(tx) + if err == nil { + coded = append(coded, tx.RlpEncode()) + } + } + */ + + // Broadcast the valid block back to the wire + //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value}) + + // If there's a block processor present, pass in the block for further + // processing + if bm.SecondaryBlockProcessor != nil { + bm.SecondaryBlockProcessor.ProcessBlock(block) + } + + log.Printf("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + } else { + fmt.Println("total diff failed") + } + + return nil +} + +func (bm *BlockManager) CalculateTD(block *Block) bool { + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } + + // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty + td := new(big.Int) + td = td.Add(bm.bc.TD, uncleDiff) + td = td.Add(td, block.Difficulty) + + // The new TD will only be accepted if the new difficulty is + // is greater than the previous. + if td.Cmp(bm.bc.TD) > 0 { + // Set the new total difficulty back to the block chain + bm.bc.SetTotalDifficulty(td) + + /* + if ethutil.Config.Debug { + log.Println("[BMGR] TD(block) =", td) + } + */ + + return true + } + + return false +} + +// Validates the current block. Returns an error if the block was invalid, +// an uncle or anything that isn't on the current block chain. +// Validation validates easy over difficult (dagger takes longer time = difficult) +func (bm *BlockManager) ValidateBlock(block *Block) error { + // TODO + // 2. Check if the difficulty is correct + + // Check each uncle's previous hash. In order for it to be valid + // is if it has the same block hash as the current + previousBlock := bm.bc.GetBlock(block.PrevHash) + for _, uncle := range block.Uncles { + if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 { + return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash) + } + } + + diff := block.Time - bm.bc.CurrentBlock.Time + if diff < 0 { + return ValidationError("Block timestamp less then prev block %v", diff) + } + + // New blocks must be within the 15 minute range of the last block. + if diff > int64(15*time.Minute) { + return ValidationError("Block is too far in the future of last block (> 15 minutes)") + } + + // Verify the nonce of the block. Return an error if it's not valid + if !bm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { + return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) + } + + return nil +} + +func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { + // Get the coinbase rlp data + addr := processor.GetAddr(block.Coinbase) + // Reward amount of ether to the coinbase address + addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) + + processor.UpdateAddr(block.Coinbase, addr) + + // TODO Reward each uncle + + return nil +} + +func (bm *BlockManager) Stop() { + bm.bc.Stop() +} + +func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { + // Recovering function in case the VM had any errors + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + } + }() + + // Process contract + bm.ProcContract(tx, block, func(opType OpType) bool { + // TODO turn on once big ints are in place + //if !block.PayFee(tx.Hash(), StepFee.Uint64()) { + // return false + //} + + return true // Continue + }) +} + +// Contract evaluation is done here. +func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { + + // Instruction pointer + pc := 0 + blockInfo := bm.bc.BlockInfo(block) + + contract := block.GetContract(tx.Hash()) + if contract == nil { + fmt.Println("Contract not found") + return + } + + Pow256 := ethutil.BigPow(2, 256) + + if ethutil.Config.Debug { + fmt.Printf("# op arg\n") + } +out: + for { + // The base big int for all calculations. Use this for any results. + base := new(big.Int) + // XXX Should Instr return big int slice instead of string slice? + // Get the next instruction from the contract + //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) + nb := ethutil.NumberToBytes(uint64(pc), 32) + o, _, _ := ethutil.Instr(contract.State().Get(string(nb))) + op := OpCode(o) + + if !cb(0) { + break + } + + if ethutil.Config.Debug { + fmt.Printf("%-3d %-4s\n", pc, op.String()) + } + + switch op { + case oSTOP: + break out + case oADD: + x, y := bm.stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oSUB: + x, y := bm.stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oMUL: + x, y := bm.stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + bm.stack.Push(base) + case oDIV: + x, y := bm.stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + bm.stack.Push(base) + case oSDIV: + x, y := bm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Div(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + bm.stack.Push(z) + case oMOD: + x, y := bm.stack.Popn() + base.Mod(x, y) + bm.stack.Push(base) + case oSMOD: + x, y := bm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Mod(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + bm.stack.Push(z) + case oEXP: + x, y := bm.stack.Popn() + base.Exp(x, y, Pow256) + + bm.stack.Push(base) + case oNEG: + base.Sub(Pow256, bm.stack.Pop()) + bm.stack.Push(base) + case oLT: + x, y := bm.stack.Popn() + // x < y + if x.Cmp(y) < 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oLE: + x, y := bm.stack.Popn() + // x <= y + if x.Cmp(y) < 1 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := bm.stack.Popn() + // x > y + if x.Cmp(y) > 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oGE: + x, y := bm.stack.Popn() + // x >= y + if x.Cmp(y) > -1 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := bm.stack.Popn() + // x != y + if x.Cmp(y) != 0 { + bm.stack.Push(ethutil.BigTrue) + } else { + bm.stack.Push(ethutil.BigFalse) + } + + // Please note that the following code contains some + // ugly string casting. This will have to change to big + // ints. TODO :) + case oMYADDRESS: + bm.stack.Push(ethutil.BigD(tx.Hash())) + case oTXSENDER: + bm.stack.Push(ethutil.BigD(tx.Sender())) + case oTXVALUE: + bm.stack.Push(tx.Value) + case oTXDATAN: + bm.stack.Push(big.NewInt(int64(len(tx.Data)))) + case oTXDATA: + v := bm.stack.Pop() + // v >= len(data) + if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 { + bm.stack.Push(ethutil.Big("0")) + } else { + bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()])) + } + case oBLK_PREVHASH: + bm.stack.Push(ethutil.BigD(block.PrevHash)) + case oBLK_COINBASE: + bm.stack.Push(ethutil.BigD(block.Coinbase)) + case oBLK_TIMESTAMP: + bm.stack.Push(big.NewInt(block.Time)) + case oBLK_NUMBER: + bm.stack.Push(big.NewInt(int64(blockInfo.Number))) + case oBLK_DIFFICULTY: + bm.stack.Push(block.Difficulty) + case oBASEFEE: + // e = 10^21 + e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) + d := new(big.Rat) + d.SetInt(block.Difficulty) + c := new(big.Rat) + c.SetFloat64(0.5) + // d = diff / 0.5 + d.Quo(d, c) + // base = floor(d) + base.Div(d.Num(), d.Denom()) + + x := new(big.Int) + x.Div(e, base) + + // x = floor(10^21 / floor(diff^0.5)) + bm.stack.Push(x) + case oSHA256, oSHA3, oRIPEMD160: + // This is probably save + // ceil(pop / 32) + length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0)) + // New buffer which will contain the concatenated popped items + data := new(bytes.Buffer) + for i := 0; i < length; i++ { + // Encode the number to bytes and have it 32bytes long + num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256) + data.WriteString(string(num)) + } + + if op == oSHA256 { + bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) + } else if op == oSHA3 { + bm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) + } else { + bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) + } + case oECMUL: + y := bm.stack.Pop() + x := bm.stack.Pop() + //n := bm.stack.Pop() + + //if ethutil.Big(x).Cmp(ethutil.Big(y)) { + data := new(bytes.Buffer) + data.WriteString(x.String()) + data.WriteString(y.String()) + if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { + // TODO + } else { + // Invalid, push infinity + bm.stack.Push(ethutil.Big("0")) + bm.stack.Push(ethutil.Big("0")) + } + //} else { + // // Invalid, push infinity + // bm.stack.Push("0") + // bm.stack.Push("0") + //} + + case oECADD: + case oECSIGN: + case oECRECOVER: + case oECVALID: + case oPUSH: + pc++ + bm.stack.Push(bm.mem[strconv.Itoa(pc)]) + case oPOP: + // Pop current value of the stack + bm.stack.Pop() + case oDUP: + // Dup top stack + x := bm.stack.Pop() + bm.stack.Push(x) + bm.stack.Push(x) + case oSWAP: + // Swap two top most values + x, y := bm.stack.Popn() + bm.stack.Push(y) + bm.stack.Push(x) + case oMLOAD: + x := bm.stack.Pop() + bm.stack.Push(bm.mem[x.String()]) + case oMSTORE: + x, y := bm.stack.Popn() + bm.mem[x.String()] = y + case oSLOAD: + // Load the value in storage and push it on the stack + x := bm.stack.Pop() + // decode the object as a big integer + decoder := ethutil.NewRlpValueFromBytes([]byte(contract.State().Get(x.String()))) + if !decoder.IsNil() { + bm.stack.Push(decoder.AsBigInt()) + } else { + bm.stack.Push(ethutil.BigFalse) + } + case oSSTORE: + // Store Y at index X + x, y := bm.stack.Popn() + contract.State().Update(x.String(), string(ethutil.Encode(y))) + case oJMP: + x := int(bm.stack.Pop().Uint64()) + // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) + pc = x + pc-- + case oJMPI: + x := bm.stack.Pop() + // Set pc to x if it's non zero + if x.Cmp(ethutil.BigFalse) != 0 { + pc = int(x.Uint64()) + pc-- + } + case oIND: + bm.stack.Push(big.NewInt(int64(pc))) + case oEXTRO: + memAddr := bm.stack.Pop() + contractAddr := bm.stack.Pop().Bytes() + + // Push the contract's memory on to the stack + bm.stack.Push(getContractMemory(block, contractAddr, memAddr)) + case oBALANCE: + // Pushes the balance of the popped value on to the stack + d := block.State().Get(bm.stack.Pop().String()) + ether := NewAddressFromData([]byte(d)) + bm.stack.Push(ether.Amount) + case oMKTX: + value, addr := bm.stack.Popn() + from, length := bm.stack.Popn() + + j := 0 + dataItems := make([]string, int(length.Uint64())) + for i := from.Uint64(); i < length.Uint64(); i++ { + dataItems[j] = string(bm.mem[strconv.Itoa(int(i))].Bytes()) + j++ + } + // TODO sign it? + tx := NewTransaction(addr.Bytes(), value, dataItems) + // Add the transaction to the tx pool + bm.TransactionPool.QueueTransaction(tx) + case oSUICIDE: + //addr := bm.stack.Pop() + } + pc++ + } +} + +// Returns an address from the specified contract's address +func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big.Int { + contract := block.GetContract(contractAddr) + if contract == nil { + log.Panicf("invalid contract addr %x", contractAddr) + } + val := contract.State().Get(memAddr.String()) + + // decode the object as a big integer + decoder := ethutil.NewRlpValueFromBytes([]byte(val)) + if decoder.IsNil() { + return ethutil.BigFalse + } + + return decoder.AsBigInt() +} diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go new file mode 100644 index 0000000000..502c50b97b --- /dev/null +++ b/ethchain/block_manager_test.go @@ -0,0 +1,75 @@ +package ethchain + +/* +import ( + _ "fmt" + "testing" +) + +func TestVm(t *testing.T) { + InitFees() + + db, _ := NewMemDatabase() + Db = db + + ctrct := NewTransaction("", 200000000, []string{ + "PUSH", "1a2f2e", + "PUSH", "hallo", + "POP", // POP hallo + "PUSH", "3", + "LOAD", // Load hallo back on the stack + + "PUSH", "1", + "PUSH", "2", + "ADD", + + "PUSH", "2", + "PUSH", "1", + "SUB", + + "PUSH", "100000000000000000000000", + "PUSH", "10000000000000", + "SDIV", + + "PUSH", "105", + "PUSH", "200", + "MOD", + + "PUSH", "100000000000000000000000", + "PUSH", "10000000000000", + "SMOD", + + "PUSH", "5", + "PUSH", "10", + "LT", + + "PUSH", "5", + "PUSH", "5", + "LE", + + "PUSH", "50", + "PUSH", "5", + "GT", + + "PUSH", "5", + "PUSH", "5", + "GE", + + "PUSH", "10", + "PUSH", "10", + "NOT", + + "MYADDRESS", + "TXSENDER", + + "STOP", + }) + tx := NewTransaction("1e8a42ea8cce13", 100, []string{}) + + block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx}) + db.Put(block.Hash(), block.RlpEncode()) + + bm := NewBlockManager() + bm.ProcessBlock(block) +} +*/ diff --git a/ethchain/contract.go b/ethchain/contract.go new file mode 100644 index 0000000000..d1fcec3b46 --- /dev/null +++ b/ethchain/contract.go @@ -0,0 +1,66 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Contract struct { + Amount *big.Int + Nonce uint64 + state *ethutil.Trie +} + +func NewContract(Amount *big.Int, root []byte) *Contract { + contract := &Contract{Amount: Amount, Nonce: 0} + contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root)) + + return contract +} + +func (c *Contract) RlpEncode() []byte { + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.Root}) +} + +func (c *Contract) RlpDecode(data []byte) { + decoder := ethutil.NewRlpValueFromBytes(data) + + c.Amount = decoder.Get(0).AsBigInt() + c.Nonce = decoder.Get(1).AsUint() + c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw()) +} + +func (c *Contract) State() *ethutil.Trie { + return c.state +} + +type Address struct { + Amount *big.Int + Nonce uint64 +} + +func NewAddress(amount *big.Int) *Address { + return &Address{Amount: amount, Nonce: 0} +} + +func NewAddressFromData(data []byte) *Address { + address := &Address{} + address.RlpDecode(data) + + return address +} + +func (a *Address) AddFee(fee *big.Int) { + a.Amount.Add(a.Amount, fee) +} + +func (a *Address) RlpEncode() []byte { + return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) +} + +func (a *Address) RlpDecode(data []byte) { + decoder := ethutil.NewRlpValueFromBytes(data) + + a.Amount = decoder.Get(0).AsBigInt() + a.Nonce = decoder.Get(1).AsUint() +} diff --git a/ethchain/dagger.go b/ethchain/dagger.go new file mode 100644 index 0000000000..5b4f8b2cd0 --- /dev/null +++ b/ethchain/dagger.go @@ -0,0 +1,199 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/sha3" + "hash" + "log" + "math/big" + "math/rand" + "time" +) + +type PoW interface { + Search(block *Block) []byte + Verify(hash []byte, diff *big.Int, nonce []byte) bool +} + +type EasyPow struct { + hash *big.Int +} + +func (pow *EasyPow) Search(block *Block) []byte { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + hash := block.HashNoNonce() + diff := block.Difficulty + for { + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + if pow.Verify(hash, diff, sha) { + return sha + } + } + + return nil +} + +func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool { + sha := sha3.NewKeccak256() + + d := append(hash, nonce...) + sha.Write(d) + + v := ethutil.BigPow(2, 256) + ret := new(big.Int).Div(v, diff) + + res := new(big.Int) + res.SetBytes(sha.Sum(nil)) + + return res.Cmp(ret) == -1 +} + +func (pow *EasyPow) SetHash(hash *big.Int) { +} + +type Dagger struct { + hash *big.Int + xn *big.Int +} + +var Found bool + +func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for i := 0; i < 1000; i++ { + rnd := r.Int63() + + res := dag.Eval(big.NewInt(rnd)) + log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + if res.Cmp(obj) < 0 { + // Post back result on the channel + resChan <- rnd + // Notify other threads we've found a valid nonce + Found = true + } + + // Break out if found + if Found { + break + } + } + + resChan <- 0 +} + +func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { + // TODO fix multi threading. Somehow it results in the wrong nonce + amountOfRoutines := 1 + + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + Found = false + resChan := make(chan int64, 3) + var res int64 + + for k := 0; k < amountOfRoutines; k++ { + go dag.Find(obj, resChan) + } + + // Wait for each go routine to finish + for k := 0; k < amountOfRoutines; k++ { + // Get the result from the channel. 0 = quit + if r := <-resChan; r != 0 { + res = r + } + } + + return big.NewInt(res) +} + +func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { + dag.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + return dag.Eval(nonce).Cmp(obj) < 0 +} + +func DaggerVerify(hash, diff, nonce *big.Int) bool { + dagger := &Dagger{} + dagger.hash = hash + + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) + + return dagger.Eval(nonce).Cmp(obj) < 0 +} + +func (dag *Dagger) Node(L uint64, i uint64) *big.Int { + if L == i { + return dag.hash + } + + var m *big.Int + if L == 9 { + m = big.NewInt(16) + } else { + m = big.NewInt(3) + } + + sha := sha3.NewKeccak256() + sha.Reset() + d := sha3.NewKeccak256() + b := new(big.Int) + ret := new(big.Int) + + for k := 0; k < int(m.Uint64()); k++ { + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(big.NewInt(int64(L)).Bytes()) + d.Write(big.NewInt(int64(i)).Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) + + b.SetBytes(Sum(d)) + pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) + sha.Write(dag.Node(L-1, pk).Bytes()) + } + + ret.SetBytes(Sum(sha)) + + return ret +} + +func Sum(sha hash.Hash) []byte { + //in := make([]byte, 32) + return sha.Sum(nil) +} + +func (dag *Dagger) Eval(N *big.Int) *big.Int { + pow := ethutil.BigPow(2, 26) + dag.xn = pow.Div(N, pow) + + sha := sha3.NewKeccak256() + sha.Reset() + ret := new(big.Int) + + for k := 0; k < 4; k++ { + d := sha3.NewKeccak256() + b := new(big.Int) + + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(N.Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) + + b.SetBytes(Sum(d)) + pk := (b.Uint64() & 0x1ffffff) + + sha.Write(dag.Node(9, pk).Bytes()) + } + + return ret.SetBytes(Sum(sha)) +} diff --git a/ethchain/dagger_test.go b/ethchain/dagger_test.go new file mode 100644 index 0000000000..9d4e03c925 --- /dev/null +++ b/ethchain/dagger_test.go @@ -0,0 +1,18 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func BenchmarkDaggerSearch(b *testing.B) { + hash := big.NewInt(0) + diff := ethutil.BigPow(2, 36) + o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity + + // Reset timer so the big generation isn't included in the benchmark + b.ResetTimer() + // Validate + DaggerVerify(hash, diff, o) +} diff --git a/ethchain/error.go b/ethchain/error.go new file mode 100644 index 0000000000..0f1d061c0d --- /dev/null +++ b/ethchain/error.go @@ -0,0 +1,42 @@ +package ethchain + +import "fmt" + +// Parent error. In case a parent is unknown this error will be thrown +// by the block manager +type ParentErr struct { + Message string +} + +func (err *ParentErr) Error() string { + return err.Message +} + +func ParentError(hash []byte) error { + return &ParentErr{Message: fmt.Sprintf("Block's parent unkown %x", hash)} +} + +func IsParentErr(err error) bool { + _, ok := err.(*ParentErr) + + return ok +} + +// Block validation error. If any validation fails, this error will be thrown +type ValidationErr struct { + Message string +} + +func (err *ValidationErr) Error() string { + return err.Message +} + +func ValidationError(format string, v ...interface{}) *ValidationErr { + return &ValidationErr{Message: fmt.Sprintf(format, v...)} +} + +func IsValidationErr(err error) bool { + _, ok := err.(*ValidationErr) + + return ok +} diff --git a/ethchain/fees.go b/ethchain/fees.go new file mode 100644 index 0000000000..8f1646ab4c --- /dev/null +++ b/ethchain/fees.go @@ -0,0 +1,65 @@ +package ethchain + +import ( + "math/big" +) + +var StepFee *big.Int = new(big.Int) +var TxFeeRat *big.Int = big.NewInt(100000000000000) +var TxFee *big.Int = big.NewInt(100) +var ContractFee *big.Int = new(big.Int) +var MemFee *big.Int = new(big.Int) +var DataFee *big.Int = new(big.Int) +var CryptoFee *big.Int = new(big.Int) +var ExtroFee *big.Int = new(big.Int) + +var BlockReward *big.Int = big.NewInt(1500000000000000000) +var Period1Reward *big.Int = new(big.Int) +var Period2Reward *big.Int = new(big.Int) +var Period3Reward *big.Int = new(big.Int) +var Period4Reward *big.Int = new(big.Int) + +func InitFees() { + /* + // Base for 2**64 + b60 := new(big.Int) + b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + // Base for 2**80 + b80 := new(big.Int) + b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0)) + + StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0)) + //StepFee.Div(b60, big.NewInt(64)) + //fmt.Println("StepFee:", StepFee) + + TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + //fmt.Println("TxFee:", TxFee) + + ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) + //fmt.Println("ContractFee:", ContractFee) + + MemFee.Div(b60, big.NewInt(4)) + //fmt.Println("MemFee:", MemFee) + + DataFee.Div(b60, big.NewInt(16)) + //fmt.Println("DataFee:", DataFee) + + CryptoFee.Div(b60, big.NewInt(16)) + //fmt.Println("CrytoFee:", CryptoFee) + + ExtroFee.Div(b60, big.NewInt(16)) + //fmt.Println("ExtroFee:", ExtroFee) + + Period1Reward.Mul(b80, big.NewInt(1024)) + //fmt.Println("Period1Reward:", Period1Reward) + + Period2Reward.Mul(b80, big.NewInt(512)) + //fmt.Println("Period2Reward:", Period2Reward) + + Period3Reward.Mul(b80, big.NewInt(256)) + //fmt.Println("Period3Reward:", Period3Reward) + + Period4Reward.Mul(b80, big.NewInt(128)) + //fmt.Println("Period4Reward:", Period4Reward) + */ +} diff --git a/ethchain/genesis.go b/ethchain/genesis.go new file mode 100644 index 0000000000..060d347e42 --- /dev/null +++ b/ethchain/genesis.go @@ -0,0 +1,39 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +/* + * This is the special genesis block. + */ + +var ZeroHash256 = make([]byte, 32) +var ZeroHash160 = make([]byte, 20) +var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) + +var GenisisHeader = []interface{}{ + // Previous hash (none) + //"", + ZeroHash256, + // Sha of uncles + ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + // Coinbase + ZeroHash160, + // Root state + "", + // Sha of transactions + //EmptyShaList, + ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + // Difficulty + ethutil.BigPow(2, 22), + // Time + int64(0), + // Extra + "", + // Nonce + ethutil.Sha3Bin(big.NewInt(42).Bytes()), +} + +var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/stack.go b/ethchain/stack.go new file mode 100644 index 0000000000..c80d01e5c2 --- /dev/null +++ b/ethchain/stack.go @@ -0,0 +1,167 @@ +package ethchain + +import ( + "fmt" + "math/big" +) + +type OpCode int + +// Op codes +const ( + oSTOP OpCode = iota + oADD + oMUL + oSUB + oDIV + oSDIV + oMOD + oSMOD + oEXP + oNEG + oLT + oLE + oGT + oGE + oEQ + oNOT + oMYADDRESS + oTXSENDER + oTXVALUE + oTXFEE + oTXDATAN + oTXDATA + oBLK_PREVHASH + oBLK_COINBASE + oBLK_TIMESTAMP + oBLK_NUMBER + oBLK_DIFFICULTY + oBASEFEE + oSHA256 OpCode = 32 + oRIPEMD160 OpCode = 33 + oECMUL OpCode = 34 + oECADD OpCode = 35 + oECSIGN OpCode = 36 + oECRECOVER OpCode = 37 + oECVALID OpCode = 38 + oSHA3 OpCode = 39 + oPUSH OpCode = 48 + oPOP OpCode = 49 + oDUP OpCode = 50 + oSWAP OpCode = 51 + oMLOAD OpCode = 52 + oMSTORE OpCode = 53 + oSLOAD OpCode = 54 + oSSTORE OpCode = 55 + oJMP OpCode = 56 + oJMPI OpCode = 57 + oIND OpCode = 58 + oEXTRO OpCode = 59 + oBALANCE OpCode = 60 + oMKTX OpCode = 61 + oSUICIDE OpCode = 62 +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oLE: "LE", + oGT: "GT", + oGE: "GE", + oEQ: "EQ", + oNOT: "NOT", + oMYADDRESS: "MYADDRESS", + oTXSENDER: "TXSENDER", + oTXVALUE: "TXVALUE", + oTXFEE: "TXFEE", + oTXDATAN: "TXDATAN", + oTXDATA: "TXDATA", + oBLK_PREVHASH: "BLK_PREVHASH", + oBLK_COINBASE: "BLK_COINBASE", + oBLK_TIMESTAMP: "BLK_TIMESTAMP", + oBLK_NUMBER: "BLK_NUMBER", + oBLK_DIFFICULTY: "BLK_DIFFICULTY", + oBASEFEE: "BASEFEE", + oSHA256: "SHA256", + oRIPEMD160: "RIPEMD160", + oECMUL: "ECMUL", + oECADD: "ECADD", + oECSIGN: "ECSIGN", + oECRECOVER: "ECRECOVER", + oECVALID: "ECVALID", + oSHA3: "SHA3", + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJMP: "JMP", + oJMPI: "JMPI", + oIND: "IND", + oEXTRO: "EXTRO", + oBALANCE: "BALANCE", + oMKTX: "MKTX", + oSUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + return opCodeToString[o] +} + +type OpType int + +const ( + tNorm = iota + tData + tExtro + tCrypto +) + +type TxCallback func(opType OpType) bool + +// Simple push/pop stack mechanism +type Stack struct { + data []*big.Int +} + +func NewStack() *Stack { + return &Stack{} +} + +func (st *Stack) Pop() *big.Int { + s := len(st.data) + + str := st.data[s-1] + st.data = st.data[:s-1] + + return str +} + +func (st *Stack) Popn() (*big.Int, *big.Int) { + s := len(st.data) + + ints := st.data[s-2:] + st.data = st.data[:s-2] + + return ints[0], ints[1] +} + +func (st *Stack) Push(d *big.Int) { + st.data = append(st.data, d) +} +func (st *Stack) Print() { + fmt.Println(st.data) +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go new file mode 100644 index 0000000000..1a92582010 --- /dev/null +++ b/ethchain/transaction.go @@ -0,0 +1,157 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "math/big" +) + +type Transaction struct { + Nonce uint64 + Recipient []byte + Value *big.Int + Data []string + Memory []int + v byte + r, s []byte +} + +func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { + tx := Transaction{Recipient: to, Value: value} + tx.Nonce = 0 + + // Serialize the data + tx.Data = make([]string, len(data)) + for i, val := range data { + instr, err := ethutil.CompileInstr(val) + if err != nil { + //fmt.Printf("compile error:%d %v\n", i+1, err) + } + + tx.Data[i] = instr + } + + return &tx +} + +func NewTransactionFromData(data []byte) *Transaction { + tx := &Transaction{} + tx.RlpDecode(data) + + return tx +} + +func NewTransactionFromValue(val *ethutil.Value) *Transaction { + tx := &Transaction{} + tx.RlpValueDecode(val) + + return tx +} + +func (tx *Transaction) Hash() []byte { + data := make([]interface{}, len(tx.Data)) + for i, val := range tx.Data { + data[i] = val + } + + preEnc := []interface{}{ + tx.Nonce, + tx.Recipient, + tx.Value, + data, + } + + return ethutil.Sha3Bin(ethutil.Encode(preEnc)) +} + +func (tx *Transaction) IsContract() bool { + return len(tx.Recipient) == 0 +} + +func (tx *Transaction) Signature(key []byte) []byte { + hash := tx.Hash() + + sig, _ := secp256k1.Sign(hash, key) + + return sig +} + +func (tx *Transaction) PublicKey() []byte { + hash := tx.Hash() + + // If we don't make a copy we will overwrite the existing underlying array + dst := make([]byte, len(tx.r)) + copy(dst, tx.r) + + sig := append(dst, tx.s...) + sig = append(sig, tx.v-27) + + pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + + return pubkey +} + +func (tx *Transaction) Sender() []byte { + pubkey := tx.PublicKey() + + // Validate the returned key. + // Return nil if public key isn't in full format + if pubkey[0] != 4 { + return nil + } + + return ethutil.Sha3Bin(pubkey[1:])[12:] +} + +func (tx *Transaction) Sign(privk []byte) error { + + sig := tx.Signature(privk) + + tx.r = sig[:32] + tx.s = sig[32:64] + tx.v = sig[64] + 27 + + return nil +} + +func (tx *Transaction) RlpData() interface{} { + // Prepare the transaction for serialization + return []interface{}{ + tx.Nonce, + tx.Recipient, + tx.Value, + ethutil.NewSliceValue(tx.Data).Slice(), + tx.v, + tx.r, + tx.s, + } +} + +func (tx *Transaction) RlpValue() *ethutil.Value { + return ethutil.NewValue(tx.RlpData()) +} + +func (tx *Transaction) RlpEncode() []byte { + return tx.RlpValue().Encode() +} + +func (tx *Transaction) RlpDecode(data []byte) { + tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) +} + +func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + tx.Nonce = decoder.Get(0).Uint() + tx.Recipient = decoder.Get(1).Bytes() + tx.Value = decoder.Get(2).BigInt() + + d := decoder.Get(3) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + // TODO something going wrong here + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go new file mode 100644 index 0000000000..c2d65a2a7b --- /dev/null +++ b/ethchain/transaction_pool.go @@ -0,0 +1,219 @@ +package ethchain + +import ( + "bytes" + "container/list" + "errors" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "log" + "math/big" + "sync" +) + +const ( + txPoolQueueSize = 50 +) + +type TxPoolHook chan *Transaction + +func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { + for e := pool.Front(); e != nil; e = e.Next() { + if tx, ok := e.Value.(*Transaction); ok { + if finder(tx, e) { + return tx + } + } + } + + return nil +} + +type PublicSpeaker interface { + Broadcast(msgType ethwire.MsgType, data []interface{}) +} + +// The tx pool a thread safe transaction pool handler. In order to +// guarantee a non blocking pool we use a queue channel which can be +// independently read without needing access to the actual pool. If the +// pool is being drained or synced for whatever reason the transactions +// will simple queue up and handled when the mutex is freed. +type TxPool struct { + //server *Server + Speaker PublicSpeaker + // The mutex for accessing the Tx pool. + mutex sync.Mutex + // Queueing channel for reading and writing incoming + // transactions to + queueChan chan *Transaction + // Quiting channel + quit chan bool + // The actual pool + pool *list.List + + BlockManager *BlockManager + + Hook TxPoolHook +} + +func NewTxPool() *TxPool { + return &TxPool{ + //server: s, + mutex: sync.Mutex{}, + pool: list.New(), + queueChan: make(chan *Transaction, txPoolQueueSize), + quit: make(chan bool), + } +} + +// Blocking function. Don't use directly. Use QueueTransaction instead +func (pool *TxPool) addTransaction(tx *Transaction) { + pool.mutex.Lock() + pool.pool.PushBack(tx) + pool.mutex.Unlock() + + // Broadcast the transaction to the rest of the peers + pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) +} + +// Process transaction validates the Tx and processes funds from the +// sender to the recipient. +func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { + log.Printf("[TXPL] Processing Tx %x\n", tx.Hash()) + + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() + // Get the sender + sender := block.GetAddr(tx.Sender()) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + if sender.Amount.Cmp(totAmount) < 0 { + return errors.New("Insufficient amount in sender's account") + } + + if sender.Nonce != tx.Nonce { + if ethutil.Config.Debug { + return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce) + } else { + return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) + } + } + + // Subtract the amount from the senders account + sender.Amount.Sub(sender.Amount, totAmount) + sender.Nonce += 1 + + // Get the receiver + receiver := block.GetAddr(tx.Recipient) + // Add the amount to receivers account which should conclude this transaction + receiver.Amount.Add(receiver.Amount, tx.Value) + + block.UpdateAddr(tx.Sender(), sender) + block.UpdateAddr(tx.Recipient, receiver) + + return +} + +func (pool *TxPool) ValidateTransaction(tx *Transaction) error { + // Get the last block so we can retrieve the sender and receiver from + // the merkle trie + block := pool.BlockManager.BlockChain().CurrentBlock + // Something has gone horribly wrong if this happens + if block == nil { + return errors.New("No last block on the block chain") + } + + // Get the sender + sender := block.GetAddr(tx.Sender()) + + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + if sender.Amount.Cmp(totAmount) < 0 { + return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) + } + + // Increment the nonce making each tx valid only once to prevent replay + // attacks + + return nil +} + +func (pool *TxPool) queueHandler() { +out: + for { + select { + case tx := <-pool.queueChan: + hash := tx.Hash() + foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { + return bytes.Compare(tx.Hash(), hash) == 0 + }) + + if foundTx != nil { + break + } + + // Validate the transaction + err := pool.ValidateTransaction(tx) + if err != nil { + if ethutil.Config.Debug { + log.Println("Validating Tx failed", err) + } + } else { + // Call blocking version. At this point it + // doesn't matter since this is a goroutine + pool.addTransaction(tx) + + if pool.Hook != nil { + pool.Hook <- tx + } + } + case <-pool.quit: + break out + } + } +} + +func (pool *TxPool) QueueTransaction(tx *Transaction) { + pool.queueChan <- tx +} + +func (pool *TxPool) Flush() []*Transaction { + pool.mutex.Lock() + defer pool.mutex.Unlock() + + txList := make([]*Transaction, pool.pool.Len()) + i := 0 + for e := pool.pool.Front(); e != nil; e = e.Next() { + if tx, ok := e.Value.(*Transaction); ok { + txList[i] = tx + } + + i++ + } + + // Recreate a new list all together + // XXX Is this the fastest way? + pool.pool = list.New() + + return txList +} + +func (pool *TxPool) Start() { + go pool.queueHandler() +} + +func (pool *TxPool) Stop() { + log.Println("[TXP] Stopping...") + + close(pool.quit) + + pool.Flush() +} diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go new file mode 100644 index 0000000000..c9090b83df --- /dev/null +++ b/ethchain/transaction_test.go @@ -0,0 +1,54 @@ +package ethchain + +import ( + "encoding/hex" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func TestAddressRetrieval(t *testing.T) { + // TODO + // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f + key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") + + tx := &Transaction{ + Nonce: 0, + Recipient: ZeroHash160, + Value: big.NewInt(0), + Data: nil, + } + //fmt.Printf("rlp %x\n", tx.RlpEncode()) + //fmt.Printf("sha rlp %x\n", tx.Hash()) + + tx.Sign(key) + + //fmt.Printf("hex tx key %x\n", tx.PublicKey()) + //fmt.Printf("seder %x\n", tx.Sender()) +} + +func TestAddressRetrieval2(t *testing.T) { + // TODO + // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f + key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") + addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b") + tx := &Transaction{ + Nonce: 0, + Recipient: addr, + Value: big.NewInt(1000), + Data: nil, + } + tx.Sign(key) + //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") + //tx := NewTransactionFromData(data) + fmt.Println(tx.RlpValue()) + + fmt.Printf("rlp %x\n", tx.RlpEncode()) + fmt.Printf("sha rlp %x\n", tx.Hash()) + + //tx.Sign(key) + + fmt.Printf("hex tx key %x\n", tx.PublicKey()) + fmt.Printf("seder %x\n", tx.Sender()) +} diff --git a/ethdb/.gitignore b/ethdb/.gitignore new file mode 100644 index 0000000000..f725d58d14 --- /dev/null +++ b/ethdb/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethdb/README.md b/ethdb/README.md new file mode 100644 index 0000000000..5bed8eedc6 --- /dev/null +++ b/ethdb/README.md @@ -0,0 +1,11 @@ +# ethdb + +The ethdb package contains the ethereum database interfaces + +# Installation + +`go get github.com/ethereum/ethdb-go` + +# Usage + +Todo :-) diff --git a/ethdb/database.go b/ethdb/database.go new file mode 100644 index 0000000000..76e4b4e4df --- /dev/null +++ b/ethdb/database.go @@ -0,0 +1,64 @@ +package ethdb + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/syndtr/goleveldb/leveldb" + "path" +) + +type LDBDatabase struct { + db *leveldb.DB +} + +func NewLDBDatabase() (*LDBDatabase, error) { + dbPath := path.Join(ethutil.Config.ExecPath, "database") + + // Open the db + db, err := leveldb.OpenFile(dbPath, nil) + if err != nil { + return nil, err + } + + database := &LDBDatabase{db: db} + + return database, nil +} + +func (db *LDBDatabase) Put(key []byte, value []byte) { + err := db.db.Put(key, value, nil) + if err != nil { + fmt.Println("Error put", err) + } +} + +func (db *LDBDatabase) Get(key []byte) ([]byte, error) { + return db.db.Get(key, nil) +} + +func (db *LDBDatabase) LastKnownTD() []byte { + data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil) + + if len(data) == 0 { + data = []byte{0x0} + } + + return data +} + +func (db *LDBDatabase) Close() { + // Close the leveldb database + db.db.Close() +} + +func (db *LDBDatabase) Print() { + iter := db.db.NewIterator(nil) + for iter.Next() { + key := iter.Key() + value := iter.Value() + + fmt.Printf("%x(%d): ", key, len(key)) + node := ethutil.NewValueFromBytes(value) + fmt.Printf("%v\n", node) + } +} diff --git a/ethdb/database_test.go b/ethdb/database_test.go new file mode 100644 index 0000000000..bb1b4de2a0 --- /dev/null +++ b/ethdb/database_test.go @@ -0,0 +1,6 @@ +package ethdb + +import ( + _ "fmt" + _ "testing" +) diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go new file mode 100644 index 0000000000..656de9f0ef --- /dev/null +++ b/ethdb/memory_database.go @@ -0,0 +1,49 @@ +package ethdb + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" +) + +/* + * This is a test memory database. Do not use for any production it does not get persisted + */ +type MemDatabase struct { + db map[string][]byte +} + +func NewMemDatabase() (*MemDatabase, error) { + db := &MemDatabase{db: make(map[string][]byte)} + + return db, nil +} + +func (db *MemDatabase) Put(key []byte, value []byte) { + db.db[string(key)] = value +} + +func (db *MemDatabase) Get(key []byte) ([]byte, error) { + return db.db[string(key)], nil +} + +func (db *MemDatabase) Print() { + for key, val := range db.db { + fmt.Printf("%x(%d): ", key, len(key)) + dec, _ := ethutil.Decode(val, 0) + node := ethutil.Conv(dec) + fmt.Printf("%q\n", node.AsRaw()) + } +} + +func (db *MemDatabase) Close() { +} + +func (db *MemDatabase) LastKnownTD() []byte { + data, _ := db.Get([]byte("LastKnownTotalDifficulty")) + + if len(data) == 0 || data == nil { + data = []byte{0x0} + } + + return data +} diff --git a/ethereum.go b/ethereum.go index e1bc385421..9feb5a15c6 100644 --- a/ethereum.go +++ b/ethereum.go @@ -2,10 +2,10 @@ package eth import ( "container/list" - "github.com/ethereum/ethchain-go" - "github.com/ethereum/ethdb-go" - "github.com/ethereum/ethutil-go" - "github.com/ethereum/ethwire-go" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "io/ioutil" "log" "net" @@ -60,8 +60,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase() - //db, err := ethdb.NewMemDatabase() + //db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } diff --git a/ethutil/.gitignore b/ethutil/.gitignore new file mode 100644 index 0000000000..f725d58d14 --- /dev/null +++ b/ethutil/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethutil/.travil.yml b/ethutil/.travil.yml new file mode 100644 index 0000000000..69359072d9 --- /dev/null +++ b/ethutil/.travil.yml @@ -0,0 +1,3 @@ +language: go +go: + - 1.2 diff --git a/ethutil/README.md b/ethutil/README.md new file mode 100644 index 0000000000..c98612e1e3 --- /dev/null +++ b/ethutil/README.md @@ -0,0 +1,137 @@ +# ethutil + +[![Build +Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum) + +The ethutil package contains the ethereum utility library. + +# Installation + +`go get github.com/ethereum/ethutil-go` + +# Usage + +## RLP (Recursive Linear Prefix) Encoding + +RLP Encoding is an encoding scheme utilized by the Ethereum project. It +encodes any native value or list to string. + +More in depth information about the Encoding scheme see the [Wiki](http://wiki.ethereum.org/index.php/RLP) +article. + +```go +rlp := ethutil.Encode("doge") +fmt.Printf("%q\n", rlp) // => "\0x83dog" + +rlp = ethutil.Encode([]interface{}{"dog", "cat"}) +fmt.Printf("%q\n", rlp) // => "\0xc8\0x83dog\0x83cat" +decoded := ethutil.Decode(rlp) +fmt.Println(decoded) // => ["dog" "cat"] +``` + +## Patricia Trie + +Patricie Tree is a merkle trie utilized by the Ethereum project. + +More in depth information about the (modified) Patricia Trie can be +found on the [Wiki](http://wiki.ethereum.org/index.php/Patricia_Tree). + +The patricia trie uses a db as backend and could be anything as long as +it satisfies the Database interface found in `ethutil/db.go`. + +```go +db := NewDatabase() + +// db, root +trie := ethutil.NewTrie(db, "") + +trie.Put("puppy", "dog") +trie.Put("horse", "stallion") +trie.Put("do", "verb") +trie.Put("doge", "coin") + +// Look up the key "do" in the trie +out := trie.Get("do") +fmt.Println(out) // => verb +``` + +The patricia trie, in combination with RLP, provides a robust, +cryptographically authenticated data structure that can be used to store +all (key, value) bindings. + +```go +// ... Create db/trie + +// Note that RLP uses interface slices as list +value := ethutil.Encode([]interface{}{"one", 2, "three", []interface{}{42}}) +// Store the RLP encoded value of the list +trie.Put("mykey", value) +``` + +## Value + +Value is a Generic Value which is used in combination with RLP data or +`([])interface{}` structures. It may serve as a bridge between RLP data +and actual real values and takes care of all the type checking and +casting. Unlike Go's `reflect.Value` it does not panic if it's unable to +cast to the requested value. It simple returns the base value of that +type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc). + +### Creating a new Value + +`NewEmptyValue()` returns a new \*Value with it's initial value set to a +`[]interface{}` + +`AppendLint()` appends a list to the current value. + +`Append(v)` appends the value (v) to the current value/list. + +```go +val := ethutil.NewEmptyValue().Append(1).Append("2") +val.AppendList().Append(3) +``` + +### Retrieving values + +`Get(i)` returns the `i` item in the list. + +`Uint()` returns the value as an unsigned int64. + +`Slice()` returns the value as a interface slice. + +`Str()` returns the value as a string. + +`Bytes()` returns the value as a byte slice. + +`Len()` assumes current to be a slice and returns its length. + +`Byte()` returns the value as a single byte. + +```go +val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}}) +val.Get(0).Uint() // => 1 +val.Get(1).Str() // => "2" +s := val.Get(2) // => Value([]interface{}{3}) +s.Get(0).Uint() // => 3 +``` + +## Decoding + +Decoding streams of RLP data is simplified + +```go +val := ethutil.NewValueFromBytes(rlpData) +val.Get(0).Uint() +``` + +## Encoding + +Encoding from Value to RLP is done with the `Encode` method. The +underlying value can be anything RLP can encode (int, str, lists, bytes) + +```go +val := ethutil.NewValue([]interface{}{1,"2",[]interface{}{3}}) +rlp := val.Encode() +// Store the rlp data +Store(rlp) +``` diff --git a/ethutil/big.go b/ethutil/big.go new file mode 100644 index 0000000000..979078bef9 --- /dev/null +++ b/ethutil/big.go @@ -0,0 +1,37 @@ +package ethutil + +import ( + "math/big" +) + +var BigInt0 *big.Int = big.NewInt(0) + +// True +var BigTrue *big.Int = big.NewInt(1) + +// False +var BigFalse *big.Int = big.NewInt(0) + +// Returns the power of two integers +func BigPow(a, b int) *big.Int { + c := new(big.Int) + c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) + + return c +} + +// Like big.NewInt(uint64); this takes a string instead. +func Big(num string) *big.Int { + n := new(big.Int) + n.SetString(num, 0) + + return n +} + +// Like big.NewInt(uint64); this takes a byte buffer instead. +func BigD(data []byte) *big.Int { + n := new(big.Int) + n.SetBytes(data) + + return n +} diff --git a/ethutil/bytes.go b/ethutil/bytes.go new file mode 100644 index 0000000000..40903a5f17 --- /dev/null +++ b/ethutil/bytes.go @@ -0,0 +1,64 @@ +package ethutil + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +func NumberToBytes(num interface{}, bits int) []byte { + buf := new(bytes.Buffer) + err := binary.Write(buf, binary.BigEndian, num) + if err != nil { + fmt.Println("NumberToBytes failed:", err) + } + + return buf.Bytes()[buf.Len()-(bits/8):] +} + +func BytesToNumber(b []byte) uint64 { + var number uint64 + + // Make sure the buffer is 64bits + data := make([]byte, 8) + data = append(data[:len(b)], b...) + + buf := bytes.NewReader(data) + err := binary.Read(buf, binary.BigEndian, &number) + if err != nil { + fmt.Println("BytesToNumber failed:", err) + } + + return number +} + +// Read variable integer in big endian +func ReadVarint(reader *bytes.Reader) (ret uint64) { + if reader.Len() == 8 { + var num uint64 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else if reader.Len() == 4 { + var num uint32 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else if reader.Len() == 2 { + var num uint16 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } else { + var num uint8 + binary.Read(reader, binary.BigEndian, &num) + ret = uint64(num) + } + + return ret +} + +func BinaryLength(num int) int { + if num == 0 { + return 0 + } + + return 1 + BinaryLength(num>>8) +} diff --git a/ethutil/config.go b/ethutil/config.go new file mode 100644 index 0000000000..7782e7daad --- /dev/null +++ b/ethutil/config.go @@ -0,0 +1,106 @@ +package ethutil + +import ( + "log" + "os" + "os/user" + "path" +) + +type LogType byte + +const ( + LogTypeStdIn = 1 + LogTypeFile = 2 +) + +// Config struct isn't exposed +type config struct { + Db Database + + Log Logger + ExecPath string + Debug bool + Ver string + Pubkey []byte + Seed bool +} + +var Config *config + +// Read config doesn't read anything yet. +func ReadConfig(base string) *config { + if Config == nil { + usr, _ := user.Current() + path := path.Join(usr.HomeDir, base) + + //Check if the logging directory already exists, create it if not + _, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it", path) + os.Mkdir(path, 0777) + } + } + + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.1"} + Config.Log = NewLogger(LogFile|LogStd, 0) + } + + return Config +} + +type LoggerType byte + +const ( + LogFile = 0x1 + LogStd = 0x2 +) + +type Logger struct { + logSys []*log.Logger + logLevel int +} + +func NewLogger(flag LoggerType, level int) Logger { + var loggers []*log.Logger + + flags := log.LstdFlags | log.Lshortfile + + if flag&LogFile > 0 { + file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) + if err != nil { + log.Panic("unable to create file logger", err) + } + + log := log.New(file, "[ETH]", flags) + + loggers = append(loggers, log) + } + if flag&LogStd > 0 { + log := log.New(os.Stdout, "[ETH]", flags) + loggers = append(loggers, log) + } + + return Logger{logSys: loggers, logLevel: level} +} + +func (log Logger) Debugln(v ...interface{}) { + if log.logLevel != 0 { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log Logger) Debugf(format string, v ...interface{}) { + if log.logLevel != 0 { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} diff --git a/ethutil/db.go b/ethutil/db.go new file mode 100644 index 0000000000..3681c4b058 --- /dev/null +++ b/ethutil/db.go @@ -0,0 +1,10 @@ +package ethutil + +// Database interface +type Database interface { + Put(key []byte, value []byte) + Get(key []byte) ([]byte, error) + LastKnownTD() []byte + Close() + Print() +} diff --git a/ethutil/encoding.go b/ethutil/encoding.go new file mode 100644 index 0000000000..207548c933 --- /dev/null +++ b/ethutil/encoding.go @@ -0,0 +1,62 @@ +package ethutil + +import ( + "bytes" + "encoding/hex" + _ "fmt" + "strings" +) + +func CompactEncode(hexSlice []int) string { + terminator := 0 + if hexSlice[len(hexSlice)-1] == 16 { + terminator = 1 + } + + if terminator == 1 { + hexSlice = hexSlice[:len(hexSlice)-1] + } + + oddlen := len(hexSlice) % 2 + flags := 2*terminator + oddlen + if oddlen != 0 { + hexSlice = append([]int{flags}, hexSlice...) + } else { + hexSlice = append([]int{flags, 0}, hexSlice...) + } + + var buff bytes.Buffer + for i := 0; i < len(hexSlice); i += 2 { + buff.WriteByte(byte(16*hexSlice[i] + hexSlice[i+1])) + } + + return buff.String() +} + +func CompactDecode(str string) []int { + base := CompactHexDecode(str) + base = base[:len(base)-1] + if base[0] >= 2 { // && base[len(base)-1] != 16 { + base = append(base, 16) + } + if base[0]%2 == 1 { + base = base[1:] + } else { + base = base[2:] + } + + return base +} + +func CompactHexDecode(str string) []int { + base := "0123456789abcdef" + hexSlice := make([]int, 0) + + enc := hex.EncodeToString([]byte(str)) + for _, v := range enc { + hexSlice = append(hexSlice, strings.IndexByte(base, byte(v))) + } + hexSlice = append(hexSlice, 16) + + return hexSlice +} diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go new file mode 100644 index 0000000000..bcabab0b19 --- /dev/null +++ b/ethutil/encoding_test.go @@ -0,0 +1,37 @@ +package ethutil + +import ( + "fmt" + "testing" +) + +func TestCompactEncode(t *testing.T) { + test1 := []int{1, 2, 3, 4, 5} + if res := CompactEncode(test1); res != "\x11\x23\x45" { + t.Error(fmt.Sprintf("even compact encode failed. Got: %q", res)) + } + + test2 := []int{0, 1, 2, 3, 4, 5} + if res := CompactEncode(test2); res != "\x00\x01\x23\x45" { + t.Error(fmt.Sprintf("odd compact encode failed. Got: %q", res)) + } + + test3 := []int{0, 15, 1, 12, 11, 8 /*term*/, 16} + if res := CompactEncode(test3); res != "\x20\x0f\x1c\xb8" { + t.Error(fmt.Sprintf("odd terminated compact encode failed. Got: %q", res)) + } + + test4 := []int{15, 1, 12, 11, 8 /*term*/, 16} + if res := CompactEncode(test4); res != "\x3f\x1c\xb8" { + t.Error(fmt.Sprintf("even terminated compact encode failed. Got: %q", res)) + } +} + +func TestCompactHexDecode(t *testing.T) { + exp := []int{7, 6, 6, 5, 7, 2, 6, 2, 16} + res := CompactHexDecode("verb") + + if !CompareIntSlice(res, exp) { + t.Error("Error compact hex decode. Expected", exp, "got", res) + } +} diff --git a/ethutil/helpers.go b/ethutil/helpers.go new file mode 100644 index 0000000000..1c6adf2569 --- /dev/null +++ b/ethutil/helpers.go @@ -0,0 +1,61 @@ +package ethutil + +import ( + "code.google.com/p/go.crypto/ripemd160" + "crypto/sha256" + "encoding/hex" + "github.com/obscuren/sha3" + "strconv" +) + +func Uitoa(i uint32) string { + return strconv.FormatUint(uint64(i), 10) +} + +func Sha256Bin(data []byte) []byte { + hash := sha256.Sum256(data) + + return hash[:] +} + +func Ripemd160(data []byte) []byte { + ripemd := ripemd160.New() + ripemd.Write(data) + + return ripemd.Sum(nil) +} + +func Sha3Bin(data []byte) []byte { + d := sha3.NewKeccak256() + d.Reset() + d.Write(data) + + return d.Sum(nil) +} + +// Helper function for comparing slices +func CompareIntSlice(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +// Returns the amount of nibbles that match each other from 0 ... +func MatchingNibbleLength(a, b []int) int { + i := 0 + for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { + i += 1 + } + + return i +} + +func Hex(d []byte) string { + return hex.EncodeToString(d) +} diff --git a/ethutil/parsing.go b/ethutil/parsing.go new file mode 100644 index 0000000000..2c41fb4df2 --- /dev/null +++ b/ethutil/parsing.go @@ -0,0 +1,108 @@ +package ethutil + +import ( + "errors" + "fmt" + "math/big" + "strconv" + "strings" +) + +// Op codes +var OpCodes = map[string]string{ + "STOP": "0", + "ADD": "1", + "MUL": "2", + "SUB": "3", + "DIV": "4", + "SDIV": "5", + "MOD": "6", + "SMOD": "7", + "EXP": "8", + "NEG": "9", + "LT": "10", + "LE": "11", + "GT": "12", + "GE": "13", + "EQ": "14", + "NOT": "15", + "MYADDRESS": "16", + "TXSENDER": "17", + + "PUSH": "48", + "POP": "49", + "LOAD": "54", +} + +func CompileInstr(s string) (string, error) { + tokens := strings.Split(s, " ") + if OpCodes[tokens[0]] == "" { + return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0])) + } + + code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent + op := new(big.Int) + op.SetString(code, 0) + + args := make([]*big.Int, 6) + for i, val := range tokens[1:len(tokens)] { + num := new(big.Int) + num.SetString(val, 0) + args[i] = num + } + + // Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6 + base := new(big.Int) + x := new(big.Int) + y := new(big.Int) + z := new(big.Int) + a := new(big.Int) + b := new(big.Int) + c := new(big.Int) + + if args[0] != nil { + x.Mul(args[0], big.NewInt(256)) + } + if args[1] != nil { + y.Mul(args[1], BigPow(256, 2)) + } + if args[2] != nil { + z.Mul(args[2], BigPow(256, 3)) + } + if args[3] != nil { + a.Mul(args[3], BigPow(256, 4)) + } + if args[4] != nil { + b.Mul(args[4], BigPow(256, 5)) + } + if args[5] != nil { + c.Mul(args[5], BigPow(256, 6)) + } + + base.Add(op, x) + base.Add(base, y) + base.Add(base, z) + base.Add(base, a) + base.Add(base, b) + base.Add(base, c) + + return base.String(), nil +} + +func Instr(instr string) (int, []string, error) { + base := new(big.Int) + base.SetString(instr, 0) + + args := make([]string, 7) + for i := 0; i < 7; i++ { + // int(int(val) / int(math.Pow(256,float64(i)))) % 256 + exp := BigPow(256, i) + num := new(big.Int) + num.Div(base, exp) + + args[i] = num.Mod(num, big.NewInt(256)).String() + } + op, _ := strconv.Atoi(args[0]) + + return op, args[1:7], nil +} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go new file mode 100644 index 0000000000..482eef3ee8 --- /dev/null +++ b/ethutil/parsing_test.go @@ -0,0 +1,32 @@ +package ethutil + +import ( + "math" + "testing" +) + +func TestCompile(t *testing.T) { + instr, err := CompileInstr("PUSH") + + if err != nil { + t.Error("Failed compiling instruction") + } + + calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) + if Big(instr).Int64() != calc { + t.Error("Expected", calc, ", got:", instr) + } +} + +func TestValidInstr(t *testing.T) { + /* + op, args, err := Instr("68163") + if err != nil { + t.Error("Error decoding instruction") + } + */ + +} + +func TestInvalidInstr(t *testing.T) { +} diff --git a/ethutil/rand.go b/ethutil/rand.go new file mode 100644 index 0000000000..91dafec7ed --- /dev/null +++ b/ethutil/rand.go @@ -0,0 +1,24 @@ +package ethutil + +import ( + "crypto/rand" + "encoding/binary" + "io" +) + +func randomUint64(r io.Reader) (uint64, error) { + b := make([]byte, 8) + n, err := r.Read(b) + if n != len(b) { + return 0, io.ErrShortBuffer + } + if err != nil { + return 0, err + } + return binary.BigEndian.Uint64(b), nil +} + +// RandomUint64 returns a cryptographically random uint64 value. +func RandomUint64() (uint64, error) { + return randomUint64(rand.Reader) +} diff --git a/ethutil/rlp.go b/ethutil/rlp.go new file mode 100644 index 0000000000..0f88933b3e --- /dev/null +++ b/ethutil/rlp.go @@ -0,0 +1,418 @@ +package ethutil + +import ( + "bytes" + _ "encoding/binary" + "fmt" + _ "log" + _ "math" + "math/big" + "reflect" +) + +/////////////////////////////////////// +type EthEncoder interface { + EncodeData(rlpData interface{}) []byte +} +type EthDecoder interface { + Get(idx int) *RlpValue +} + +////////////////////////////////////// + +type RlpEncoder struct { + rlpData []byte +} + +func NewRlpEncoder() *RlpEncoder { + encoder := &RlpEncoder{} + + return encoder +} +func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { + return Encode(rlpData) +} + +// Data rlpValueutes are returned by the rlp decoder. The data rlpValueutes represents +// one item within the rlp data structure. It's responsible for all the casting +// It always returns something rlpValueid +type RlpValue struct { + Value interface{} + kind reflect.Value +} + +func (rlpValue *RlpValue) String() string { + return fmt.Sprintf("%q", rlpValue.Value) +} + +func Conv(rlpValue interface{}) *RlpValue { + return &RlpValue{Value: rlpValue, kind: reflect.ValueOf(rlpValue)} +} + +func NewRlpValue(rlpValue interface{}) *RlpValue { + return &RlpValue{Value: rlpValue} +} + +func (rlpValue *RlpValue) Type() reflect.Kind { + return reflect.TypeOf(rlpValue.Value).Kind() +} + +func (rlpValue *RlpValue) IsNil() bool { + return rlpValue.Value == nil +} + +func (rlpValue *RlpValue) Length() int { + //return rlpValue.kind.Len() + if data, ok := rlpValue.Value.([]interface{}); ok { + return len(data) + } + + return 0 +} + +func (rlpValue *RlpValue) AsRaw() interface{} { + return rlpValue.Value +} + +func (rlpValue *RlpValue) AsUint() uint64 { + if Value, ok := rlpValue.Value.(uint8); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint16); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint32); ok { + return uint64(Value) + } else if Value, ok := rlpValue.Value.(uint64); ok { + return Value + } + + return 0 +} + +func (rlpValue *RlpValue) AsByte() byte { + if Value, ok := rlpValue.Value.(byte); ok { + return Value + } + + return 0x0 +} + +func (rlpValue *RlpValue) AsBigInt() *big.Int { + if a, ok := rlpValue.Value.([]byte); ok { + b := new(big.Int) + b.SetBytes(a) + return b + } + + return big.NewInt(0) +} + +func (rlpValue *RlpValue) AsString() string { + if a, ok := rlpValue.Value.([]byte); ok { + return string(a) + } else if a, ok := rlpValue.Value.(string); ok { + return a + } else { + //panic(fmt.Sprintf("not string %T: %v", rlpValue.Value, rlpValue.Value)) + } + + return "" +} + +func (rlpValue *RlpValue) AsBytes() []byte { + if a, ok := rlpValue.Value.([]byte); ok { + return a + } + + return make([]byte, 0) +} + +func (rlpValue *RlpValue) AsSlice() []interface{} { + if d, ok := rlpValue.Value.([]interface{}); ok { + return d + } + + return []interface{}{} +} + +func (rlpValue *RlpValue) AsSliceFrom(from int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[from:]) +} + +func (rlpValue *RlpValue) AsSliceTo(to int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[:to]) +} + +func (rlpValue *RlpValue) AsSliceFromTo(from, to int) *RlpValue { + slice := rlpValue.AsSlice() + + return NewRlpValue(slice[from:to]) +} + +// Threat the rlpValueute as a slice +func (rlpValue *RlpValue) Get(idx int) *RlpValue { + if d, ok := rlpValue.Value.([]interface{}); ok { + // Guard for oob + if len(d) <= idx { + return NewRlpValue(nil) + } + + if idx < 0 { + panic("negative idx for Rlp Get") + } + + return NewRlpValue(d[idx]) + } + + // If this wasn't a slice you probably shouldn't be using this function + return NewRlpValue(nil) +} + +func (rlpValue *RlpValue) Cmp(o *RlpValue) bool { + return reflect.DeepEqual(rlpValue.Value, o.Value) +} + +func (rlpValue *RlpValue) Encode() []byte { + return Encode(rlpValue.Value) +} + +func NewRlpValueFromBytes(rlpData []byte) *RlpValue { + if len(rlpData) != 0 { + data, _ := Decode(rlpData, 0) + return NewRlpValue(data) + } + + return NewRlpValue(nil) +} + +// RlpValue value setters +// An empty rlp value is always a list +func EmptyRlpValue() *RlpValue { + return NewRlpValue([]interface{}{}) +} + +func (rlpValue *RlpValue) AppendList() *RlpValue { + list := EmptyRlpValue() + rlpValue.Value = append(rlpValue.AsSlice(), list) + + return list +} + +func (rlpValue *RlpValue) Append(v interface{}) *RlpValue { + rlpValue.Value = append(rlpValue.AsSlice(), v) + + return rlpValue +} + +/* +func FromBin(data []byte) uint64 { + if len(data) == 0 { + return 0 + } + + return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) +} +*/ + +const ( + RlpEmptyList = 0x80 + RlpEmptyStr = 0x40 +) + +func Char(c []byte) int { + if len(c) > 0 { + return int(c[0]) + } + + return 0 +} + +func DecodeWithReader(reader *bytes.Buffer) interface{} { + var slice []interface{} + + // Read the next byte + char := Char(reader.Next(1)) + switch { + case char == 0: + return nil + case char <= 0x7c: + return char + + case char <= 0xb7: + return reader.Next(int(char - 0x80)) + + case char <= 0xbf: + buff := bytes.NewReader(reader.Next(int(char - 0xb8))) + length := ReadVarint(buff) + + return reader.Next(int(length)) + + case char <= 0xf7: + length := int(char - 0xc0) + for i := 0; i < length; i++ { + obj := DecodeWithReader(reader) + if obj != nil { + slice = append(slice, obj) + } else { + break + } + } + + return slice + + } + + return slice +} + +// TODO Use a bytes.Buffer instead of a raw byte slice. +// Cleaner code, and use draining instead of seeking the next bytes to read +func Decode(data []byte, pos uint64) (interface{}, uint64) { + /* + if pos > uint64(len(data)-1) { + log.Println(data) + log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data)) + } + */ + + var slice []interface{} + char := int(data[pos]) + switch { + case char <= 0x7f: + return data[pos], pos + 1 + + case char <= 0xb7: + b := uint64(data[pos]) - 0x80 + + return data[pos+1 : pos+1+b], pos + 1 + b + + case char <= 0xbf: + b := uint64(data[pos]) - 0xb7 + + b2 := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+b])) + + return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 + + case char <= 0xf7: + b := uint64(data[pos]) - 0xc0 + prevPos := pos + pos++ + for i := uint64(0); i < b; { + var obj interface{} + + // Get the next item in the data list and append it + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + // Increment i by the amount bytes read in the previous + // read + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + case char <= 0xff: + l := uint64(data[pos]) - 0xf7 + //b := BigD(data[pos+1 : pos+1+l]).Uint64() + b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) + + pos = pos + l + 1 + + prevPos := b + for i := uint64(0); i < uint64(b); { + var obj interface{} + + obj, prevPos = Decode(data, pos) + slice = append(slice, obj) + + i += (prevPos - pos) + pos = prevPos + } + return slice, pos + + default: + panic(fmt.Sprintf("byte not supported: %q", char)) + } + + return slice, 0 +} + +var ( + directRlp = big.NewInt(0x7f) + numberRlp = big.NewInt(0xb7) + zeroRlp = big.NewInt(0x0) +) + +func Encode(object interface{}) []byte { + var buff bytes.Buffer + + if object != nil { + switch t := object.(type) { + case *RlpValue: + buff.Write(Encode(t.AsRaw())) + // Code dup :-/ + case int: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint: + buff.Write(Encode(big.NewInt(int64(t)))) + case int8: + buff.Write(Encode(big.NewInt(int64(t)))) + case int16: + buff.Write(Encode(big.NewInt(int64(t)))) + case int32: + buff.Write(Encode(big.NewInt(int64(t)))) + case int64: + buff.Write(Encode(big.NewInt(t))) + case uint16: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint32: + buff.Write(Encode(big.NewInt(int64(t)))) + case uint64: + buff.Write(Encode(big.NewInt(int64(t)))) + case byte: + buff.Write(Encode(big.NewInt(int64(t)))) + case *big.Int: + buff.Write(Encode(t.Bytes())) + case []byte: + if len(t) == 1 && t[0] <= 0x7f { + buff.Write(t) + } else if len(t) < 56 { + buff.WriteByte(byte(len(t) + 0x80)) + buff.Write(t) + } else { + b := big.NewInt(int64(len(t))) + buff.WriteByte(byte(len(b.Bytes()) + 0xb7)) + buff.Write(b.Bytes()) + buff.Write(t) + } + case string: + buff.Write(Encode([]byte(t))) + case []interface{}: + // Inline function for writing the slice header + WriteSliceHeader := func(length int) { + if length < 56 { + buff.WriteByte(byte(length + 0xc0)) + } else { + b := big.NewInt(int64(length)) + buff.WriteByte(byte(len(b.Bytes()) + 0xf7)) + buff.Write(b.Bytes()) + } + } + + var b bytes.Buffer + for _, val := range t { + b.Write(Encode(val)) + } + WriteSliceHeader(len(b.Bytes())) + buff.Write(b.Bytes()) + } + } else { + // Empty list for nil + buff.WriteByte(0xc0) + } + + return buff.Bytes() +} diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go new file mode 100644 index 0000000000..32bcbdce1d --- /dev/null +++ b/ethutil/rlp_test.go @@ -0,0 +1,170 @@ +package ethutil + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/big" + "reflect" + "testing" +) + +func TestRlpValueEncoding(t *testing.T) { + val := EmptyRlpValue() + val.AppendList().Append(1).Append(2).Append(3) + val.Append("4").AppendList().Append(5) + + res := val.Encode() + exp := Encode([]interface{}{[]interface{}{1, 2, 3}, "4", []interface{}{5}}) + if bytes.Compare(res, exp) != 0 { + t.Errorf("expected %q, got %q", res, exp) + } +} + +func TestValueSlice(t *testing.T) { + val := []interface{}{ + "value1", + "valeu2", + "value3", + } + + value := NewValue(val) + splitVal := value.SliceFrom(1) + + if splitVal.Len() != 2 { + t.Error("SliceFrom: Expected len", 2, "got", splitVal.Len()) + } + + splitVal = value.SliceTo(2) + if splitVal.Len() != 2 { + t.Error("SliceTo: Expected len", 2, "got", splitVal.Len()) + } + + splitVal = value.SliceFromTo(1, 3) + if splitVal.Len() != 2 { + t.Error("SliceFromTo: Expected len", 2, "got", splitVal.Len()) + } +} + +func TestValue(t *testing.T) { + value := NewValueFromBytes([]byte("\xcd\x83dog\x83god\x83cat\x01")) + if value.Get(0).Str() != "dog" { + t.Errorf("expected '%v', got '%v'", value.Get(0).Str(), "dog") + } + + if value.Get(3).Uint() != 1 { + t.Errorf("expected '%v', got '%v'", value.Get(3).Uint(), 1) + } +} + +func TestEncode(t *testing.T) { + strRes := "\x83dog" + bytes := Encode("dog") + + str := string(bytes) + if str != strRes { + t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + } + + sliceRes := "\xcc\x83dog\x83god\x83cat" + strs := []interface{}{"dog", "god", "cat"} + bytes = Encode(strs) + slice := string(bytes) + if slice != sliceRes { + t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + } + + intRes := "\x82\x04\x00" + bytes = Encode(1024) + if string(bytes) != intRes { + t.Errorf("Expected %q, got %q", intRes, bytes) + } +} + +func TestDecode(t *testing.T) { + single := []byte("\x01") + b, _ := Decode(single, 0) + + if b.(uint8) != 1 { + t.Errorf("Expected 1, got %q", b) + } + + str := []byte("\x83dog") + b, _ = Decode(str, 0) + if bytes.Compare(b.([]byte), []byte("dog")) != 0 { + t.Errorf("Expected dog, got %q", b) + } + + slice := []byte("\xcc\x83dog\x83god\x83cat") + res := []interface{}{"dog", "god", "cat"} + b, _ = Decode(slice, 0) + if reflect.DeepEqual(b, res) { + t.Errorf("Expected %q, got %q", res, b) + } +} + +func TestEncodeDecodeBigInt(t *testing.T) { + bigInt := big.NewInt(1391787038) + encoded := Encode(bigInt) + + value := NewValueFromBytes(encoded) + fmt.Println(value.BigInt(), bigInt) + if value.BigInt().Cmp(bigInt) != 0 { + t.Errorf("Expected %v, got %v", bigInt, value.BigInt()) + } + + dec, _ := hex.DecodeString("52f4fc1e") + fmt.Println(NewValueFromBytes(dec).BigInt()) +} + +func TestEncodeDecodeBytes(t *testing.T) { + b := NewValue([]interface{}{[]byte{1, 2, 3, 4, 5}, byte(6)}) + val := NewValueFromBytes(b.Encode()) + if !b.Cmp(val) { + t.Errorf("Expected %v, got %v", val, b) + } +} + +/* +var ZeroHash256 = make([]byte, 32) +var ZeroHash160 = make([]byte, 20) +var EmptyShaList = Sha3Bin(Encode([]interface{}{})) + +var GenisisHeader = []interface{}{ + // Previous hash (none) + //"", + ZeroHash256, + // Sha of uncles + Sha3Bin(Encode([]interface{}{})), + // Coinbase + ZeroHash160, + // Root state + "", + // Sha of transactions + //EmptyShaList, + Sha3Bin(Encode([]interface{}{})), + // Difficulty + BigPow(2, 22), + // Time + //big.NewInt(0), + int64(0), + // extra + "", + // Nonce + big.NewInt(42), +} + +func TestEnc(t *testing.T) { + //enc := Encode(GenisisHeader) + //fmt.Printf("%x (%d)\n", enc, len(enc)) + h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a") + fmt.Printf("%x\n", Sha3Bin(h)) +} +*/ + +func BenchmarkEncodeDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + bytes := Encode([]interface{}{"dog", "god", "cat"}) + Decode(bytes, 0) + } +} diff --git a/ethutil/trie.go b/ethutil/trie.go new file mode 100644 index 0000000000..44d2d5774a --- /dev/null +++ b/ethutil/trie.go @@ -0,0 +1,354 @@ +package ethutil + +import ( + "fmt" + "reflect" +) + +type Node struct { + Key []byte + Value *Value + Dirty bool +} + +func NewNode(key []byte, val *Value, dirty bool) *Node { + return &Node{Key: key, Value: val, Dirty: dirty} +} + +func (n *Node) Copy() *Node { + return NewNode(n.Key, n.Value, n.Dirty) +} + +type Cache struct { + nodes map[string]*Node + db Database +} + +func NewCache(db Database) *Cache { + return &Cache{db: db, nodes: make(map[string]*Node)} +} + +func (cache *Cache) Put(v interface{}) interface{} { + value := NewValue(v) + + enc := value.Encode() + if len(enc) >= 32 { + sha := Sha3Bin(enc) + + cache.nodes[string(sha)] = NewNode(sha, value, true) + + return sha + } + + return v +} + +func (cache *Cache) Get(key []byte) *Value { + // First check if the key is the cache + if cache.nodes[string(key)] != nil { + return cache.nodes[string(key)].Value + } + + // Get the key of the database instead and cache it + data, _ := cache.db.Get(key) + // Create the cached value + value := NewValueFromBytes(data) + // Create caching node + cache.nodes[string(key)] = NewNode(key, value, false) + + return value +} + +func (cache *Cache) Commit() { + for key, node := range cache.nodes { + if node.Dirty { + cache.db.Put([]byte(key), node.Value.Encode()) + node.Dirty = false + } + } + + // If the nodes grows beyond the 200 entries we simple empty it + // FIXME come up with something better + if len(cache.nodes) > 200 { + cache.nodes = make(map[string]*Node) + } +} + +func (cache *Cache) Undo() { + for key, node := range cache.nodes { + if node.Dirty { + delete(cache.nodes, key) + } + } +} + +// A (modified) Radix Trie implementation +type Trie struct { + Root interface{} + //db Database + cache *Cache +} + +func NewTrie(db Database, Root interface{}) *Trie { + return &Trie{cache: NewCache(db), Root: Root} +} + +func (t *Trie) Sync() { + t.cache.Commit() +} + +/* + * Public (query) interface functions + */ +func (t *Trie) Update(key string, value string) { + k := CompactHexDecode(key) + + t.Root = t.UpdateState(t.Root, k, value) +} + +func (t *Trie) Get(key string) string { + k := CompactHexDecode(key) + c := NewValue(t.GetState(t.Root, k)) + + return c.Str() +} + +func (t *Trie) GetState(node interface{}, key []int) interface{} { + n := NewValue(node) + // Return the node if key is empty (= found) + if len(key) == 0 || n.IsNil() || n.Len() == 0 { + return node + } + + currentNode := t.GetNode(node) + length := currentNode.Len() + + if length == 0 { + return "" + } else if length == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + if len(key) >= len(k) && CompareIntSlice(k, key[:len(k)]) { + return t.GetState(v, key[len(k):]) + } else { + return "" + } + } else if length == 17 { + return t.GetState(currentNode.Get(key[0]).Raw(), key[1:]) + } + + // It shouldn't come this far + fmt.Println("GetState unexpected return") + return "" +} + +func (t *Trie) GetNode(node interface{}) *Value { + n := NewValue(node) + + if !n.Get(0).IsNil() { + return n + } + + str := n.Str() + if len(str) == 0 { + return n + } else if len(str) < 32 { + return NewValueFromBytes([]byte(str)) + } + /* + else { + // Fetch the encoded node from the db + o, err := t.db.Get(n.Bytes()) + if err != nil { + fmt.Println("Error InsertState", err) + return NewValue("") + } + + return NewValueFromBytes(o) + } + */ + return t.cache.Get(n.Bytes()) + +} + +func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { + if value != "" { + return t.InsertState(node, key, value) + } else { + // delete it + } + + return "" +} + +func (t *Trie) Put(node interface{}) interface{} { + /* + enc := Encode(node) + if len(enc) >= 32 { + var sha []byte + sha = Sha3Bin(enc) + //t.db.Put([]byte(sha), enc) + + return sha + } + return node + */ + + /* + TODO? + c := Conv(t.Root) + fmt.Println(c.Type(), c.Length()) + if c.Type() == reflect.String && c.AsString() == "" { + return enc + } + */ + + return t.cache.Put(node) + +} + +func EmptyStringSlice(l int) []interface{} { + slice := make([]interface{}, l) + for i := 0; i < l; i++ { + slice[i] = "" + } + return slice +} + +func (t *Trie) InsertState(node interface{}, key []int, value interface{}) interface{} { + if len(key) == 0 { + return value + } + + // New node + n := NewValue(node) + 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) + } + + currentNode := t.GetNode(node) + // Check for "special" 2 slice type node + if currentNode.Len() == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + // Matching key pair (ie. there's already an object with this key) + if CompareIntSlice(k, key) { + newNode := []interface{}{CompactEncode(key), value} + return t.Put(newNode) + } + + var newHash interface{} + matchingLength := MatchingNibbleLength(key, k) + if matchingLength == len(k) { + // Insert the hash, creating a new node + newHash = t.InsertState(v, key[matchingLength:], value) + } else { + // Expand the 2 length slice to a 17 length slice + oldNode := t.InsertState("", k[matchingLength+1:], v) + newNode := t.InsertState("", key[matchingLength+1:], value) + // Create an expanded slice + scaledSlice := EmptyStringSlice(17) + // Set the copied and new node + scaledSlice[k[matchingLength]] = oldNode + scaledSlice[key[matchingLength]] = newNode + + newHash = t.Put(scaledSlice) + } + + if matchingLength == 0 { + // End of the chain, return + return newHash + } else { + newNode := []interface{}{CompactEncode(key[:matchingLength]), newHash} + return t.Put(newNode) + } + } else { + + // Copy the current node over to the new node and replace the first nibble in the key + newNode := EmptyStringSlice(17) + + for i := 0; i < 17; i++ { + cpy := currentNode.Get(i).Raw() + if cpy != nil { + newNode[i] = cpy + } + } + + newNode[key[0]] = t.InsertState(currentNode.Get(key[0]).Raw(), key[1:], value) + + return t.Put(newNode) + } + + return "" +} + +// Simple compare function which creates a rlp value out of the evaluated objects +func (t *Trie) Cmp(trie *Trie) bool { + return NewValue(t.Root).Cmp(NewValue(trie.Root)) +} + +// Returns a copy of this trie +func (t *Trie) Copy() *Trie { + trie := NewTrie(t.cache.db, t.Root) + for key, node := range t.cache.nodes { + trie.cache.nodes[key] = node.Copy() + } + + return trie +} + +/* + * Trie helper functions + */ +// Helper function for printing out the raw contents of a slice +func PrintSlice(slice []string) { + fmt.Printf("[") + for i, val := range slice { + fmt.Printf("%q", val) + if i != len(slice)-1 { + fmt.Printf(",") + } + } + fmt.Printf("]\n") +} + +func PrintSliceT(slice interface{}) { + c := Conv(slice) + for i := 0; i < c.Length(); i++ { + val := c.Get(i) + if val.Type() == reflect.Slice { + PrintSliceT(val.AsRaw()) + } else { + fmt.Printf("%q", val) + if i != c.Length()-1 { + fmt.Printf(",") + } + } + } +} + +// RLP Decodes a node in to a [2] or [17] string slice +func DecodeNode(data []byte) []string { + dec, _ := Decode(data, 0) + if slice, ok := dec.([]interface{}); ok { + strSlice := make([]string, len(slice)) + + for i, s := range slice { + if str, ok := s.([]byte); ok { + strSlice[i] = string(str) + } + } + + return strSlice + } else { + fmt.Printf("It wasn't a []. It's a %T\n", dec) + } + + return nil +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go new file mode 100644 index 0000000000..b87d35e1ab --- /dev/null +++ b/ethutil/trie_test.go @@ -0,0 +1,40 @@ +package ethutil + +import ( + _ "encoding/hex" + _ "fmt" + "testing" +) + +type MemDatabase struct { + db map[string][]byte +} + +func NewMemDatabase() (*MemDatabase, error) { + db := &MemDatabase{db: make(map[string][]byte)} + return db, nil +} +func (db *MemDatabase) Put(key []byte, value []byte) { + db.db[string(key)] = value +} +func (db *MemDatabase) Get(key []byte) ([]byte, error) { + return db.db[string(key)], nil +} +func (db *MemDatabase) Print() {} +func (db *MemDatabase) Close() {} +func (db *MemDatabase) LastKnownTD() []byte { return nil } + +func TestTrieSync(t *testing.T) { + db, _ := NewMemDatabase() + trie := NewTrie(db, "") + + trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety") + if len(db.db) != 0 { + t.Error("Expected no data in database") + } + + trie.Sync() + if len(db.db) == 0 { + t.Error("Expected data to be persisted") + } +} diff --git a/ethutil/value.go b/ethutil/value.go new file mode 100644 index 0000000000..2a990783e0 --- /dev/null +++ b/ethutil/value.go @@ -0,0 +1,204 @@ +package ethutil + +import ( + "bytes" + "fmt" + "math/big" + "reflect" +) + +// Data values are returned by the rlp decoder. The data values represents +// one item within the rlp data structure. It's responsible for all the casting +// It always returns something valid +type Value struct { + Val interface{} + kind reflect.Value +} + +func (val *Value) String() string { + return fmt.Sprintf("%q", val.Val) +} + +func NewValue(val interface{}) *Value { + return &Value{Val: val} +} + +func (val *Value) Type() reflect.Kind { + return reflect.TypeOf(val.Val).Kind() +} + +func (val *Value) IsNil() bool { + return val.Val == nil +} + +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 { + // FIXME + return len(data) + } + + return 0 +} + +func (val *Value) Raw() interface{} { + return val.Val +} + +func (val *Value) Interface() interface{} { + return val.Val +} + +func (val *Value) Uint() uint64 { + if Val, ok := val.Val.(uint8); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint16); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint32); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint64); ok { + return Val + } else if Val, ok := val.Val.([]byte); ok { + return ReadVarint(bytes.NewReader(Val)) + } + + return 0 +} + +func (val *Value) Byte() byte { + if Val, ok := val.Val.(byte); ok { + return Val + } + + return 0x0 +} + +func (val *Value) BigInt() *big.Int { + if a, ok := val.Val.([]byte); ok { + b := new(big.Int).SetBytes(a) + + return b + } else { + return big.NewInt(int64(val.Uint())) + } + + return big.NewInt(0) +} + +func (val *Value) Str() string { + if a, ok := val.Val.([]byte); ok { + return string(a) + } else if a, ok := val.Val.(string); ok { + return a + } + + return "" +} + +func (val *Value) Bytes() []byte { + if a, ok := val.Val.([]byte); ok { + return a + } + + return make([]byte, 0) +} + +func (val *Value) Slice() []interface{} { + if d, ok := val.Val.([]interface{}); ok { + return d + } + + return []interface{}{} +} + +func (val *Value) SliceFrom(from int) *Value { + slice := val.Slice() + + return NewValue(slice[from:]) +} + +func (val *Value) SliceTo(to int) *Value { + slice := val.Slice() + + return NewValue(slice[:to]) +} + +func (val *Value) SliceFromTo(from, to int) *Value { + slice := val.Slice() + + return NewValue(slice[from:to]) +} + +// Threat the value as a slice +func (val *Value) Get(idx int) *Value { + if d, ok := val.Val.([]interface{}); ok { + // Guard for oob + if len(d) <= idx { + return NewValue(nil) + } + + if idx < 0 { + panic("negative idx for Rlp Get") + } + + return NewValue(d[idx]) + } + + // If this wasn't a slice you probably shouldn't be using this function + return NewValue(nil) +} + +func (val *Value) Cmp(o *Value) bool { + return reflect.DeepEqual(val.Val, o.Val) +} + +func (val *Value) Encode() []byte { + return Encode(val.Val) +} + +func NewValueFromBytes(rlpData []byte) *Value { + if len(rlpData) != 0 { + data, _ := Decode(rlpData, 0) + return NewValue(data) + } + + return NewValue(nil) +} + +// Value setters +func NewSliceValue(s interface{}) *Value { + list := EmptyValue() + + if s != nil { + if slice, ok := s.([]interface{}); ok { + for _, val := range slice { + list.Append(val) + } + } else if slice, ok := s.([]string); ok { + for _, val := range slice { + list.Append(val) + } + } + } + + return list +} + +func EmptyValue() *Value { + return NewValue([]interface{}{}) +} + +func (val *Value) AppendList() *Value { + list := EmptyValue() + val.Val = append(val.Slice(), list) + + return list +} + +func (val *Value) Append(v interface{}) *Value { + val.Val = append(val.Slice(), v) + + return val +} diff --git a/ethwire/.gitignore b/ethwire/.gitignore new file mode 100644 index 0000000000..f725d58d14 --- /dev/null +++ b/ethwire/.gitignore @@ -0,0 +1,12 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile ~/.gitignore_global + +/tmp +*/**/*un~ +*un~ +.DS_Store +*/**/.DS_Store + diff --git a/ethwire/README.md b/ethwire/README.md new file mode 100644 index 0000000000..7f63688b3c --- /dev/null +++ b/ethwire/README.md @@ -0,0 +1,36 @@ +# ethwire + +The ethwire package contains the ethereum wire protocol. The ethwire +package is required to write and read from the ethereum network. + +# Installation + +`go get github.com/ethereum/ethwire-go` + +# Messaging overview + +The Ethereum Wire protocol defines the communication between the nodes +running Ethereum. Further reader reading can be done on the +[Wiki](http://wiki.ethereum.org/index.php/Wire_Protocol). + +# Reading Messages + +```go +// Read and validate the next eth message from the provided connection. +// returns a error message with the details. +msg, err := ethwire.ReadMessage(conn) +if err != nil { + // Handle error +} +``` + +# Writing Messages + +```go +// Constructs a message which can be interpreted by the eth network. +// Write the inventory to network +err := ethwire.WriteMessage(conn, &Msg{ + Type: ethwire.MsgInvTy, + Data : []interface{}{...}, +}) +``` diff --git a/ethwire/messaging.go b/ethwire/messaging.go new file mode 100644 index 0000000000..651bf4710c --- /dev/null +++ b/ethwire/messaging.go @@ -0,0 +1,180 @@ +package ethwire + +import ( + "bytes" + "errors" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "net" + "time" +) + +// Message: +// [4 bytes token] RLP([TYPE, DATA]) +// Refer to http://wiki.ethereum.org/index.php/Wire_Protocol + +// The magic token which should be the first 4 bytes of every message. +var MagicToken = []byte{34, 64, 8, 145} + +type MsgType byte + +const ( + MsgHandshakeTy = 0x00 + MsgDiscTy = 0x01 + MsgPingTy = 0x02 + MsgPongTy = 0x03 + MsgGetPeersTy = 0x10 + MsgPeersTy = 0x11 + MsgTxTy = 0x12 + MsgBlockTy = 0x13 + MsgGetChainTy = 0x14 + MsgNotInChainTy = 0x15 + + MsgTalkTy = 0xff +) + +var msgTypeToString = map[MsgType]string{ + MsgHandshakeTy: "Handshake", + MsgDiscTy: "Disconnect", + MsgPingTy: "Ping", + MsgPongTy: "Pong", + MsgGetPeersTy: "Get peers", + MsgPeersTy: "Peers", + MsgTxTy: "Transactions", + MsgBlockTy: "Blocks", + MsgGetChainTy: "Get chain", + MsgNotInChainTy: "Not in chain", +} + +func (mt MsgType) String() string { + return msgTypeToString[mt] +} + +type Msg struct { + Type MsgType // Specifies how the encoded data should be interpreted + //Data []byte + Data *ethutil.Value +} + +func NewMessage(msgType MsgType, data interface{}) *Msg { + return &Msg{ + Type: msgType, + Data: ethutil.NewValue(data), + } +} + +func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { + if len(data) == 0 { + return nil, nil, true, nil + } + + if len(data) <= 8 { + return nil, remaining, false, errors.New("Invalid message") + } + + // Check if the received 4 first bytes are the magic token + if bytes.Compare(MagicToken, data[:4]) != 0 { + return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) + } + + messageLength := ethutil.BytesToNumber(data[4:8]) + remaining = data[8+messageLength:] + if int(messageLength) > len(data[8:]) { + return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) + } + + message := data[8 : 8+messageLength] + decoder := ethutil.NewValueFromBytes(message) + // Type of message + t := decoder.Get(0).Uint() + // Actual data + d := decoder.SliceFrom(1) + + msg = &Msg{ + Type: MsgType(t), + Data: d, + } + + return +} + +func bufferedRead(conn net.Conn) ([]byte, error) { + return nil, nil +} + +// The basic message reader waits for data on the given connection, decoding +// and doing a few sanity checks such as if there's a data type and +// unmarhals the given data +func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { + // The recovering function in case anything goes horribly wrong + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("ethwire.ReadMessage error: %v", r) + } + }() + + // Buff for writing network message to + //buff := make([]byte, 1440) + var buff []byte + var totalBytes int + for { + // Give buffering some time + conn.SetReadDeadline(time.Now().Add(20 * time.Millisecond)) + // Create a new temporarily buffer + b := make([]byte, 1440) + // Wait for a message from this peer + n, _ := conn.Read(b) + if err != nil && n == 0 { + if err.Error() != "EOF" { + fmt.Println("err now", err) + return nil, err + } else { + fmt.Println("IOF NOW") + break + } + + // Messages can't be empty + } else if n == 0 { + break + } + + buff = append(buff, b[:n]...) + totalBytes += n + } + + // Reslice buffer + buff = buff[:totalBytes] + msg, remaining, done, err := ReadMessage(buff) + for ; done != true; msg, remaining, done, err = ReadMessage(remaining) { + //log.Println("rx", msg) + + if msg != nil { + msgs = append(msgs, msg) + } + } + + return +} + +// The basic message writer takes care of writing data over the given +// connection and does some basic error checking +func WriteMessage(conn net.Conn, msg *Msg) error { + var pack []byte + + // Encode the type and the (RLP encoded) data for sending over the wire + encoded := ethutil.NewValue(append([]interface{}{byte(msg.Type)}, msg.Data.Slice()...)).Encode() + payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32) + + // Write magic token and payload length (first 8 bytes) + pack = append(MagicToken, payloadLength...) + pack = append(pack, encoded...) + //fmt.Printf("payload %v (%v) %q\n", msg.Type, conn.RemoteAddr(), encoded) + + // Write to the connection + _, err := conn.Write(pack) + if err != nil { + return err + } + + return nil +} diff --git a/peer.go b/peer.go index cdb3bfcf59..7b17b8b09d 100644 --- a/peer.go +++ b/peer.go @@ -3,9 +3,9 @@ package eth import ( "bytes" "fmt" - "github.com/ethereum/ethchain-go" - "github.com/ethereum/ethutil-go" - "github.com/ethereum/ethwire-go" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "log" "net" "runtime" @@ -293,7 +293,7 @@ func (p *Peer) HandleInbound() { err = p.ethereum.BlockManager.ProcessBlock(block) if err != nil { - log.Println(err) + log.Println("bckmsg", err) break } else { lastBlock = block @@ -306,8 +306,7 @@ func (p *Peer) HandleInbound() { log.Println("Attempting to catch up") p.catchingUp = false p.CatchupWithPeer() - } - if ethchain.IsValidationErr(err) { + } else if ethchain.IsValidationErr(err) { // TODO } } else { From f247f0c518c6e848061462e3234f32cc7d854a46 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 00:04:46 +0100 Subject: [PATCH 0049/1237] Added readme --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..3bf5697afa --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +Ethereum +======== + +[![Build Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum) + +Ethereum Go Development package (C) Jeffrey Wilcke + +Ethereum is currently in its testing phase. The current state is "Proof +of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge). + +Ethereum Go is split up in several sub packages Please refer to each +individual package for more information. + 1. [eth](https://github.com/ethereum/eth-go) + 2. [ethchain](https://github.com/ethereum/eth-go/tree/master/ethchain) + 3. [ethwire](https://github.com/ethereum/eth-go/tree/master/ethwire) + 4. [ethdb](https://github.com/ethereum/eth-go/tree/master/ethdb) + 5. [ethutil](https://github.com/ethereum/eth-go/tree/master/ethutil) + +The [eth](https://github.com/ethereum/eth-go) is the top-level package +of the Ethereum protocol. It functions as the Ethereum bootstrapping and +peer communication layer. The [ethchain](https://github.com/ethereum/eth-go/tree/master/ethchain) +contains the Ethereum blockchain, block manager, transaction and +transaction handlers. The [ethwire](https://github.com/ethereum/eth-go/tree/master/ethwire) contains +the Ethereum [wire protocol](http://wiki.ethereum.org/index.php/Wire_Protocol) which can be used +to hook in to the Ethereum network. [ethutil](https://github.com/ethereum/eth-go/tree/master/ethutil) contains +utility functions which are not Ethereum specific. The utility package +contains the [patricia trie](http://wiki.ethereum.org/index.php/Patricia_Tree), +[RLP Encoding](http://wiki.ethereum.org/index.php/RLP) and hex encoding +helpers. The [ethdb](https://github.com/ethereum/eth-go/tree/master/ethdb) package +contains the LevelDB interface and memory DB interface. + +This is the bootstrap package. Eth-go contains all the necessary code to +get a node and connectivity going. + +Build +======= + +This is the Developer package. For the development client please see +[Ethereum(G)](https://github.com/ethereum/go-ethereum). + +`go get -u github.com/ethereum/eth-go` + +Contribution +============ + +If you'd like to contribute to Ethereum Go please fork, fix, commit and +send a pull request. Commits who do not comply with the coding standards +are ignored. + +Coding standards +================ + +Sources should be formatted according to the [Go Formatting +Style](http://golang.org/doc/effective_go.html#formatting). + +Unless structs fields are supposed to be directly accesible, provide +Getters and hide the fields through Go's exporting facility. + +When you comment put meaningfull comments. Describe in detail what you +want to achieve. + +*wrong* + +```go +// Check if the value at x is greater than y +if x > y { + // It's greater! +} +``` + +Everyone reading the source probably know what you wanted to achieve +with above code. Those are **not** meaningful comments. + +While the project isn't 100% tested I want you to write tests non the +less. I haven't got time to evaluate everyone's code in detail so I +expect you to write tests for me so I don't have to test your code +manually. (If you want to contribute by just writing tests that's fine +too!) + From 73fd358d940418b15dec850f50407bd2e504d88c Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 01:34:18 +0100 Subject: [PATCH 0050/1237] Removed RlpValue in favour of Value --- ethchain/block.go | 8 +- ethchain/block_chain.go | 2 +- ethchain/block_manager.go | 8 +- ethchain/contract.go | 14 +-- ethdb/memory_database.go | 5 +- ethereum.go | 4 +- ethutil/rlp.go | 189 +------------------------------------- ethutil/trie.go | 70 ++------------ 8 files changed, 29 insertions(+), 271 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index a7a1f787b8..0678f64e21 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -102,7 +102,7 @@ func CreateBlock(root interface{}, // Returns a hash of the block func (block *Block) Hash() []byte { - return ethutil.Sha3Bin(block.RlpValue().Encode()) + return ethutil.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { @@ -261,14 +261,14 @@ func (block *Block) SetTransactions(txs []*Transaction) { block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) } -func (block *Block) RlpValue() *ethutil.RlpValue { - return ethutil.NewRlpValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) +func (block *Block) Value() *ethutil.Value { + return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) } func (block *Block) RlpEncode() []byte { // Encode a slice interface which contains the header and the list of // transactions. - return block.RlpValue().Encode() + return block.Value().Encode() } func (block *Block) RlpDecode(data []byte) { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 56bc43a8e4..54f48bc601 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -103,7 +103,7 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { block := bc.GetBlock(currentHash) currentHash = block.PrevHash - chain = append(chain, block.RlpValue().Value) + chain = append(chain, block.Value().Val) //chain = append([]interface{}{block.RlpValue().Value}, chain...) num-- diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 92f20e2532..7d83977906 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -553,9 +553,9 @@ out: // Load the value in storage and push it on the stack x := bm.stack.Pop() // decode the object as a big integer - decoder := ethutil.NewRlpValueFromBytes([]byte(contract.State().Get(x.String()))) + decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) if !decoder.IsNil() { - bm.stack.Push(decoder.AsBigInt()) + bm.stack.Push(decoder.BigInt()) } else { bm.stack.Push(ethutil.BigFalse) } @@ -618,10 +618,10 @@ func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big val := contract.State().Get(memAddr.String()) // decode the object as a big integer - decoder := ethutil.NewRlpValueFromBytes([]byte(val)) + decoder := ethutil.NewValueFromBytes([]byte(val)) if decoder.IsNil() { return ethutil.BigFalse } - return decoder.AsBigInt() + return decoder.BigInt() } diff --git a/ethchain/contract.go b/ethchain/contract.go index d1fcec3b46..70189593b6 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -23,11 +23,11 @@ func (c *Contract) RlpEncode() []byte { } func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewRlpValueFromBytes(data) + decoder := ethutil.NewValueFromBytes(data) - c.Amount = decoder.Get(0).AsBigInt() - c.Nonce = decoder.Get(1).AsUint() - c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).AsRaw()) + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) } func (c *Contract) State() *ethutil.Trie { @@ -59,8 +59,8 @@ func (a *Address) RlpEncode() []byte { } func (a *Address) RlpDecode(data []byte) { - decoder := ethutil.NewRlpValueFromBytes(data) + decoder := ethutil.NewValueFromBytes(data) - a.Amount = decoder.Get(0).AsBigInt() - a.Nonce = decoder.Get(1).AsUint() + a.Amount = decoder.Get(0).BigInt() + a.Nonce = decoder.Get(1).Uint() } diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index 656de9f0ef..cd9f240005 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -29,9 +29,8 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) { func (db *MemDatabase) Print() { for key, val := range db.db { fmt.Printf("%x(%d): ", key, len(key)) - dec, _ := ethutil.Decode(val, 0) - node := ethutil.Conv(dec) - fmt.Printf("%q\n", node.AsRaw()) + node := ethutil.NewValueFromBytes(val) + fmt.Printf("%q\n", node.Interface()) } } diff --git a/ethereum.go b/ethereum.go index 9feb5a15c6..bd6caac089 100644 --- a/ethereum.go +++ b/ethereum.go @@ -60,8 +60,8 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - //db, err := ethdb.NewLDBDatabase() - db, err := ethdb.NewMemDatabase() + db, err := ethdb.NewLDBDatabase() + //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err } diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 0f88933b3e..025d269a0d 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -7,19 +7,8 @@ import ( _ "log" _ "math" "math/big" - "reflect" ) -/////////////////////////////////////// -type EthEncoder interface { - EncodeData(rlpData interface{}) []byte -} -type EthDecoder interface { - Get(idx int) *RlpValue -} - -////////////////////////////////////// - type RlpEncoder struct { rlpData []byte } @@ -33,180 +22,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { return Encode(rlpData) } -// Data rlpValueutes are returned by the rlp decoder. The data rlpValueutes represents -// one item within the rlp data structure. It's responsible for all the casting -// It always returns something rlpValueid -type RlpValue struct { - Value interface{} - kind reflect.Value -} - -func (rlpValue *RlpValue) String() string { - return fmt.Sprintf("%q", rlpValue.Value) -} - -func Conv(rlpValue interface{}) *RlpValue { - return &RlpValue{Value: rlpValue, kind: reflect.ValueOf(rlpValue)} -} - -func NewRlpValue(rlpValue interface{}) *RlpValue { - return &RlpValue{Value: rlpValue} -} - -func (rlpValue *RlpValue) Type() reflect.Kind { - return reflect.TypeOf(rlpValue.Value).Kind() -} - -func (rlpValue *RlpValue) IsNil() bool { - return rlpValue.Value == nil -} - -func (rlpValue *RlpValue) Length() int { - //return rlpValue.kind.Len() - if data, ok := rlpValue.Value.([]interface{}); ok { - return len(data) - } - - return 0 -} - -func (rlpValue *RlpValue) AsRaw() interface{} { - return rlpValue.Value -} - -func (rlpValue *RlpValue) AsUint() uint64 { - if Value, ok := rlpValue.Value.(uint8); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint16); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint32); ok { - return uint64(Value) - } else if Value, ok := rlpValue.Value.(uint64); ok { - return Value - } - - return 0 -} - -func (rlpValue *RlpValue) AsByte() byte { - if Value, ok := rlpValue.Value.(byte); ok { - return Value - } - - return 0x0 -} - -func (rlpValue *RlpValue) AsBigInt() *big.Int { - if a, ok := rlpValue.Value.([]byte); ok { - b := new(big.Int) - b.SetBytes(a) - return b - } - - return big.NewInt(0) -} - -func (rlpValue *RlpValue) AsString() string { - if a, ok := rlpValue.Value.([]byte); ok { - return string(a) - } else if a, ok := rlpValue.Value.(string); ok { - return a - } else { - //panic(fmt.Sprintf("not string %T: %v", rlpValue.Value, rlpValue.Value)) - } - - return "" -} - -func (rlpValue *RlpValue) AsBytes() []byte { - if a, ok := rlpValue.Value.([]byte); ok { - return a - } - - return make([]byte, 0) -} - -func (rlpValue *RlpValue) AsSlice() []interface{} { - if d, ok := rlpValue.Value.([]interface{}); ok { - return d - } - - return []interface{}{} -} - -func (rlpValue *RlpValue) AsSliceFrom(from int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[from:]) -} - -func (rlpValue *RlpValue) AsSliceTo(to int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[:to]) -} - -func (rlpValue *RlpValue) AsSliceFromTo(from, to int) *RlpValue { - slice := rlpValue.AsSlice() - - return NewRlpValue(slice[from:to]) -} - -// Threat the rlpValueute as a slice -func (rlpValue *RlpValue) Get(idx int) *RlpValue { - if d, ok := rlpValue.Value.([]interface{}); ok { - // Guard for oob - if len(d) <= idx { - return NewRlpValue(nil) - } - - if idx < 0 { - panic("negative idx for Rlp Get") - } - - return NewRlpValue(d[idx]) - } - - // If this wasn't a slice you probably shouldn't be using this function - return NewRlpValue(nil) -} - -func (rlpValue *RlpValue) Cmp(o *RlpValue) bool { - return reflect.DeepEqual(rlpValue.Value, o.Value) -} - -func (rlpValue *RlpValue) Encode() []byte { - return Encode(rlpValue.Value) -} - -func NewRlpValueFromBytes(rlpData []byte) *RlpValue { - if len(rlpData) != 0 { - data, _ := Decode(rlpData, 0) - return NewRlpValue(data) - } - - return NewRlpValue(nil) -} - -// RlpValue value setters -// An empty rlp value is always a list -func EmptyRlpValue() *RlpValue { - return NewRlpValue([]interface{}{}) -} - -func (rlpValue *RlpValue) AppendList() *RlpValue { - list := EmptyRlpValue() - rlpValue.Value = append(rlpValue.AsSlice(), list) - - return list -} - -func (rlpValue *RlpValue) Append(v interface{}) *RlpValue { - rlpValue.Value = append(rlpValue.AsSlice(), v) - - return rlpValue -} - /* func FromBin(data []byte) uint64 { if len(data) == 0 { @@ -351,8 +166,8 @@ func Encode(object interface{}) []byte { if object != nil { switch t := object.(type) { - case *RlpValue: - buff.Write(Encode(t.AsRaw())) + case *Value: + buff.Write(Encode(t.Raw())) // Code dup :-/ case int: buff.Write(Encode(big.NewInt(int64(t)))) diff --git a/ethutil/trie.go b/ethutil/trie.go index 44d2d5774a..0a3f731362 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -82,7 +82,12 @@ func (cache *Cache) Undo() { } } -// A (modified) Radix Trie implementation +// A (modified) Radix Trie implementation. The Trie implements +// a caching mechanism and will used cached values if they are +// present. If a node is not present in the cache it will try to +// fetch it from the database and store the cached value. +// Please note that the data isn't persisted unless `Sync` is +// explicitly called. type Trie struct { Root interface{} //db Database @@ -93,6 +98,7 @@ func NewTrie(db Database, Root interface{}) *Trie { return &Trie{cache: NewCache(db), Root: Root} } +// Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() } @@ -157,20 +163,8 @@ func (t *Trie) GetNode(node interface{}) *Value { } else if len(str) < 32 { return NewValueFromBytes([]byte(str)) } - /* - else { - // Fetch the encoded node from the db - o, err := t.db.Get(n.Bytes()) - if err != nil { - fmt.Println("Error InsertState", err) - return NewValue("") - } - return NewValueFromBytes(o) - } - */ return t.cache.Get(n.Bytes()) - } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { @@ -302,53 +296,3 @@ func (t *Trie) Copy() *Trie { return trie } - -/* - * Trie helper functions - */ -// Helper function for printing out the raw contents of a slice -func PrintSlice(slice []string) { - fmt.Printf("[") - for i, val := range slice { - fmt.Printf("%q", val) - if i != len(slice)-1 { - fmt.Printf(",") - } - } - fmt.Printf("]\n") -} - -func PrintSliceT(slice interface{}) { - c := Conv(slice) - for i := 0; i < c.Length(); i++ { - val := c.Get(i) - if val.Type() == reflect.Slice { - PrintSliceT(val.AsRaw()) - } else { - fmt.Printf("%q", val) - if i != c.Length()-1 { - fmt.Printf(",") - } - } - } -} - -// RLP Decodes a node in to a [2] or [17] string slice -func DecodeNode(data []byte) []string { - dec, _ := Decode(data, 0) - if slice, ok := dec.([]interface{}); ok { - strSlice := make([]string, len(slice)) - - for i, s := range slice { - if str, ok := s.([]byte); ok { - strSlice[i] = string(str) - } - } - - return strSlice - } else { - fmt.Printf("It wasn't a []. It's a %T\n", dec) - } - - return nil -} From 4a656eff7bbb17d590014eb258431b77d33a1ad1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 11:49:39 +0100 Subject: [PATCH 0051/1237] Added git flow explanation --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3bf5697afa..f6c49cc2dc 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,14 @@ This is the Developer package. For the development client please see Contribution ============ -If you'd like to contribute to Ethereum Go please fork, fix, commit and +If you'd like to contribute to Eth please fork, fix, commit and send a pull request. Commits who do not comply with the coding standards -are ignored. +are ignored. If you send pull requests make absolute sure that you +commit on the `develop` branch and that you do not merge to master. +Commits that are directly based on master are simply ignored. + +To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets +this all up and streamlines your work flow. Coding standards ================ From 334c41d088ba1484d6e529a3d3f09fbd95e5c03f Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 11:49:53 +0100 Subject: [PATCH 0052/1237] Added MIT license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..803f2ef4e3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Geff Obscura + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From fd1aa869e1544fd4d867b8f5a51985e01b692b0d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 11:52:28 +0100 Subject: [PATCH 0053/1237] Bumped version number --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 7782e7daad..2a239f8e25 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.2"} Config.Log = NewLogger(LogFile|LogStd, 0) } From f5fbbb147fc84297bba0f72856573f1ca6444fec Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:11:40 +0100 Subject: [PATCH 0054/1237] Removed debug message --- ethchain/block_manager.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 7d83977906..8b237a29a9 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -71,9 +71,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { if bm.bc.CurrentBlock == nil { AddTestNetFunds(bm.bc.genesisBlock) // Prepare the genesis block - //bm.bc.genesisBlock.State().Sync() bm.bc.Add(bm.bc.genesisBlock) - log.Println(bm.bc.genesisBlock) log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash()) //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) From 9bcb3d22168f5f02cd32ff23df60239156ddc899 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:40:19 +0100 Subject: [PATCH 0055/1237] Fixed test --- ethutil/rlp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 32bcbdce1d..2bddeec8f6 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -10,7 +10,7 @@ import ( ) func TestRlpValueEncoding(t *testing.T) { - val := EmptyRlpValue() + val := EmptyValue() val.AppendList().Append(1).Append(2).Append(3) val.Append("4").AppendList().Append(5) From 5883446b219a2980d67ff604c7f227089e5c8619 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 12:41:17 +0100 Subject: [PATCH 0056/1237] Fixed test --- ethutil/rlp_test.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2bddeec8f6..54f929ebd5 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,8 +2,6 @@ package ethutil import ( "bytes" - "encoding/hex" - "fmt" "math/big" "reflect" "testing" @@ -63,7 +61,7 @@ func TestEncode(t *testing.T) { str := string(bytes) if str != strRes { - t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + t.Errorf("Expected %q, got %q", strRes, str) } sliceRes := "\xcc\x83dog\x83god\x83cat" @@ -71,7 +69,7 @@ func TestEncode(t *testing.T) { bytes = Encode(strs) slice := string(bytes) if slice != sliceRes { - t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + t.Error("Expected %q, got %q", sliceRes, slice) } intRes := "\x82\x04\x00" @@ -108,13 +106,9 @@ func TestEncodeDecodeBigInt(t *testing.T) { encoded := Encode(bigInt) value := NewValueFromBytes(encoded) - fmt.Println(value.BigInt(), bigInt) if value.BigInt().Cmp(bigInt) != 0 { t.Errorf("Expected %v, got %v", bigInt, value.BigInt()) } - - dec, _ := hex.DecodeString("52f4fc1e") - fmt.Println(NewValueFromBytes(dec).BigInt()) } func TestEncodeDecodeBytes(t *testing.T) { From 07c12f0b921a05aec668ae8ce63b6dfac51d76a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 15 Feb 2014 13:21:11 +0100 Subject: [PATCH 0057/1237] Added trie tests, value tests --- ethutil/trie_test.go | 64 +++++++++++++++++++++++++++++++++++++++++-- ethutil/value.go | 4 +++ ethutil/value_test.go | 38 +++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 ethutil/value_test.go diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index b87d35e1ab..94414b82e5 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -6,6 +6,8 @@ import ( "testing" ) +const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" + type MemDatabase struct { db map[string][]byte } @@ -24,11 +26,15 @@ func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } -func TestTrieSync(t *testing.T) { +func New() (*MemDatabase, *Trie) { db, _ := NewMemDatabase() - trie := NewTrie(db, "") + return db, NewTrie(db, "") +} - trie.Update("dog", "kindofalongsentencewhichshouldbeencodedinitsentirety") +func TestTrieSync(t *testing.T) { + db, trie := New() + + trie.Update("dog", LONG_WORD) if len(db.db) != 0 { t.Error("Expected no data in database") } @@ -38,3 +44,55 @@ func TestTrieSync(t *testing.T) { t.Error("Expected data to be persisted") } } + +func TestTrieReset(t *testing.T) { + _, trie := New() + + trie.Update("cat", LONG_WORD) + if len(trie.cache.nodes) == 0 { + t.Error("Expected cached nodes") + } + + trie.cache.Undo() + + if len(trie.cache.nodes) != 0 { + t.Error("Expected no nodes after undo") + } +} + +func TestTrieGet(t *testing.T) { + _, trie := New() + + trie.Update("cat", LONG_WORD) + x := trie.Get("cat") + if x != LONG_WORD { + t.Error("expected %s, got %s", LONG_WORD, x) + } +} + +func TestTrieUpdating(t *testing.T) { + _, trie := New() + trie.Update("cat", LONG_WORD) + trie.Update("cat", LONG_WORD+"1") + x := trie.Get("cat") + if x != LONG_WORD+"1" { + t.Error("expected %S, got %s", LONG_WORD+"1", x) + } +} + +func TestTrieCmp(t *testing.T) { + _, trie1 := New() + _, trie2 := New() + + trie1.Update("doge", LONG_WORD) + trie2.Update("doge", LONG_WORD) + if !trie1.Cmp(trie2) { + t.Error("Expected tries to be equal") + } + + trie1.Update("dog", LONG_WORD) + trie2.Update("cat", LONG_WORD) + if trie1.Cmp(trie2) { + t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root) + } +} diff --git a/ethutil/value.go b/ethutil/value.go index 2a990783e0..f91c339831 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -60,6 +60,10 @@ func (val *Value) Uint() uint64 { return uint64(Val) } else if Val, ok := val.Val.(uint64); ok { return Val + } else if Val, ok := val.Val.(int); ok { + return uint64(Val) + } else if Val, ok := val.Val.(uint); ok { + return uint64(Val) } else if Val, ok := val.Val.([]byte); ok { return ReadVarint(bytes.NewReader(Val)) } diff --git a/ethutil/value_test.go b/ethutil/value_test.go new file mode 100644 index 0000000000..7d41eb1c94 --- /dev/null +++ b/ethutil/value_test.go @@ -0,0 +1,38 @@ +package ethutil + +import ( + "testing" +) + +func TestValueCmp(t *testing.T) { + val1 := NewValue("hello") + val2 := NewValue("world") + if val1.Cmp(val2) { + t.Error("Expected values not to be equal") + } + + val3 := NewValue("hello") + val4 := NewValue("hello") + if !val3.Cmp(val4) { + t.Error("Expected values to be equal") + } +} + +func TestValueTypes(t *testing.T) { + str := NewValue("str") + num := NewValue(1) + inter := NewValue([]interface{}{1}) + + if str.Str() != "str" { + t.Errorf("expected Str to return 'str', got %s", str.Str()) + } + + if num.Uint() != 1 { + t.Errorf("expected Uint to return '1', got %d", num.Uint()) + } + + exp := []interface{}{1} + if !NewValue(inter.Interface()).Cmp(NewValue(exp)) { + t.Errorf("expected Interface to return '%v', got %v", exp, num.Interface()) + } +} From 066940f134170ab4b0901887b69f824418c322fc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:21 +0100 Subject: [PATCH 0058/1237] Defer undo on the current block's state --- ethchain/block_manager.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 8b237a29a9..d9cdcd2d9b 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -103,6 +103,11 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // Processing a blocks may never happen simultaneously bm.mutex.Lock() defer bm.mutex.Unlock() + // Defer the Undo on the Trie. If the block processing happened + // we don't want to undo but since undo only happens on dirty + // nodes this won't happen because Commit would have been called + // before that. + defer bm.bc.CurrentBlock.State().Undo() hash := block.Hash() From c95a27e39485eeeebd8608537115a4fd246c246c Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:33 +0100 Subject: [PATCH 0059/1237] Added more tests --- ethutil/value.go | 12 +++++++----- ethutil/value_test.go | 20 +++++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ethutil/value.go b/ethutil/value.go index f91c339831..701ece5bb6 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -84,6 +84,8 @@ func (val *Value) BigInt() *big.Int { b := new(big.Int).SetBytes(a) return b + } else if a, ok := val.Val.(*big.Int); ok { + return a } else { return big.NewInt(int64(val.Uint())) } @@ -106,7 +108,7 @@ func (val *Value) Bytes() []byte { return a } - return make([]byte, 0) + return []byte{} } func (val *Value) Slice() []interface{} { @@ -144,7 +146,7 @@ func (val *Value) Get(idx int) *Value { } if idx < 0 { - panic("negative idx for Rlp Get") + panic("negative idx for Value Get") } return NewValue(d[idx]) @@ -162,9 +164,9 @@ func (val *Value) Encode() []byte { return Encode(val.Val) } -func NewValueFromBytes(rlpData []byte) *Value { - if len(rlpData) != 0 { - data, _ := Decode(rlpData, 0) +func NewValueFromBytes(data []byte) *Value { + if len(data) != 0 { + data, _ := Decode(data, 0) return NewValue(data) } diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 7d41eb1c94..0e2da53287 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -1,6 +1,8 @@ package ethutil import ( + "bytes" + "math/big" "testing" ) @@ -22,6 +24,8 @@ func TestValueTypes(t *testing.T) { str := NewValue("str") num := NewValue(1) inter := NewValue([]interface{}{1}) + byt := NewValue([]byte{1, 2, 3, 4}) + bigInt := NewValue(big.NewInt(10)) if str.Str() != "str" { t.Errorf("expected Str to return 'str', got %s", str.Str()) @@ -31,8 +35,18 @@ func TestValueTypes(t *testing.T) { t.Errorf("expected Uint to return '1', got %d", num.Uint()) } - exp := []interface{}{1} - if !NewValue(inter.Interface()).Cmp(NewValue(exp)) { - t.Errorf("expected Interface to return '%v', got %v", exp, num.Interface()) + interExp := []interface{}{1} + if !NewValue(inter.Interface()).Cmp(NewValue(interExp)) { + t.Errorf("expected Interface to return '%v', got %v", interExp, num.Interface()) + } + + bytExp := []byte{1, 2, 3, 4} + if bytes.Compare(byt.Bytes(), bytExp) != 0 { + t.Errorf("expected Bytes to return '%v', got %v", bytExp, byt.Bytes()) + } + + bigExp := big.NewInt(10) + if bigInt.BigInt().Cmp(bigExp) != 0 { + t.Errorf("expected BigInt to return '%v', got %v", bigExp, bigInt.BigInt()) } } From f1d6f1bd1793767a5596d4c277651e2264c1cf8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:30:50 +0100 Subject: [PATCH 0060/1237] Removed Reset --- ethutil/helpers.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 1c6adf2569..2e3aeb9a32 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -27,7 +27,6 @@ func Ripemd160(data []byte) []byte { func Sha3Bin(data []byte) []byte { d := sha3.NewKeccak256() - d.Reset() d.Write(data) return d.Sum(nil) From 7264044122d2ceef413667ad8473746a40a44782 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:31:02 +0100 Subject: [PATCH 0061/1237] Added a few tests --- ethutil/rlp_test.go | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 54f929ebd5..2a58bfc0fa 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -119,43 +119,6 @@ func TestEncodeDecodeBytes(t *testing.T) { } } -/* -var ZeroHash256 = make([]byte, 32) -var ZeroHash160 = make([]byte, 20) -var EmptyShaList = Sha3Bin(Encode([]interface{}{})) - -var GenisisHeader = []interface{}{ - // Previous hash (none) - //"", - ZeroHash256, - // Sha of uncles - Sha3Bin(Encode([]interface{}{})), - // Coinbase - ZeroHash160, - // Root state - "", - // Sha of transactions - //EmptyShaList, - Sha3Bin(Encode([]interface{}{})), - // Difficulty - BigPow(2, 22), - // Time - //big.NewInt(0), - int64(0), - // extra - "", - // Nonce - big.NewInt(42), -} - -func TestEnc(t *testing.T) { - //enc := Encode(GenisisHeader) - //fmt.Printf("%x (%d)\n", enc, len(enc)) - h, _ := hex.DecodeString("f8a0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06d076baa9c4074fb2df222dd16a96b0155a1e6686b3e5748b4e9ca0a208a425ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493478340000080802a") - fmt.Printf("%x\n", Sha3Bin(h)) -} -*/ - func BenchmarkEncodeDecode(b *testing.B) { for i := 0; i < b.N; i++ { bytes := Encode([]interface{}{"dog", "god", "cat"}) From e4a6ee3d7f8a3876387f837f6fec6822bd97951e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:32:56 +0100 Subject: [PATCH 0062/1237] Added dirty tracking on the cache --- ethutil/trie.go | 17 +++++++++++++++-- ethutil/trie_test.go | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 0a3f731362..7140a1b361 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -20,8 +20,9 @@ func (n *Node) Copy() *Node { } type Cache struct { - nodes map[string]*Node - db Database + nodes map[string]*Node + db Database + IsDirty bool } func NewCache(db Database) *Cache { @@ -36,6 +37,7 @@ func (cache *Cache) Put(v interface{}) interface{} { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) + cache.IsDirty = true return sha } @@ -60,12 +62,18 @@ func (cache *Cache) Get(key []byte) *Value { } func (cache *Cache) Commit() { + // Don't try to commit if it isn't dirty + if !cache.IsDirty { + return + } + for key, node := range cache.nodes { if node.Dirty { cache.db.Put([]byte(key), node.Value.Encode()) node.Dirty = false } } + cache.IsDirty = false // If the nodes grows beyond the 200 entries we simple empty it // FIXME come up with something better @@ -80,6 +88,7 @@ func (cache *Cache) Undo() { delete(cache.nodes, key) } } + cache.IsDirty = false } // A (modified) Radix Trie implementation. The Trie implements @@ -103,6 +112,10 @@ func (t *Trie) Sync() { t.cache.Commit() } +func (t *Trie) Undo() { + t.cache.Undo() +} + /* * Public (query) interface functions */ diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 94414b82e5..fa60c8cfc0 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -45,6 +45,26 @@ func TestTrieSync(t *testing.T) { } } +func TestTrieDirtyTracking(t *testing.T) { + _, trie := New() + trie.Update("dog", LONG_WORD) + if !trie.cache.IsDirty { + t.Error("Expected trie to be dirty") + } + + trie.Sync() + if trie.cache.IsDirty { + t.Error("Expected trie not to be dirty") + } + + trie.Update("test", LONG_WORD) + trie.cache.Undo() + if trie.cache.IsDirty { + t.Error("Expected trie not to be dirty") + } + +} + func TestTrieReset(t *testing.T) { _, trie := New() From 2ea05292c0c7947deb90c37378eb36ea78b6cf20 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:33:07 +0100 Subject: [PATCH 0063/1237] Added proper name :) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 803f2ef4e3..b77f7909a6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Geff Obscura +Copyright (c) 2013 Jeffrey Wilcke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From e5b97fe03e8789bf4e113946a1935c0ba270ad2b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 16 Feb 2014 20:33:23 +0100 Subject: [PATCH 0064/1237] Added proper error message --- peer.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 7b17b8b09d..926d34eb39 100644 --- a/peer.go +++ b/peer.go @@ -293,7 +293,9 @@ func (p *Peer) HandleInbound() { err = p.ethereum.BlockManager.ProcessBlock(block) if err != nil { - log.Println("bckmsg", err) + if ethutil.Config.Debug { + log.Printf("[PEER] Block (%x) err %v", block.Hash()[:4], err) + } break } else { lastBlock = block From b7a636b8949a2270ae030f56791c88060fa5483a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Feb 2014 20:29:54 +0100 Subject: [PATCH 0065/1237] Values should accept bytes as valid string output --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethutil/value.go b/ethutil/value.go index 701ece5bb6..d3a38f87ff 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -98,6 +98,8 @@ func (val *Value) Str() string { return string(a) } else if a, ok := val.Val.(string); ok { return a + } else if a, ok := val.Val.(byte); ok { + return string(a) } return "" From 7413552a28c538ca4f33d0dafe28907b7b761863 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Feb 2014 20:40:33 +0100 Subject: [PATCH 0066/1237] Root should reset on undo --- ethutil/trie.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 7140a1b361..95abca6027 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -98,22 +98,25 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { - Root interface{} + prevRoot interface{} + Root interface{} //db Database cache *Cache } func NewTrie(db Database, Root interface{}) *Trie { - return &Trie{cache: NewCache(db), Root: Root} + return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root} } // Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() + t.prevRoot = t.Root } func (t *Trie) Undo() { t.cache.Undo() + t.Root = t.prevRoot } /* @@ -181,6 +184,7 @@ func (t *Trie) GetNode(node interface{}) *Value { } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { + if value != "" { return t.InsertState(node, key, value) } else { @@ -241,6 +245,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter // Check for "special" 2 slice type node if currentNode.Len() == 2 { // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) v := currentNode.Get(1).Raw() From e72a782bf0e0a0059e8dff83fa5fc80cc6f678e5 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Mon, 17 Feb 2014 15:46:16 -0800 Subject: [PATCH 0067/1237] adding compact decode tests --- ethutil/encoding_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go index bcabab0b19..cbfbc0eafa 100644 --- a/ethutil/encoding_test.go +++ b/ethutil/encoding_test.go @@ -35,3 +35,33 @@ func TestCompactHexDecode(t *testing.T) { t.Error("Error compact hex decode. Expected", exp, "got", res) } } + +func TestCompactDecode(t *testing.T) { + exp := []int{1, 2, 3, 4, 5} + res := CompactDecode("\x11\x23\x45") + + if !CompareIntSlice(res, exp) { + t.Error("odd compact decode. Expected", exp, "got", res) + } + + exp = []int{0, 1, 2, 3, 4, 5} + res = CompactDecode("\x00\x01\x23\x45") + + if !CompareIntSlice(res, exp) { + t.Error("even compact decode. Expected", exp, "got", res) + } + + exp = []int{0, 15, 1, 12, 11, 8 /*term*/, 16} + res = CompactDecode("\x20\x0f\x1c\xb8") + + if !CompareIntSlice(res, exp) { + t.Error("even terminated compact decode. Expected", exp, "got", res) + } + + exp = []int{15, 1, 12, 11, 8 /*term*/, 16} + res = CompactDecode("\x3f\x1c\xb8") + + if !CompareIntSlice(res, exp) { + t.Error("even terminated compact decode. Expected", exp, "got", res) + } +} \ No newline at end of file From c5b009ba6f153aa65fa25126bea41d899a436299 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Mon, 17 Feb 2014 15:47:33 -0800 Subject: [PATCH 0068/1237] new line --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 2a239f8e25..b361a30799 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -38,7 +38,7 @@ func ReadConfig(base string) *config { _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it", path) + log.Printf("Debug logging directory %s doesn't exist, creating it\n", path) os.Mkdir(path, 0777) } } From a5b7279cb507de93fde39d86c414e417f2d0b3e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:31:31 +0100 Subject: [PATCH 0069/1237] Changed uncle block fee as to what it should be --- ethchain/fees.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index 8f1646ab4c..57017cdc95 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -13,7 +13,13 @@ var DataFee *big.Int = new(big.Int) var CryptoFee *big.Int = new(big.Int) var ExtroFee *big.Int = new(big.Int) -var BlockReward *big.Int = big.NewInt(1500000000000000000) +var BlockReward *big.Int = big.NewInt(1.5e+18) + +var UncleReward *big.Int = big.NewInt(1.125e+18) + +//var UncleReward *big.Int = big.NewInt(2e18) +var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) + var Period1Reward *big.Int = new(big.Int) var Period2Reward *big.Int = new(big.Int) var Period3Reward *big.Int = new(big.Int) From bb3e28310ee3c2cfc5b3153510d4a1d220a22e81 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:31:51 +0100 Subject: [PATCH 0070/1237] If sender is receiver only subtract the fee --- ethchain/transaction_pool.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index c2d65a2a7b..75a8aa5d1d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -106,17 +106,25 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } } - // Subtract the amount from the senders account - sender.Amount.Sub(sender.Amount, totAmount) - sender.Nonce += 1 - // Get the receiver receiver := block.GetAddr(tx.Recipient) - // Add the amount to receivers account which should conclude this transaction - receiver.Amount.Add(receiver.Amount, tx.Value) + sender.Nonce += 1 + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + } else { + // Subtract the amount from the senders account + sender.Amount.Sub(sender.Amount, totAmount) + + // Add the amount to receivers account which should conclude this transaction + receiver.Amount.Add(receiver.Amount, tx.Value) + + block.UpdateAddr(tx.Recipient, receiver) + } block.UpdateAddr(tx.Sender(), sender) - block.UpdateAddr(tx.Recipient, receiver) return } From ba95849097f7a35d9f315a4f2e340d3ef944a306 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:32:20 +0100 Subject: [PATCH 0071/1237] Added hex method --- ethutil/helpers.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 2e3aeb9a32..11a474081f 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -58,3 +58,7 @@ func MatchingNibbleLength(a, b []int) int { func Hex(d []byte) string { return hex.EncodeToString(d) } +func ToHex(str string) []byte { + h, _ := hex.DecodeString(str) + return h +} From c7623c31650d078184511be796f7a00dde2a25a1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:32:39 +0100 Subject: [PATCH 0072/1237] Changed debug messages --- peer.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/peer.go b/peer.go index 926d34eb39..53fdfa8fc0 100644 --- a/peer.go +++ b/peer.go @@ -294,7 +294,9 @@ func (p *Peer) HandleInbound() { if err != nil { if ethutil.Config.Debug { - log.Printf("[PEER] Block (%x) err %v", block.Hash()[:4], err) + log.Printf("[PEER] Block %x failed\n", block.Hash()) + log.Printf("[PEER] %v\n", err) + log.Println(block) } break } else { @@ -467,7 +469,7 @@ func (p *Peer) pushHandshake() error { pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(4), uint32(0), p.Version, byte(p.caps), p.port, pubkey, + uint32(5), uint32(0), p.Version, byte(p.caps), p.port, pubkey, }) p.QueueMessage(msg) @@ -494,7 +496,7 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - if c.Get(0).Uint() != 4 { + if c.Get(0).Uint() != 5 { log.Println("Invalid peer version. Require protocol v4") p.Stop() return @@ -527,7 +529,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { // Get a reference to the peers version p.Version = c.Get(2).Str() - log.Println(p) + log.Println("[PEER]", p) } func (p *Peer) String() string { @@ -544,7 +546,7 @@ func (p *Peer) String() string { strConnectType = "disconnected" } - return fmt.Sprintf("peer [%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) + return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) } From 8629d9a4187c2027e565a50d763f949993ab169c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:33:15 +0100 Subject: [PATCH 0073/1237] String changed and removed some debugging code --- ethchain/block.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 0678f64e21..34ddf9fecd 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -135,7 +135,7 @@ func (block *Block) GetContract(addr []byte) *Contract { } func (block *Block) UpdateContract(addr []byte, contract *Contract) { // Make sure the state is synced - contract.State().Sync() + //contract.State().Sync() block.state.Update(string(addr), string(contract.RlpEncode())) } @@ -298,12 +298,6 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { tx := NewTransactionFromValue(txes.Get(i)) block.transactions[i] = tx - - /* - if ethutil.Config.Debug { - ethutil.Config.Db.Put(tx.Hash(), ethutil.Encode(tx)) - } - */ } } @@ -335,7 +329,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { } func (block *Block) String() string { - return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce) + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } //////////// UNEXPORTED ///////////////// From 68028f492f092f0546c2c084c1694ee6bf43b34e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:33:26 +0100 Subject: [PATCH 0074/1237] Fixed block handling --- ethchain/block_chain.go | 7 +++---- ethchain/block_manager.go | 42 ++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 54f48bc601..5b55782a9e 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -104,7 +104,6 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { currentHash = block.PrevHash chain = append(chain, block.Value().Val) - //chain = append([]interface{}{block.RlpValue().Value}, chain...) num-- } @@ -141,7 +140,9 @@ func (bc *BlockChain) Add(block *Block) { bc.CurrentBlock = block bc.LastBlockHash = block.Hash() - ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) + encodedBlock := block.RlpEncode() + ethutil.Config.Db.Put(block.Hash(), encodedBlock) + ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } func (bc *BlockChain) GetBlock(hash []byte) *Block { @@ -177,8 +178,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) { func (bc *BlockChain) Stop() { if bc.CurrentBlock != nil { - ethutil.Config.Db.Put([]byte("LastBlock"), bc.CurrentBlock.RlpEncode()) - log.Println("[CHAIN] Stopped") } } diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index d9cdcd2d9b..092e3dea5b 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "github.com/obscuren/secp256k1-go" "log" "math" @@ -18,10 +19,6 @@ type BlockProcessor interface { ProcessBlock(block *Block) } -func CalculateBlockReward(block *Block, uncleLength int) *big.Int { - return BlockReward -} - type BlockManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -48,7 +45,7 @@ func AddTestNetFunds(block *Block) { "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "80c01a26338f0d905e295fccb71fa9ea849ffa12", // Alex + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex } { //log.Println("2^200 Wei to", addr) codedAddr, _ := hex.DecodeString(addr) @@ -70,14 +67,17 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { if bm.bc.CurrentBlock == nil { AddTestNetFunds(bm.bc.genesisBlock) + + bm.bc.genesisBlock.State().Sync() // Prepare the genesis block bm.bc.Add(bm.bc.genesisBlock) - log.Printf("Genesis: %x\n", bm.bc.genesisBlock.Hash()) //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) //bm.bc.genesisBlock.PrintHash() } + log.Printf("Last block: %x\n", bm.bc.CurrentBlock.Hash()) + return bm } @@ -115,12 +115,6 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return nil } - /* - if ethutil.Config.Debug { - log.Printf("[BMGR] Processing block(%x)\n", hash) - } - */ - // Check if we have the parent hash, if it isn't known we discard it // Reasons might be catching up or simply an invalid block if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil { @@ -142,13 +136,12 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { } if !block.State().Cmp(bm.bc.CurrentBlock.State()) { - //if block.State().Root != state.Root { return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root) } // Calculate the new total difficulty and sync back to the db if bm.CalculateTD(block) { - // Sync the current block's state to the database + // Sync the current block's state to the database and cancelling out the deferred Undo bm.bc.CurrentBlock.State().Sync() // Add the block to the chain bm.bc.Add(block) @@ -172,7 +165,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { */ // Broadcast the valid block back to the wire - //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.RlpValue().Value}) + bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // If there's a block processor present, pass in the block for further // processing @@ -251,6 +244,18 @@ func (bm *BlockManager) ValidateBlock(block *Block) error { return nil } +func CalculateBlockReward(block *Block, uncleLength int) *big.Int { + base := new(big.Int) + for i := 0; i < uncleLength; i++ { + base.Add(base, UncleInclusionReward) + } + return base.Add(base, BlockReward) +} + +func CalculateUncleReward(block *Block) *big.Int { + return UncleReward +} + func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data addr := processor.GetAddr(block.Coinbase) @@ -259,7 +264,12 @@ func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error processor.UpdateAddr(block.Coinbase, addr) - // TODO Reward each uncle + for _, uncle := range block.Uncles { + uncleAddr := processor.GetAddr(uncle.Coinbase) + uncleAddr.AddFee(CalculateUncleReward(uncle)) + + processor.UpdateAddr(uncle.Coinbase, uncleAddr) + } return nil } From d7eca7bcc12e940f0aa80d45e6e802ba68143b5c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 01:34:06 +0100 Subject: [PATCH 0075/1237] Rlp update --- ethereum.go | 39 +++++++++++++++++++++------------------ ethutil/encoding.go | 3 +-- ethutil/rlp.go | 8 -------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/ethereum.go b/ethereum.go index bd6caac089..c54303795d 100644 --- a/ethereum.go +++ b/ethereum.go @@ -85,7 +85,6 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { Nonce: nonce, serverCaps: caps, nat: nat, - MaxPeers: 5, } ethereum.TxPool = ethchain.NewTxPool() ethereum.TxPool.Speaker = ethereum @@ -114,29 +113,33 @@ func (s *Ethereum) ProcessPeerList(addrs []string) { } func (s *Ethereum) ConnectToPeer(addr string) error { - var alreadyConnected bool + if s.peers.Len() < s.MaxPeers { + var alreadyConnected bool - eachPeer(s.peers, func(p *Peer, v *list.Element) { - if p.conn == nil { - return + eachPeer(s.peers, func(p *Peer, v *list.Element) { + if p.conn == nil { + return + } + phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) + ahost, _, _ := net.SplitHostPort(addr) + + if phost == ahost { + alreadyConnected = true + return + } + }) + + if alreadyConnected { + return nil } - phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) - ahost, _, _ := net.SplitHostPort(addr) - if phost == ahost { - alreadyConnected = true - return - } - }) + peer := NewOutboundPeer(addr, s, s.serverCaps) - if alreadyConnected { - return nil + s.peers.PushBack(peer) + + log.Printf("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers) } - peer := NewOutboundPeer(addr, s, s.serverCaps) - - s.peers.PushBack(peer) - return nil } diff --git a/ethutil/encoding.go b/ethutil/encoding.go index 207548c933..1f661947a7 100644 --- a/ethutil/encoding.go +++ b/ethutil/encoding.go @@ -3,7 +3,6 @@ package ethutil import ( "bytes" "encoding/hex" - _ "fmt" "strings" ) @@ -36,7 +35,7 @@ func CompactEncode(hexSlice []int) string { func CompactDecode(str string) []int { base := CompactHexDecode(str) base = base[:len(base)-1] - if base[0] >= 2 { // && base[len(base)-1] != 16 { + if base[0] >= 2 { base = append(base, 16) } if base[0]%2 == 1 { diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 025d269a0d..e633f5f1dc 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -86,13 +86,6 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { // TODO Use a bytes.Buffer instead of a raw byte slice. // Cleaner code, and use draining instead of seeking the next bytes to read func Decode(data []byte, pos uint64) (interface{}, uint64) { - /* - if pos > uint64(len(data)-1) { - log.Println(data) - log.Panicf("index out of range %d for data %q, l = %d", pos, data, len(data)) - } - */ - var slice []interface{} char := int(data[pos]) switch { @@ -131,7 +124,6 @@ func Decode(data []byte, pos uint64) (interface{}, uint64) { case char <= 0xff: l := uint64(data[pos]) - 0xf7 - //b := BigD(data[pos+1 : pos+1+l]).Uint64() b := ReadVarint(bytes.NewReader(data[pos+1 : pos+1+l])) pos = pos + l + 1 From c866fcc5b37b53e0d11c1fd7e6cb971859537f2c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Feb 2014 12:10:21 +0100 Subject: [PATCH 0076/1237] Added new address --- ethchain/block_manager.go | 2 +- ethutil/config.go | 2 +- ethutil/helpers.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 092e3dea5b..4e72f51ba4 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -43,7 +43,7 @@ type BlockManager struct { func AddTestNetFunds(block *Block) { for _, addr := range []string{ "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "93658b04240e4bd4046fd2d6d417d20f146f4b43", // Jeffrey + "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex } { diff --git a/ethutil/config.go b/ethutil/config.go index 2a239f8e25..df1772d81d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.2"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} Config.Log = NewLogger(LogFile|LogStd, 0) } diff --git a/ethutil/helpers.go b/ethutil/helpers.go index 11a474081f..aa0f79a044 100644 --- a/ethutil/helpers.go +++ b/ethutil/helpers.go @@ -58,7 +58,7 @@ func MatchingNibbleLength(a, b []int) int { func Hex(d []byte) string { return hex.EncodeToString(d) } -func ToHex(str string) []byte { +func FromHex(str string) []byte { h, _ := hex.DecodeString(str) return h } From 4d405f665480fc9d0a0133161909856230f2f7a9 Mon Sep 17 00:00:00 2001 From: Sam Boyer Date: Tue, 18 Feb 2014 10:40:58 -0500 Subject: [PATCH 0077/1237] s/GenisisHeader/GenesisHeader/ --- ethchain/genesis.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 060d347e42..935978a69e 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -13,7 +13,7 @@ var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) -var GenisisHeader = []interface{}{ +var GenesisHeader = []interface{}{ // Previous hash (none) //"", ZeroHash256, @@ -36,4 +36,4 @@ var GenisisHeader = []interface{}{ ethutil.Sha3Bin(big.NewInt(42).Bytes()), } -var Genesis = []interface{}{GenisisHeader, []interface{}{}, []interface{}{}} +var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} From 6dac014978d30883aa556c004f948e66a314d2de Mon Sep 17 00:00:00 2001 From: Sam Boyer Date: Tue, 18 Feb 2014 10:47:09 -0500 Subject: [PATCH 0078/1237] Fix a couple errors from go vet --- peer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 53fdfa8fc0..95b526c67c 100644 --- a/peer.go +++ b/peer.go @@ -285,7 +285,6 @@ func (p *Peer) HandleInbound() { p.lastPong = time.Now().Unix() case ethwire.MsgBlockTy: // Get all blocks and process them - msg.Data = msg.Data var block, lastBlock *ethchain.Block var err error for i := msg.Data.Len() - 1; i >= 0; i-- { @@ -438,7 +437,7 @@ func (p *Peer) Start() { err := p.pushHandshake() if err != nil { - log.Printf("Peer can't send outbound version ack", err) + log.Println("Peer can't send outbound version ack", err) p.Stop() From 5adbd399463edc5ec800bdcf3524d64313c8add5 Mon Sep 17 00:00:00 2001 From: Sam Boyer Date: Tue, 18 Feb 2014 17:20:41 -0500 Subject: [PATCH 0079/1237] Express bit flag constants using iota bitshift. --- peer.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/peer.go b/peer.go index 53fdfa8fc0..e64b5b3bda 100644 --- a/peer.go +++ b/peer.go @@ -56,9 +56,9 @@ func (d DiscReason) String() string { type Caps byte const ( - CapPeerDiscTy = 0x01 - CapTxTy = 0x02 - CapChainTy = 0x04 + CapPeerDiscTy = 1 << iota + CapTxTy + CapChainTy CapDefault = CapChainTy | CapTxTy | CapPeerDiscTy ) From 357b4bc14c82d206a8c813291fb3ead01ed29041 Mon Sep 17 00:00:00 2001 From: Sam Boyer Date: Tue, 18 Feb 2014 17:24:44 -0500 Subject: [PATCH 0080/1237] Add comment explaining why iota is not used. --- ethwire/messaging.go | 3 +++ peer.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 651bf4710c..185faa341a 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -19,6 +19,9 @@ var MagicToken = []byte{34, 64, 8, 145} type MsgType byte const ( + // Values are given explicitly instead of by iota because these values are + // defined by the wire protocol spec; it is easier for humans to ensure + // correctness when values are explicit. MsgHandshakeTy = 0x00 MsgDiscTy = 0x01 MsgPingTy = 0x02 diff --git a/peer.go b/peer.go index e64b5b3bda..a6481e10c6 100644 --- a/peer.go +++ b/peer.go @@ -23,6 +23,9 @@ const ( type DiscReason byte const ( + // Values are given explicitly instead of by iota because these values are + // defined by the wire protocol spec; it is easier for humans to ensure + // correctness when values are explicit. DiscReRequested = 0x00 DiscReTcpSysErr = 0x01 DiscBadProto = 0x02 From 24f2b2afc3a848190822c382e6aa31c8ab120f07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 11:35:17 +0100 Subject: [PATCH 0081/1237] Running contracts fixed --- ethchain/block.go | 53 +++++++++++++++++++----- ethchain/block_manager.go | 35 ++++++++++------ ethchain/block_manager_test.go | 74 +++++++--------------------------- ethchain/stack.go | 9 ++++- ethchain/transaction.go | 5 ++- ethchain/transaction_test.go | 16 ++++---- ethereum.go | 2 +- ethutil/big.go | 6 +++ ethutil/config.go | 14 ++++--- ethutil/trie.go | 4 ++ 10 files changed, 120 insertions(+), 98 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 34ddf9fecd..ae654b7d8a 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -46,6 +46,8 @@ type Block struct { // List of transactions and/or contracts transactions []*Transaction TxSha []byte + + contractStates map[string]*ethutil.Trie } // New block takes a raw encoded string @@ -79,14 +81,15 @@ func CreateBlock(root interface{}, block := &Block{ // Slice of transactions to include in this block - transactions: txes, - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: EmptyShaList, + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + contractStates: make(map[string]*ethutil.Trie), } block.SetTransactions(txes) block.SetUncles([]*Block{}) @@ -131,6 +134,13 @@ func (block *Block) GetContract(addr []byte) *Contract { contract := &Contract{} contract.RlpDecode([]byte(data)) + cachedState := block.contractStates[string(addr)] + if cachedState != nil { + contract.state = cachedState + } else { + block.contractStates[string(addr)] = contract.state + } + return contract } func (block *Block) UpdateContract(addr []byte, contract *Contract) { @@ -190,6 +200,25 @@ func (block *Block) BlockInfo() BlockInfo { return bi } +// Sync the block's state and contract respectively +func (block *Block) Sync() { + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Sync() + } + // Sync the block state itself + block.state.Sync() +} + +func (block *Block) Undo() { + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Undo() + } + // Sync the block state itself + block.state.Undo() +} + func (block *Block) MakeContract(tx *Transaction) { // Create contract if there's no recipient if tx.IsContract() { @@ -199,9 +228,14 @@ func (block *Block) MakeContract(tx *Transaction) { contract := NewContract(value, []byte("")) block.state.Update(string(addr), string(contract.RlpEncode())) for i, val := range tx.Data { - contract.state.Update(string(ethutil.NumberToBytes(uint64(i), 32)), val) + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.Update(string(bytNum), val) + } } block.UpdateContract(addr, contract) + + block.contractStates[string(addr)] = contract.state } } @@ -288,6 +322,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.Time = int64(header.Get(6).BigInt().Uint64()) block.Extra = header.Get(7).Str() block.Nonce = header.Get(8).Bytes() + block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their // header set. diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 4e72f51ba4..33df338ff8 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -107,7 +107,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. - defer bm.bc.CurrentBlock.State().Undo() + defer bm.bc.CurrentBlock.Undo() hash := block.Hash() @@ -142,7 +142,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { // Calculate the new total difficulty and sync back to the db if bm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - bm.bc.CurrentBlock.State().Sync() + bm.bc.CurrentBlock.Sync() // Add the block to the chain bm.bc.Add(block) @@ -280,11 +280,13 @@ func (bm *BlockManager) Stop() { func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { // Recovering function in case the VM had any errors - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from VM execution with err =", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + } + }() + */ // Process contract bm.ProcContract(tx, block, func(opType OpType) bool { @@ -305,6 +307,7 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac blockInfo := bm.bc.BlockInfo(block) contract := block.GetContract(tx.Hash()) + if contract == nil { fmt.Println("Contract not found") return @@ -313,7 +316,7 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac Pow256 := ethutil.BigPow(2, 256) if ethutil.Config.Debug { - fmt.Printf("# op arg\n") + fmt.Printf("# op\n") } out: for { @@ -321,9 +324,11 @@ out: base := new(big.Int) // XXX Should Instr return big int slice instead of string slice? // Get the next instruction from the contract - //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) - nb := ethutil.NumberToBytes(uint64(pc), 32) - o, _, _ := ethutil.Instr(contract.State().Get(string(nb))) + nb := ethutil.BigToBytes(big.NewInt(int64(pc)), 256) + r := contract.State().Get(string(nb)) + v := ethutil.NewValueFromBytes([]byte(r)) + //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) + o := v.Uint() op := OpCode(o) if !cb(0) { @@ -575,7 +580,10 @@ out: case oSSTORE: // Store Y at index X x, y := bm.stack.Popn() - contract.State().Update(x.String(), string(ethutil.Encode(y))) + idx := ethutil.BigToBytes(x, 256) + val := ethutil.NewValue(y) + //fmt.Printf("STORING VALUE: %v @ %v\n", val.BigInt(), ethutil.BigD(idx)) + contract.State().Update(string(idx), string(val.Encode())) case oJMP: x := int(bm.stack.Pop().Uint64()) // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) @@ -617,7 +625,10 @@ out: bm.TransactionPool.QueueTransaction(tx) case oSUICIDE: //addr := bm.stack.Pop() + default: + fmt.Println("Invalid OPCODE", op) } + //bm.stack.Print() pc++ } } diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index 502c50b97b..ae29e2e254 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -1,75 +1,29 @@ package ethchain -/* import ( _ "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "math/big" "testing" ) func TestVm(t *testing.T) { InitFees() + ethutil.ReadConfig("") - db, _ := NewMemDatabase() - Db = db + db, _ := ethdb.NewMemDatabase() + ethutil.Config.Db = db + bm := NewBlockManager(nil) - ctrct := NewTransaction("", 200000000, []string{ - "PUSH", "1a2f2e", - "PUSH", "hallo", - "POP", // POP hallo - "PUSH", "3", - "LOAD", // Load hallo back on the stack - - "PUSH", "1", - "PUSH", "2", - "ADD", - - "PUSH", "2", - "PUSH", "1", - "SUB", - - "PUSH", "100000000000000000000000", - "PUSH", "10000000000000", - "SDIV", - - "PUSH", "105", - "PUSH", "200", - "MOD", - - "PUSH", "100000000000000000000000", - "PUSH", "10000000000000", - "SMOD", - - "PUSH", "5", - "PUSH", "10", - "LT", - - "PUSH", "5", - "PUSH", "5", - "LE", - - "PUSH", "50", - "PUSH", "5", - "GT", - - "PUSH", "5", - "PUSH", "5", - "GE", - - "PUSH", "10", - "PUSH", "10", - "NOT", - - "MYADDRESS", - "TXSENDER", + block := bm.bc.genesisBlock + ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), []string{ + "PUSH", + "1", + "PUSH", + "2", "STOP", }) - tx := NewTransaction("1e8a42ea8cce13", 100, []string{}) - - block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx}) - db.Put(block.Hash(), block.RlpEncode()) - - bm := NewBlockManager() - bm.ProcessBlock(block) + bm.ApplyTransactions(block, []*Transaction{ctrct}) } -*/ diff --git a/ethchain/stack.go b/ethchain/stack.go index c80d01e5c2..02834bd782 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -163,5 +163,12 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println(st.data) + fmt.Println("# val (STACK)") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 1a92582010..46f5e7e4c5 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,11 +1,14 @@ package ethchain import ( + "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" ) +var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + type Transaction struct { Nonce uint64 Recipient []byte @@ -65,7 +68,7 @@ func (tx *Transaction) Hash() []byte { } func (tx *Transaction) IsContract() bool { - return len(tx.Recipient) == 0 + return bytes.Compare(tx.Recipient, ContractAddr) == 0 } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go index c9090b83df..a49768aea2 100644 --- a/ethchain/transaction_test.go +++ b/ethchain/transaction_test.go @@ -2,8 +2,6 @@ package ethchain import ( "encoding/hex" - "fmt" - "github.com/ethereum/eth-go/ethutil" "math/big" "testing" ) @@ -42,13 +40,15 @@ func TestAddressRetrieval2(t *testing.T) { tx.Sign(key) //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") //tx := NewTransactionFromData(data) - fmt.Println(tx.RlpValue()) + /* + fmt.Println(tx.RlpValue()) - fmt.Printf("rlp %x\n", tx.RlpEncode()) - fmt.Printf("sha rlp %x\n", tx.Hash()) + fmt.Printf("rlp %x\n", tx.RlpEncode()) + fmt.Printf("sha rlp %x\n", tx.Hash()) - //tx.Sign(key) + //tx.Sign(key) - fmt.Printf("hex tx key %x\n", tx.PublicKey()) - fmt.Printf("seder %x\n", tx.Sender()) + fmt.Printf("hex tx key %x\n", tx.PublicKey()) + fmt.Printf("seder %x\n", tx.Sender()) + */ } diff --git a/ethereum.go b/ethereum.go index c54303795d..e3038cbf9d 100644 --- a/ethereum.go +++ b/ethereum.go @@ -252,7 +252,7 @@ func (s *Ethereum) Start() { if ethutil.Config.Seed { log.Println("Seeding") // Testnet seed bootstrapping - resp, err := http.Get("http://www.ethereum.org/servers.poc2.txt") + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") if err != nil { log.Println("Fetching seed failed:", err) return diff --git a/ethutil/big.go b/ethutil/big.go index 979078bef9..c41d63add6 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -35,3 +35,9 @@ func BigD(data []byte) *big.Int { return n } + +func BigToBytes(num *big.Int, base int) []byte { + ret := make([]byte, base/8) + + return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) +} diff --git a/ethutil/config.go b/ethutil/config.go index df1772d81d..70553fb5b7 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -34,12 +34,14 @@ func ReadConfig(base string) *config { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) - //Check if the logging directory already exists, create it if not - _, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it", path) - os.Mkdir(path, 0777) + if len(base) > 0 { + //Check if the logging directory already exists, create it if not + _, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it", path) + os.Mkdir(path, 0777) + } } } diff --git a/ethutil/trie.go b/ethutil/trie.go index 95abca6027..c25bd80cb6 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -119,6 +119,10 @@ func (t *Trie) Undo() { t.Root = t.prevRoot } +func (t *Trie) Cache() *Cache { + return t.cache +} + /* * Public (query) interface functions */ From b3da104e569e15c710e6b95ac00c9c2fc80bc9ae Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:26:35 +0100 Subject: [PATCH 0082/1237] Corrected contract addresses --- ethchain/block.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/block.go b/ethchain/block.go index ae654b7d8a..0b4f93e8cc 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -222,7 +222,7 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { // Create contract if there's no recipient if tx.IsContract() { - addr := tx.Hash() + addr := tx.Hash()[12:] value := tx.Value contract := NewContract(value, []byte("")) From 8e7daec886aed591436be111f2b199932b35ddba Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:26:55 +0100 Subject: [PATCH 0083/1237] Added fees and debugging --- ethchain/block_manager.go | 54 ++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 33df338ff8..1fcc06be41 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -301,12 +301,12 @@ func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { // Contract evaluation is done here. func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { - + addr := tx.Hash()[12:] // Instruction pointer pc := 0 blockInfo := bm.bc.BlockInfo(block) - contract := block.GetContract(tx.Hash()) + contract := block.GetContract(addr) if contract == nil { fmt.Println("Contract not found") @@ -318,8 +318,12 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac if ethutil.Config.Debug { fmt.Printf("# op\n") } + + stepcount := 0 + totalFee := new(big.Int) out: for { + stepcount++ // The base big int for all calculations. Use this for any results. base := new(big.Int) // XXX Should Instr return big int slice instead of string slice? @@ -331,12 +335,40 @@ out: o := v.Uint() op := OpCode(o) + var fee *big.Int = new(big.Int) + if stepcount > 16 { + fee.Add(fee, StepFee) + } + + // Calculate the fees + switch op { + /* + FIXME (testnet requires no funds yet) + case oSSTORE: + fee.Add(fee, StoreFee) + case oSLOAD: + fee.Add(fee, StoreFee) + */ + case oEXTRO, oBALANCE: + fee.Add(fee, ExtroFee) + case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: + fee.Add(fee, CryptoFee) + case oMKTX: + fee.Add(fee, ContractFee) + } + + if contract.Amount.Cmp(fee) < 0 { + break + } + // Add the fee to the total fee. It's subtracted when we're done looping + totalFee.Add(totalFee, fee) + if !cb(0) { break } if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s\n", pc, op.String()) + fmt.Printf("%-3d %-4s", pc, op.String()) } switch op { @@ -453,10 +485,6 @@ out: } else { bm.stack.Push(ethutil.BigFalse) } - - // Please note that the following code contains some - // ugly string casting. This will have to change to big - // ints. TODO :) case oMYADDRESS: bm.stack.Push(ethutil.BigD(tx.Hash())) case oTXSENDER: @@ -579,11 +607,10 @@ out: } case oSSTORE: // Store Y at index X - x, y := bm.stack.Popn() + y, x := bm.stack.Popn() idx := ethutil.BigToBytes(x, 256) - val := ethutil.NewValue(y) - //fmt.Printf("STORING VALUE: %v @ %v\n", val.BigInt(), ethutil.BigD(idx)) - contract.State().Update(string(idx), string(val.Encode())) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(idx)) + contract.State().Update(string(idx), string(y.Bytes())) case oJMP: x := int(bm.stack.Pop().Uint64()) // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) @@ -628,9 +655,12 @@ out: default: fmt.Println("Invalid OPCODE", op) } - //bm.stack.Print() + fmt.Println("") + bm.stack.Print() pc++ } + + block.UpdateContract(addr, contract) } // Returns an address from the specified contract's address From dc994b35189950a15fc5397b7f17cda2ba62e0c3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:08 +0100 Subject: [PATCH 0084/1237] Changed fee structure --- ethchain/fees.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index 57017cdc95..0096871d16 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -4,20 +4,18 @@ import ( "math/big" ) -var StepFee *big.Int = new(big.Int) var TxFeeRat *big.Int = big.NewInt(100000000000000) + var TxFee *big.Int = big.NewInt(100) -var ContractFee *big.Int = new(big.Int) -var MemFee *big.Int = new(big.Int) -var DataFee *big.Int = new(big.Int) -var CryptoFee *big.Int = new(big.Int) -var ExtroFee *big.Int = new(big.Int) +var StepFee *big.Int = big.NewInt(1) +var StoreFee *big.Int = big.NewInt(0) +var DataFee *big.Int = big.NewInt(20) +var ExtroFee *big.Int = big.NewInt(40) +var CryptoFee *big.Int = big.NewInt(20) +var ContractFee *big.Int = big.NewInt(100) var BlockReward *big.Int = big.NewInt(1.5e+18) - var UncleReward *big.Int = big.NewInt(1.125e+18) - -//var UncleReward *big.Int = big.NewInt(2e18) var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) var Period1Reward *big.Int = new(big.Int) @@ -26,6 +24,12 @@ var Period3Reward *big.Int = new(big.Int) var Period4Reward *big.Int = new(big.Int) func InitFees() { + StepFee.Mul(StepFee, TxFeeRat) + StoreFee.Mul(StoreFee, TxFeeRat) + DataFee.Mul(DataFee, TxFeeRat) + ExtroFee.Mul(ExtroFee, TxFeeRat) + CryptoFee.Mul(CryptoFee, TxFeeRat) + ContractFee.Mul(ContractFee, TxFeeRat) /* // Base for 2**64 b60 := new(big.Int) From d4cc125456c2531f133aaac6ea73d5decbb80dc4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:22 +0100 Subject: [PATCH 0085/1237] Added more logging functions --- ethutil/config.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index e61c347de0..607152b5b3 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -46,7 +46,7 @@ func ReadConfig(base string) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} - Config.Log = NewLogger(LogFile|LogStd, 0) + Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } return Config @@ -67,7 +67,7 @@ type Logger struct { func NewLogger(flag LoggerType, level int) Logger { var loggers []*log.Logger - flags := log.LstdFlags | log.Lshortfile + flags := log.LstdFlags if flag&LogFile > 0 { file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) @@ -75,20 +75,25 @@ func NewLogger(flag LoggerType, level int) Logger { log.Panic("unable to create file logger", err) } - log := log.New(file, "[ETH]", flags) + log := log.New(file, "", flags) loggers = append(loggers, log) } if flag&LogStd > 0 { - log := log.New(os.Stdout, "[ETH]", flags) + log := log.New(os.Stdout, "", flags) loggers = append(loggers, log) } return Logger{logSys: loggers, logLevel: level} } +const ( + LogLevelDebug = iota + LogLevelInfo +) + func (log Logger) Debugln(v ...interface{}) { - if log.logLevel != 0 { + if log.logLevel != LogLevelDebug { return } @@ -98,7 +103,27 @@ func (log Logger) Debugln(v ...interface{}) { } func (log Logger) Debugf(format string, v ...interface{}) { - if log.logLevel != 0 { + if log.logLevel != LogLevelDebug { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} + +func (log Logger) Infoln(v ...interface{}) { + if log.logLevel > LogLevelInfo { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log Logger) Infof(format string, v ...interface{}) { + if log.logLevel > LogLevelInfo { return } From 39b6eaf51cc278feb817570e7fe02fc7ceefeb9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:27:35 +0100 Subject: [PATCH 0086/1237] Debug logging functions --- ethchain/stack.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 02834bd782..74f3d7ec93 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -163,7 +163,7 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println("# val (STACK)") + fmt.Println("### STACK ###") if len(st.data) > 0 { for i, val := range st.data { fmt.Printf("%-3d %v\n", i, val) @@ -171,4 +171,5 @@ func (st *Stack) Print() { } else { fmt.Println("-- empty --") } + fmt.Println("#############") } From 4afb624c450229b5f0a3554d13de35fd2db8f682 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Feb 2014 16:28:08 +0100 Subject: [PATCH 0087/1237] WIP state object --- ethutil/trie.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethutil/trie.go b/ethutil/trie.go index c25bd80cb6..e900a0a633 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -5,6 +5,15 @@ import ( "reflect" ) +// TODO +// A StateObject is an object that has a state root +// This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) +type StateObject interface { + State() *Trie + Sync() + Undo() +} + type Node struct { Key []byte Value *Value From 9bc5c4a0c5116cf3b49a55fc2aceb5f5c3b3e34d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 14:40:00 +0100 Subject: [PATCH 0088/1237] Long over due Trie delete implemented --- ethutil/trie.go | 88 +++++++++++++++++++++++++++++++++++++++++++- ethutil/trie_test.go | 36 +++++++++++++++++- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index e900a0a633..322f776470 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -148,6 +148,10 @@ func (t *Trie) Get(key string) string { return c.Str() } +func (t *Trie) Delete(key string) { + t.Update(key, "") +} + func (t *Trie) GetState(node interface{}, key []int) interface{} { n := NewValue(node) // Return the node if key is empty (= found) @@ -202,9 +206,10 @@ func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{ return t.InsertState(node, key, value) } else { // delete it + return t.DeleteState(node, key) } - return "" + return t.Root } func (t *Trie) Put(node interface{}) interface{} { @@ -313,6 +318,87 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter return "" } +func (t *Trie) DeleteState(node interface{}, key []int) interface{} { + if len(key) == 0 { + return "" + } + + // New node + n := NewValue(node) + if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { + return "" + } + + currentNode := t.GetNode(node) + // Check for "special" 2 slice type node + if currentNode.Len() == 2 { + // Decode the key + k := CompactDecode(currentNode.Get(0).Str()) + v := currentNode.Get(1).Raw() + + // Matching key pair (ie. there's already an object with this key) + if CompareIntSlice(k, key) { + return "" + } else if CompareIntSlice(key[:len(k)], k) { + hash := t.DeleteState(v, key[len(k):]) + child := t.GetNode(hash) + + var newNode []interface{} + if child.Len() == 2 { + newKey := append(k, CompactDecode(child.Get(0).Str())...) + newNode = []interface{}{CompactEncode(newKey), child.Get(1).Raw()} + } else { + newNode = []interface{}{currentNode.Get(0).Str(), hash} + } + + return t.Put(newNode) + } else { + return node + } + } else { + // Copy the current node over to the new node and replace the first nibble in the key + n := EmptyStringSlice(17) + var newNode []interface{} + + for i := 0; i < 17; i++ { + cpy := currentNode.Get(i).Raw() + if cpy != nil { + n[i] = cpy + } + } + + n[key[0]] = t.DeleteState(n[key[0]], key[1:]) + amount := -1 + for i := 0; i < 17; i++ { + if n[i] != "" { + if amount == -1 { + amount = i + } else { + amount = -2 + } + } + } + if amount == 16 { + newNode = []interface{}{CompactEncode([]int{16}), n[amount]} + } else if amount >= 0 { + child := t.GetNode(n[amount]) + if child.Len() == 17 { + newNode = []interface{}{CompactEncode([]int{amount}), n[amount]} + } else if child.Len() == 2 { + key := append([]int{amount}, CompactDecode(child.Get(0).Str())...) + newNode = []interface{}{CompactEncode(key), child.Get(1).Str()} + } + + } else { + newNode = n + } + + return t.Put(newNode) + } + + return "" +} + // Simple compare function which creates a rlp value out of the evaluated objects func (t *Trie) Cmp(trie *Trie) bool { return NewValue(t.Root).Cmp(NewValue(trie.Root)) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index fa60c8cfc0..9d2c8e19f0 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,8 +1,7 @@ package ethutil import ( - _ "encoding/hex" - _ "fmt" + "reflect" "testing" ) @@ -116,3 +115,36 @@ func TestTrieCmp(t *testing.T) { t.Errorf("Expected tries not to be equal %x %x", trie1.Root, trie2.Root) } } + +func TestTrieDelete(t *testing.T) { + _, trie := New() + trie.Update("cat", LONG_WORD) + exp := trie.Root + trie.Update("dog", LONG_WORD) + trie.Delete("dog") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } + + trie.Update("dog", LONG_WORD) + exp = trie.Root + trie.Update("dude", LONG_WORD) + trie.Delete("dude") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } +} + +func TestTrieDeleteWithValue(t *testing.T) { + _, trie := New() + trie.Update("c", LONG_WORD) + exp := trie.Root + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + trie.Delete("ca") + trie.Delete("cat") + if !reflect.DeepEqual(exp, trie.Root) { + t.Errorf("Expected tries to be equal %x : %x", exp, trie.Root) + } + +} From 059ad352156b995aab9132aff9569c2e03c32b9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:05 +0100 Subject: [PATCH 0089/1237] Type checking --- ethutil/value.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ethutil/value.go b/ethutil/value.go index d3a38f87ff..03d23d5594 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -36,7 +36,8 @@ func (val *Value) Len() int { if data, ok := val.Val.([]interface{}); ok { return len(data) } else if data, ok := val.Val.([]byte); ok { - // FIXME + return len(data) + } else if data, ok := val.Val.(string); ok { return len(data) } @@ -139,6 +140,19 @@ func (val *Value) SliceFromTo(from, to int) *Value { return NewValue(slice[from:to]) } +// TODO More type checking methods +func (val *Value) IsSlice() bool { + return val.Type() == reflect.Slice +} + +func (val *Value) IsStr() bool { + return val.Type() == reflect.String +} + +func (val *Value) IsEmpty() bool { + return (val.IsSlice() || val.IsStr()) && val.Len() == 0 +} + // Threat the value as a slice func (val *Value) Get(idx int) *Value { if d, ok := val.Val.([]interface{}); ok { From 504d356232e11e98a19f9f2b6fd5ee61a5226b1d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:16 +0100 Subject: [PATCH 0090/1237] Added peek(n) --- ethchain/stack.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ethchain/stack.go b/ethchain/stack.go index 74f3d7ec93..e08f840824 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -159,6 +159,22 @@ func (st *Stack) Popn() (*big.Int, *big.Int) { return ints[0], ints[1] } +func (st *Stack) Peek() *big.Int { + s := len(st.data) + + str := st.data[s-1] + + return str +} + +func (st *Stack) Peekn() (*big.Int, *big.Int) { + s := len(st.data) + + ints := st.data[s-2:] + + return ints[0], ints[1] +} + func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } From 8f69c2ac45a1109985ad8cc3b98dcd2e315dc8e9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:36 +0100 Subject: [PATCH 0091/1237] Added contract addr acessors --- ethchain/contract.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethchain/contract.go b/ethchain/contract.go index 70189593b6..5dccb8728b 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -30,6 +30,14 @@ func (c *Contract) RlpDecode(data []byte) { c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) } +func (c *Contract) Addr(addr []byte) *ethutil.Value { + return ethutil.NewValueFromBytes([]byte(c.state.Get(string(addr)))) +} + +func (c *Contract) SetAddr(addr []byte, value interface{}) { + c.state.Update(string(addr), string(ethutil.NewValue(value).Encode())) +} + func (c *Contract) State() *ethutil.Trie { return c.state } From ed05779adb27d715b52de99022b6d927e5fe4706 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:10:43 +0100 Subject: [PATCH 0092/1237] Updated fees --- ethchain/fees.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index 0096871d16..02f09fa04e 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -8,7 +8,7 @@ var TxFeeRat *big.Int = big.NewInt(100000000000000) var TxFee *big.Int = big.NewInt(100) var StepFee *big.Int = big.NewInt(1) -var StoreFee *big.Int = big.NewInt(0) +var StoreFee *big.Int = big.NewInt(5) var DataFee *big.Int = big.NewInt(20) var ExtroFee *big.Int = big.NewInt(40) var CryptoFee *big.Int = big.NewInt(20) From 06ea7fc8308265e80b24352f676315ed4c826b6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Feb 2014 23:11:17 +0100 Subject: [PATCH 0093/1237] re: Added contract fees --- ethchain/block_manager.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 1fcc06be41..1847ba2d4b 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -336,19 +336,23 @@ out: op := OpCode(o) var fee *big.Int = new(big.Int) + var fee2 *big.Int = new(big.Int) if stepcount > 16 { fee.Add(fee, StepFee) } // Calculate the fees switch op { - /* - FIXME (testnet requires no funds yet) - case oSSTORE: - fee.Add(fee, StoreFee) - case oSLOAD: - fee.Add(fee, StoreFee) - */ + case oSSTORE: + y, x := bm.stack.Peekn() + val := contract.Addr(ethutil.BigToBytes(x, 256)) + if val.IsEmpty() && len(y.Bytes()) > 0 { + fee2.Add(DataFee, StoreFee) + } else { + fee2.Sub(DataFee, StoreFee) + } + case oSLOAD: + fee.Add(fee, StoreFee) case oEXTRO, oBALANCE: fee.Add(fee, ExtroFee) case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: @@ -357,11 +361,12 @@ out: fee.Add(fee, ContractFee) } - if contract.Amount.Cmp(fee) < 0 { + tf := new(big.Int).Add(fee, fee2) + if contract.Amount.Cmp(tf) < 0 { break } // Add the fee to the total fee. It's subtracted when we're done looping - totalFee.Add(totalFee, fee) + totalFee.Add(totalFee, tf) if !cb(0) { break @@ -608,9 +613,10 @@ out: case oSSTORE: // Store Y at index X y, x := bm.stack.Popn() - idx := ethutil.BigToBytes(x, 256) - fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(idx)) - contract.State().Update(string(idx), string(y.Bytes())) + addr := ethutil.BigToBytes(x, 256) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) + contract.SetAddr(addr, y) + //contract.State().Update(string(idx), string(y)) case oJMP: x := int(bm.stack.Pop().Uint64()) // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) From f2a1260294b25a31452fd00fe59820467f5cd86a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:36:22 +0100 Subject: [PATCH 0094/1237] Nil is also considered empty --- ethutil/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/value.go b/ethutil/value.go index 03d23d5594..3dd84d12dd 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -150,7 +150,7 @@ func (val *Value) IsStr() bool { } func (val *Value) IsEmpty() bool { - return (val.IsSlice() || val.IsStr()) && val.Len() == 0 + return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) } // Threat the value as a slice From b20c0b1d59f4109c49c7351ddeecbe195912da38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:36:41 +0100 Subject: [PATCH 0095/1237] Removed all old code --- ethutil/parsing.go | 145 +++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 76 deletions(-) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 2c41fb4df2..b43dac0648 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -1,95 +1,88 @@ package ethutil import ( - "errors" - "fmt" "math/big" "strconv" - "strings" ) // Op codes -var OpCodes = map[string]string{ - "STOP": "0", - "ADD": "1", - "MUL": "2", - "SUB": "3", - "DIV": "4", - "SDIV": "5", - "MOD": "6", - "SMOD": "7", - "EXP": "8", - "NEG": "9", - "LT": "10", - "LE": "11", - "GT": "12", - "GE": "13", - "EQ": "14", - "NOT": "15", - "MYADDRESS": "16", - "TXSENDER": "17", - - "PUSH": "48", - "POP": "49", - "LOAD": "54", +var OpCodes = map[string]byte{ + "STOP": 0, + "ADD": 1, + "MUL": 2, + "SUB": 3, + "DIV": 4, + "SDIV": 5, + "MOD": 6, + "SMOD": 7, + "EXP": 8, + "NEG": 9, + "LT": 10, + "LE": 11, + "GT": 12, + "GE": 13, + "EQ": 14, + "NOT": 15, + "MYADDRESS": 16, + "TXSENDER": 17, + "TXVALUE": 18, + "TXFEE": 19, + "TXDATAN": 20, + "TXDATA": 21, + "BLK_PREVHASH": 22, + "BLK_COINBASE": 23, + "BLK_TIMESTAMP": 24, + "BLK_NUMBER": 25, + "BLK_DIFFICULTY": 26, + "BASEFEE": 27, + "SHA256": 32, + "RIPEMD160": 33, + "ECMUL": 34, + "ECADD": 35, + "ECSIGN": 36, + "ECRECOVER": 37, + "ECVALID": 38, + "SHA3": 39, + "PUSH": 48, + "POP": 49, + "DUP": 50, + "SWAP": 51, + "MLOAD": 52, + "MSTORE": 53, + "SLOAD": 54, + "SSTORE": 55, + "JMP": 56, + "JMPI": 57, + "IND": 58, + "EXTRO": 59, + "BALANCE": 60, + "MKTX": 61, + "SUICIDE": 62, } -func CompileInstr(s string) (string, error) { - tokens := strings.Split(s, " ") - if OpCodes[tokens[0]] == "" { - return s, errors.New(fmt.Sprintf("OP not found: %s", tokens[0])) +func IsOpCode(s string) bool { + for key, _ := range OpCodes { + if key == s { + return true + } + } + return false +} + +func CompileInstr(s string) ([]byte, error) { + isOp := IsOpCode(s) + if isOp { + return []byte{OpCodes[s]}, nil } - code := OpCodes[tokens[0]] // Replace op codes with the proper numerical equivalent - op := new(big.Int) - op.SetString(code, 0) + num := new(big.Int) + num.SetString(s, 0) - args := make([]*big.Int, 6) - for i, val := range tokens[1:len(tokens)] { - num := new(big.Int) - num.SetString(val, 0) - args[i] = num - } - - // Big int equation = op + x * 256 + y * 256**2 + z * 256**3 + a * 256**4 + b * 256**5 + c * 256**6 - base := new(big.Int) - x := new(big.Int) - y := new(big.Int) - z := new(big.Int) - a := new(big.Int) - b := new(big.Int) - c := new(big.Int) - - if args[0] != nil { - x.Mul(args[0], big.NewInt(256)) - } - if args[1] != nil { - y.Mul(args[1], BigPow(256, 2)) - } - if args[2] != nil { - z.Mul(args[2], BigPow(256, 3)) - } - if args[3] != nil { - a.Mul(args[3], BigPow(256, 4)) - } - if args[4] != nil { - b.Mul(args[4], BigPow(256, 5)) - } - if args[5] != nil { - c.Mul(args[5], BigPow(256, 6)) - } - - base.Add(op, x) - base.Add(base, y) - base.Add(base, z) - base.Add(base, a) - base.Add(base, b) - base.Add(base, c) - - return base.String(), nil + return num.Bytes(), nil } func Instr(instr string) (int, []string, error) { + base := new(big.Int) base.SetString(instr, 0) From 681eacaa7fdda41fe168baba03095ee74708444f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:37:06 +0100 Subject: [PATCH 0096/1237] Removed old instruction code --- ethchain/transaction.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 46f5e7e4c5..2417bbd7d7 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -26,12 +26,9 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { // Serialize the data tx.Data = make([]string, len(data)) for i, val := range data { - instr, err := ethutil.CompileInstr(val) - if err != nil { - //fmt.Printf("compile error:%d %v\n", i+1, err) - } + instr, _ := ethutil.CompileInstr(val) - tx.Data[i] = instr + tx.Data[i] = string(instr) } return &tx From 18cc35338afc8a3843716af0d96bd03d36e735ea Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 12:37:16 +0100 Subject: [PATCH 0097/1237] Fixed contract running --- ethchain/block_manager.go | 18 ++++++++++-------- ethchain/block_manager_test.go | 1 - 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 1847ba2d4b..91bcaa4685 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -321,19 +321,20 @@ func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallbac stepcount := 0 totalFee := new(big.Int) + + // helper function for getting a contract's memory address + getMem := func(num int) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) + return contract.Addr(nb) + } out: for { stepcount++ // The base big int for all calculations. Use this for any results. base := new(big.Int) - // XXX Should Instr return big int slice instead of string slice? - // Get the next instruction from the contract - nb := ethutil.BigToBytes(big.NewInt(int64(pc)), 256) - r := contract.State().Get(string(nb)) - v := ethutil.NewValueFromBytes([]byte(r)) + val := getMem(pc) //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) - o := v.Uint() - op := OpCode(o) + op := OpCode(val.Uint()) var fee *big.Int = new(big.Int) var fee2 *big.Int = new(big.Int) @@ -378,6 +379,7 @@ out: switch op { case oSTOP: + fmt.Println("") break out case oADD: x, y := bm.stack.Popn() @@ -580,7 +582,7 @@ out: case oECVALID: case oPUSH: pc++ - bm.stack.Push(bm.mem[strconv.Itoa(pc)]) + bm.stack.Push(getMem(pc).BigInt()) case oPOP: // Pop current value of the stack bm.stack.Pop() diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index ae29e2e254..853d459d80 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -22,7 +22,6 @@ func TestVm(t *testing.T) { "1", "PUSH", "2", - "STOP", }) bm.ApplyTransactions(block, []*Transaction{ctrct}) From cca8585554119a4dc02c6720948012bf876a1db8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Feb 2014 13:05:59 +0100 Subject: [PATCH 0098/1237] Get a chain of blocks made simple --- ethchain/block_chain.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 5b55782a9e..21f540b963 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethutil" "log" "math" @@ -111,6 +112,25 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { return chain } +func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { + genHash := bc.genesisBlock.Hash() + + block := bc.GetBlock(hash) + var blocks []*Block + + for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) { + fmt.Println(block) + blocks = append([]*Block{block}, blocks...) + + if bytes.Compare(genHash, block.Hash()) == 0 { + break + } + i++ + } + + return blocks +} + func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { @@ -147,6 +167,9 @@ func (bc *BlockChain) Add(block *Block) { func (bc *BlockChain) GetBlock(hash []byte) *Block { data, _ := ethutil.Config.Db.Get(hash) + if len(data) == 0 { + return nil + } return NewBlockFromData(data) } From 4bfd717ba2b753f183e9e3fecd91d7e4083aaffc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 01:53:09 +0100 Subject: [PATCH 0099/1237] Added the ability to extend the logger with more sub systems --- ethutil/config.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index 607152b5b3..5bf56134d1 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "log" "os" "os/user" @@ -18,7 +19,7 @@ const ( type config struct { Db Database - Log Logger + Log *Logger ExecPath string Debug bool Ver string @@ -45,7 +46,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.2.3"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.3.0"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } @@ -59,13 +60,18 @@ const ( LogStd = 0x2 ) +type LogSystem interface { + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + type Logger struct { - logSys []*log.Logger + logSys []LogSystem logLevel int } -func NewLogger(flag LoggerType, level int) Logger { - var loggers []*log.Logger +func NewLogger(flag LoggerType, level int) *Logger { + var loggers []LogSystem flags := log.LstdFlags @@ -84,7 +90,11 @@ func NewLogger(flag LoggerType, level int) Logger { loggers = append(loggers, log) } - return Logger{logSys: loggers, logLevel: level} + return &Logger{logSys: loggers, logLevel: level} +} + +func (log *Logger) AddLogSystem(logger LogSystem) { + log.logSys = append(log.logSys, logger) } const ( @@ -92,7 +102,7 @@ const ( LogLevelInfo ) -func (log Logger) Debugln(v ...interface{}) { +func (log *Logger) Debugln(v ...interface{}) { if log.logLevel != LogLevelDebug { return } @@ -102,7 +112,7 @@ func (log Logger) Debugln(v ...interface{}) { } } -func (log Logger) Debugf(format string, v ...interface{}) { +func (log *Logger) Debugf(format string, v ...interface{}) { if log.logLevel != LogLevelDebug { return } @@ -112,17 +122,18 @@ func (log Logger) Debugf(format string, v ...interface{}) { } } -func (log Logger) Infoln(v ...interface{}) { +func (log *Logger) Infoln(v ...interface{}) { if log.logLevel > LogLevelInfo { return } + fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } } -func (log Logger) Infof(format string, v ...interface{}) { +func (log *Logger) Infof(format string, v ...interface{}) { if log.logLevel > LogLevelInfo { return } From 73b9ae95797ce8c38d82cfcb7c793efea268f476 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Feb 2014 01:53:25 +0100 Subject: [PATCH 0100/1237] Updated some of the log statements to use the ethutil logger --- ethchain/block_chain.go | 2 -- ethereum.go | 16 ++++++++-------- peer.go | 30 ++++++++++++++---------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 21f540b963..96d22366d6 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethutil" "log" "math" @@ -119,7 +118,6 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { var blocks []*Block for i := 0; i < amount && block != nil; block = bc.GetBlock(block.PrevHash) { - fmt.Println(block) blocks = append([]*Block{block}, blocks...) if bytes.Compare(genHash, block.Hash()) == 0 { diff --git a/ethereum.go b/ethereum.go index e3038cbf9d..f86cb121e6 100644 --- a/ethereum.go +++ b/ethereum.go @@ -70,7 +70,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { if usePnp { nat, err = Discover() if err != nil { - log.Println("UPnP failed", err) + ethutil.Config.Log.Debugln("UPnP failed", err) } } @@ -234,7 +234,7 @@ func (s *Ethereum) Start() { log.Println("Connection listening disabled. Acting as client") } else { // Starting accepting connections - log.Println("Ready and accepting connections") + ethutil.Config.Log.Infoln("Ready and accepting connections") // Start the peer handler go s.peerHandler(ln) } @@ -250,7 +250,7 @@ func (s *Ethereum) Start() { s.TxPool.Start() if ethutil.Config.Seed { - log.Println("Seeding") + ethutil.Config.Log.Debugln("Seeding") // Testnet seed bootstrapping resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") if err != nil { @@ -272,7 +272,7 @@ func (s *Ethereum) peerHandler(listener net.Listener) { for { conn, err := listener.Accept() if err != nil { - log.Println(err) + ethutil.Config.Log.Debugln(err) continue } @@ -315,13 +315,13 @@ out: var err error _, err = s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) if err != nil { - log.Println("can't add UPnP port mapping:", err) + ethutil.Config.Log.Debugln("can't add UPnP port mapping:", err) break out } if first && err == nil { _, err = s.nat.GetExternalAddress() if err != nil { - log.Println("UPnP can't get external address:", err) + ethutil.Config.Log.Debugln("UPnP can't get external address:", err) continue out } first = false @@ -335,8 +335,8 @@ out: timer.Stop() if err := s.nat.DeletePortMapping("TCP", int(lport), int(lport)); err != nil { - log.Println("unable to remove UPnP port mapping:", err) + ethutil.Config.Log.Debugln("unable to remove UPnP port mapping:", err) } else { - log.Println("succesfully disestablished UPnP port mapping") + ethutil.Config.Log.Debugln("succesfully disestablished UPnP port mapping") } } diff --git a/peer.go b/peer.go index ed81ddd8ed..9538e65003 100644 --- a/peer.go +++ b/peer.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" "net" "runtime" "strconv" @@ -165,7 +164,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { conn, err := net.DialTimeout("tcp", addr, 30*time.Second) if err != nil { - log.Println("Connection to peer failed", err) + ethutil.Config.Log.Debugln("Connection to peer failed", err) p.Stop() return } @@ -202,7 +201,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { err := ethwire.WriteMessage(p.conn, msg) if err != nil { - log.Println("Can't send message:", err) + ethutil.Config.Log.Debugln("Can't send message:", err) // Stop the client if there was an error writing to it p.Stop() return @@ -264,7 +263,7 @@ func (p *Peer) HandleInbound() { // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { - log.Println(err) + ethutil.Config.Log.Debugln(err) } for _, msg := range msgs { switch msg.Type { @@ -277,7 +276,7 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgDiscTy: p.Stop() - log.Println("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) + ethutil.Config.Log.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) case ethwire.MsgPingTy: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) @@ -296,9 +295,8 @@ func (p *Peer) HandleInbound() { if err != nil { if ethutil.Config.Debug { - log.Printf("[PEER] Block %x failed\n", block.Hash()) - log.Printf("[PEER] %v\n", err) - log.Println(block) + ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash()) + ethutil.Config.Log.Infof("[PEER] %v\n", err) } break } else { @@ -309,7 +307,7 @@ func (p *Peer) HandleInbound() { if err != nil { // If the parent is unknown try to catch up with this peer if ethchain.IsParentErr(err) { - log.Println("Attempting to catch up") + ethutil.Config.Log.Infoln("Attempting to catch up") p.catchingUp = false p.CatchupWithPeer() } else if ethchain.IsValidationErr(err) { @@ -321,7 +319,7 @@ func (p *Peer) HandleInbound() { if p.catchingUp && msg.Data.Len() > 1 { if ethutil.Config.Debug && lastBlock != nil { blockInfo := lastBlock.BlockInfo() - log.Printf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false p.CatchupWithPeer() @@ -392,12 +390,12 @@ func (p *Peer) HandleInbound() { p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) } case ethwire.MsgNotInChainTy: - log.Printf("Not in chain %x\n", msg.Data) + ethutil.Config.Log.Infoln("Not in chain %x\n", msg.Data) // TODO // Unofficial but fun nonetheless case ethwire.MsgTalkTy: - log.Printf("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) + ethutil.Config.Log.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) } } } @@ -440,7 +438,7 @@ func (p *Peer) Start() { err := p.pushHandshake() if err != nil { - log.Println("Peer can't send outbound version ack", err) + ethutil.Config.Log.Debugln("Peer can't send outbound version ack", err) p.Stop() @@ -499,7 +497,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data if c.Get(0).Uint() != 5 { - log.Println("Invalid peer version. Require protocol v4") + ethutil.Config.Log.Debugln("Invalid peer version. Require protocol v5") p.Stop() return } @@ -531,7 +529,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { // Get a reference to the peers version p.Version = c.Get(2).Str() - log.Println("[PEER]", p) + ethutil.Config.Log.Debugln("[PEER]", p) } func (p *Peer) String() string { @@ -558,7 +556,7 @@ func (p *Peer) CatchupWithPeer() { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)}) p.QueueMessage(msg) - log.Printf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) + ethutil.Config.Log.Debugln("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) } } From c66cf95b4019eeaf49db0c02cc7cb73c78098f5e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:56:48 +0100 Subject: [PATCH 0101/1237] Added address states for storing a session based address --- ethchain/address.go | 60 +++++++++++++++++++++++++++++++++++++++ ethchain/address_test.go | 8 ++++++ ethchain/block_manager.go | 36 ++++++++++++++++++----- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 ethchain/address.go create mode 100644 ethchain/address_test.go diff --git a/ethchain/address.go b/ethchain/address.go new file mode 100644 index 0000000000..a228c7566f --- /dev/null +++ b/ethchain/address.go @@ -0,0 +1,60 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Address struct { + Amount *big.Int + Nonce uint64 +} + +func NewAddress(amount *big.Int) *Address { + return &Address{Amount: amount, Nonce: 0} +} + +func NewAddressFromData(data []byte) *Address { + address := &Address{} + address.RlpDecode(data) + + return address +} + +func (a *Address) AddFee(fee *big.Int) { + a.Amount.Add(a.Amount, fee) +} + +func (a *Address) RlpEncode() []byte { + return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) +} + +func (a *Address) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + a.Amount = decoder.Get(0).BigInt() + a.Nonce = decoder.Get(1).Uint() +} + +type AddrStateStore struct { + states map[string]*AddressState +} + +func NewAddrStateStore() *AddrStateStore { + return &AddrStateStore{states: make(map[string]*AddressState)} +} + +func (s *AddrStateStore) Add(addr []byte, account *Address) *AddressState { + state := &AddressState{Nonce: account.Nonce, Account: account} + s.states[string(addr)] = state + return state +} + +func (s *AddrStateStore) Get(addr []byte) *AddressState { + return s.states[string(addr)] +} + +type AddressState struct { + Nonce uint64 + Account *Address +} diff --git a/ethchain/address_test.go b/ethchain/address_test.go new file mode 100644 index 0000000000..161e1b251e --- /dev/null +++ b/ethchain/address_test.go @@ -0,0 +1,8 @@ +package ethchain + +import ( + "testing" +) + +func TestAddressState(t *testing.T) { +} diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 91bcaa4685..b82e5a74ab 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" + _ "github.com/ethereum/eth-go/ethwire" "github.com/obscuren/secp256k1-go" "log" "math" @@ -19,6 +19,7 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +// TODO rename to state manager type BlockManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -26,6 +27,10 @@ type BlockManager struct { // The block chain :) bc *BlockChain + // States for addresses. You can watch any address + // at any given time + addrStateStore *AddrStateStore + // Stack for processing contracts stack *Stack // non-persistent key/value memory storage @@ -58,11 +63,12 @@ func AddTestNetFunds(block *Block) { func NewBlockManager(speaker PublicSpeaker) *BlockManager { bm := &BlockManager{ //server: s, - bc: NewBlockChain(), - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Speaker: speaker, + bc: NewBlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Speaker: speaker, + addrStateStore: NewAddrStateStore(), } if bm.bc.CurrentBlock == nil { @@ -81,6 +87,22 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { return bm } +// Watches any given address and puts it in the address state store +func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { + account := bm.bc.CurrentBlock.GetAddr(addr) + + return bm.addrStateStore.Add(addr, account) +} + +func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { + addrState := bm.addrStateStore.Get(addr) + if addrState == nil { + addrState = bm.WatchAddr(addr) + } + + return addrState +} + func (bm *BlockManager) BlockChain() *BlockChain { return bm.bc } @@ -165,7 +187,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { */ // Broadcast the valid block back to the wire - bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // If there's a block processor present, pass in the block for further // processing From f5737b929a972102b16e4b206a52b1e36b508860 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:57:04 +0100 Subject: [PATCH 0102/1237] Added a secondary processor --- ethchain/transaction_pool.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 75a8aa5d1d..1278cc4dc7 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -34,6 +34,10 @@ type PublicSpeaker interface { Broadcast(msgType ethwire.MsgType, data []interface{}) } +type TxProcessor interface { + ProcessTransaction(tx *Transaction) +} + // The tx pool a thread safe transaction pool handler. In order to // guarantee a non blocking pool we use a queue channel which can be // independently read without needing access to the actual pool. If the @@ -54,7 +58,7 @@ type TxPool struct { BlockManager *BlockManager - Hook TxPoolHook + SecondaryProcessor TxProcessor } func NewTxPool() *TxPool { @@ -69,12 +73,14 @@ func NewTxPool() *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { + log.Println("Adding tx to pool") pool.mutex.Lock() pool.pool.PushBack(tx) pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) + log.Println("broadcasting it") } // Process transaction validates the Tx and processes funds from the @@ -179,8 +185,8 @@ out: // doesn't matter since this is a goroutine pool.addTransaction(tx) - if pool.Hook != nil { - pool.Hook <- tx + if pool.SecondaryProcessor != nil { + pool.SecondaryProcessor.ProcessTransaction(tx) } } case <-pool.quit: From a4a4ffbeff2fd9082f2c96330ea0915ae1b6e6c1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:57:22 +0100 Subject: [PATCH 0103/1237] Moved address --- ethchain/contract.go | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/ethchain/contract.go b/ethchain/contract.go index 5dccb8728b..68ec39f0b4 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -41,34 +41,3 @@ func (c *Contract) SetAddr(addr []byte, value interface{}) { func (c *Contract) State() *ethutil.Trie { return c.state } - -type Address struct { - Amount *big.Int - Nonce uint64 -} - -func NewAddress(amount *big.Int) *Address { - return &Address{Amount: amount, Nonce: 0} -} - -func NewAddressFromData(data []byte) *Address { - address := &Address{} - address.RlpDecode(data) - - return address -} - -func (a *Address) AddFee(fee *big.Int) { - a.Amount.Add(a.Amount, fee) -} - -func (a *Address) RlpEncode() []byte { - return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) -} - -func (a *Address) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - a.Amount = decoder.Get(0).BigInt() - a.Nonce = decoder.Get(1).Uint() -} From 3a45cdeaf9682dea0407f827571353220eaf257b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 23 Feb 2014 01:57:45 +0100 Subject: [PATCH 0104/1237] Moved txpool start to initialisation method of ethereumm --- ethereum.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ethereum.go b/ethereum.go index f86cb121e6..725fe5a3d1 100644 --- a/ethereum.go +++ b/ethereum.go @@ -47,6 +47,7 @@ type Ethereum struct { Nonce uint64 Addr net.Addr + Port string peerMut sync.Mutex @@ -93,6 +94,9 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { ethereum.TxPool.BlockManager = ethereum.BlockManager ethereum.BlockManager.TransactionPool = ethereum.TxPool + // Start the tx pool + ethereum.TxPool.Start() + return ethereum, nil } @@ -229,7 +233,7 @@ func (s *Ethereum) ReapDeadPeerHandler() { // Start the ethereum func (s *Ethereum) Start() { // Bind to addr and port - ln, err := net.Listen("tcp", ":30303") + ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { log.Println("Connection listening disabled. Acting as client") } else { @@ -246,9 +250,6 @@ func (s *Ethereum) Start() { // Start the reaping processes go s.ReapDeadPeerHandler() - // Start the tx pool - s.TxPool.Start() - if ethutil.Config.Seed { ethutil.Config.Log.Debugln("Seeding") // Testnet seed bootstrapping @@ -306,7 +307,7 @@ func (s *Ethereum) upnpUpdateThread() { // Go off immediately to prevent code duplication, thereafter we renew // lease every 15 minutes. timer := time.NewTimer(0 * time.Second) - lport, _ := strconv.ParseInt("30303", 10, 16) + lport, _ := strconv.ParseInt(s.Port, 10, 16) first := true out: for { From 8ecb24f1141013a935b0f7e858ef7273d67de5e5 Mon Sep 17 00:00:00 2001 From: Joey Zhou Date: Sun, 23 Feb 2014 14:43:18 -0800 Subject: [PATCH 0105/1237] parse now returns byte[] instead of string --- ethutil/parsing_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 482eef3ee8..69a5e9016b 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -13,7 +13,7 @@ func TestCompile(t *testing.T) { } calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) - if Big(instr).Int64() != calc { + if BigD(instr).Int64() != calc { t.Error("Expected", calc, ", got:", instr) } } From 377c9951033d4f8d157221fd36d15c39ae17cddc Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:10:45 +0100 Subject: [PATCH 0106/1237] Separated the VM from the block manager and added states --- ethchain/state.go | 56 ++++++ ethchain/vm.go | 437 ++++++++++++++++++++++++++++++++++++++++++++ ethchain/vm_test.go | 106 +++++++++++ 3 files changed, 599 insertions(+) create mode 100644 ethchain/state.go create mode 100644 ethchain/vm.go create mode 100644 ethchain/vm_test.go diff --git a/ethchain/state.go b/ethchain/state.go new file mode 100644 index 0000000000..1a18ea1d79 --- /dev/null +++ b/ethchain/state.go @@ -0,0 +1,56 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type State struct { + trie *ethutil.Trie +} + +func NewState(trie *ethutil.Trie) *State { + return &State{trie: trie} +} + +func (s *State) GetContract(addr []byte) *Contract { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + contract := &Contract{} + contract.RlpDecode([]byte(data)) + + return contract +} + +func (s *State) UpdateContract(addr []byte, contract *Contract) { + s.trie.Update(string(addr), string(contract.RlpEncode())) +} + +func Compile(code []string) (script []string) { + script = make([]string, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = string(instr) + } + + return +} + +func (s *State) GetAccount(addr []byte) (account *Address) { + data := s.trie.Get(string(addr)) + if data == "" { + account = NewAddress(big.NewInt(0)) + } else { + account = NewAddressFromData([]byte(data)) + } + + return +} + +func (s *State) UpdateAccount(addr []byte, account *Address) { + s.trie.Update(string(addr), string(account.RlpEncode())) +} diff --git a/ethchain/vm.go b/ethchain/vm.go new file mode 100644 index 0000000000..d5f4d7ad6c --- /dev/null +++ b/ethchain/vm.go @@ -0,0 +1,437 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" + "log" + "math" + "math/big" +) + +type Vm struct { + txPool *TxPool + // Stack for processing contracts + stack *Stack + // non-persistent key/value memory storage + mem map[string]*big.Int + + vars RuntimeVars +} + +type RuntimeVars struct { + address []byte + blockNumber uint64 + sender []byte + prevHash []byte + coinbase []byte + time int64 + diff *big.Int + txValue *big.Int + txData []string +} + +func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { + vm.mem = make(map[string]*big.Int) + vm.stack = NewStack() + + addr := vars.address // tx.Hash()[12:] + // Instruction pointer + pc := 0 + + if contract == nil { + fmt.Println("Contract not found") + return + } + + Pow256 := ethutil.BigPow(2, 256) + + if ethutil.Config.Debug { + fmt.Printf("# op\n") + } + + stepcount := 0 + totalFee := new(big.Int) + +out: + for { + stepcount++ + // The base big int for all calculations. Use this for any results. + base := new(big.Int) + val := contract.GetMem(pc) + //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) + op := OpCode(val.Uint()) + + var fee *big.Int = new(big.Int) + var fee2 *big.Int = new(big.Int) + if stepcount > 16 { + fee.Add(fee, StepFee) + } + + // Calculate the fees + switch op { + case oSSTORE: + y, x := vm.stack.Peekn() + val := contract.Addr(ethutil.BigToBytes(x, 256)) + if val.IsEmpty() && len(y.Bytes()) > 0 { + fee2.Add(DataFee, StoreFee) + } else { + fee2.Sub(DataFee, StoreFee) + } + case oSLOAD: + fee.Add(fee, StoreFee) + case oEXTRO, oBALANCE: + fee.Add(fee, ExtroFee) + case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: + fee.Add(fee, CryptoFee) + case oMKTX: + fee.Add(fee, ContractFee) + } + + tf := new(big.Int).Add(fee, fee2) + if contract.Amount.Cmp(tf) < 0 { + fmt.Println("Contract fee", ContractFee) + fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) + break + } + // Add the fee to the total fee. It's subtracted when we're done looping + totalFee.Add(totalFee, tf) + + if ethutil.Config.Debug { + fmt.Printf("%-3d %-4s", pc, op.String()) + } + + switch op { + case oSTOP: + fmt.Println("") + break out + case oADD: + x, y := vm.stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oSUB: + x, y := vm.stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oMUL: + x, y := vm.stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base) + case oDIV: + x, y := vm.stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + vm.stack.Push(base) + case oSDIV: + x, y := vm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Div(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + vm.stack.Push(z) + case oMOD: + x, y := vm.stack.Popn() + base.Mod(x, y) + vm.stack.Push(base) + case oSMOD: + x, y := vm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Mod(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + vm.stack.Push(z) + case oEXP: + x, y := vm.stack.Popn() + base.Exp(x, y, Pow256) + + vm.stack.Push(base) + case oNEG: + base.Sub(Pow256, vm.stack.Pop()) + vm.stack.Push(base) + case oLT: + x, y := vm.stack.Popn() + // x < y + if x.Cmp(y) < 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oLE: + x, y := vm.stack.Popn() + // x <= y + if x.Cmp(y) < 1 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := vm.stack.Popn() + // x > y + if x.Cmp(y) > 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oGE: + x, y := vm.stack.Popn() + // x >= y + if x.Cmp(y) > -1 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := vm.stack.Popn() + // x != y + if x.Cmp(y) != 0 { + vm.stack.Push(ethutil.BigTrue) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oMYADDRESS: + vm.stack.Push(ethutil.BigD(addr)) + case oTXSENDER: + vm.stack.Push(ethutil.BigD(vars.sender)) + case oTXVALUE: + vm.stack.Push(vars.txValue) + case oTXDATAN: + vm.stack.Push(big.NewInt(int64(len(vars.txData)))) + case oTXDATA: + v := vm.stack.Pop() + // v >= len(data) + if v.Cmp(big.NewInt(int64(len(vars.txData)))) >= 0 { + vm.stack.Push(ethutil.Big("0")) + } else { + vm.stack.Push(ethutil.Big(vars.txData[v.Uint64()])) + } + case oBLK_PREVHASH: + vm.stack.Push(ethutil.BigD(vars.prevHash)) + case oBLK_COINBASE: + vm.stack.Push(ethutil.BigD(vars.coinbase)) + case oBLK_TIMESTAMP: + vm.stack.Push(big.NewInt(vars.time)) + case oBLK_NUMBER: + vm.stack.Push(big.NewInt(int64(vars.blockNumber))) + case oBLK_DIFFICULTY: + vm.stack.Push(vars.diff) + case oBASEFEE: + // e = 10^21 + e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) + d := new(big.Rat) + d.SetInt(vars.diff) + c := new(big.Rat) + c.SetFloat64(0.5) + // d = diff / 0.5 + d.Quo(d, c) + // base = floor(d) + base.Div(d.Num(), d.Denom()) + + x := new(big.Int) + x.Div(e, base) + + // x = floor(10^21 / floor(diff^0.5)) + vm.stack.Push(x) + case oSHA256, oSHA3, oRIPEMD160: + // This is probably save + // ceil(pop / 32) + length := int(math.Ceil(float64(vm.stack.Pop().Uint64()) / 32.0)) + // New buffer which will contain the concatenated popped items + data := new(bytes.Buffer) + for i := 0; i < length; i++ { + // Encode the number to bytes and have it 32bytes long + num := ethutil.NumberToBytes(vm.stack.Pop().Bytes(), 256) + data.WriteString(string(num)) + } + + if op == oSHA256 { + vm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) + } else if op == oSHA3 { + vm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) + } else { + vm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) + } + case oECMUL: + y := vm.stack.Pop() + x := vm.stack.Pop() + //n := vm.stack.Pop() + + //if ethutil.Big(x).Cmp(ethutil.Big(y)) { + data := new(bytes.Buffer) + data.WriteString(x.String()) + data.WriteString(y.String()) + if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { + // TODO + } else { + // Invalid, push infinity + vm.stack.Push(ethutil.Big("0")) + vm.stack.Push(ethutil.Big("0")) + } + //} else { + // // Invalid, push infinity + // vm.stack.Push("0") + // vm.stack.Push("0") + //} + + case oECADD: + case oECSIGN: + case oECRECOVER: + case oECVALID: + case oPUSH: + pc++ + vm.stack.Push(contract.GetMem(pc).BigInt()) + case oPOP: + // Pop current value of the stack + vm.stack.Pop() + case oDUP: + // Dup top stack + x := vm.stack.Pop() + vm.stack.Push(x) + vm.stack.Push(x) + case oSWAP: + // Swap two top most values + x, y := vm.stack.Popn() + vm.stack.Push(y) + vm.stack.Push(x) + case oMLOAD: + x := vm.stack.Pop() + vm.stack.Push(vm.mem[x.String()]) + case oMSTORE: + x, y := vm.stack.Popn() + vm.mem[x.String()] = y + case oSLOAD: + // Load the value in storage and push it on the stack + x := vm.stack.Pop() + // decode the object as a big integer + decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) + if !decoder.IsNil() { + vm.stack.Push(decoder.BigInt()) + } else { + vm.stack.Push(ethutil.BigFalse) + } + case oSSTORE: + // Store Y at index X + y, x := vm.stack.Popn() + addr := ethutil.BigToBytes(x, 256) + fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) + contract.SetAddr(addr, y) + //contract.State().Update(string(idx), string(y)) + case oJMP: + x := int(vm.stack.Pop().Uint64()) + // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) + pc = x + pc-- + case oJMPI: + x := vm.stack.Pop() + // Set pc to x if it's non zero + if x.Cmp(ethutil.BigFalse) != 0 { + pc = int(x.Uint64()) + pc-- + } + case oIND: + vm.stack.Push(big.NewInt(int64(pc))) + case oEXTRO: + memAddr := vm.stack.Pop() + contractAddr := vm.stack.Pop().Bytes() + + // Push the contract's memory on to the stack + vm.stack.Push(contractMemory(state, contractAddr, memAddr)) + case oBALANCE: + // Pushes the balance of the popped value on to the stack + account := state.GetAccount(vm.stack.Pop().Bytes()) + vm.stack.Push(account.Amount) + case oMKTX: + addr, value := vm.stack.Popn() + from, length := vm.stack.Popn() + + makeInlineTx(addr.Bytes(), value, from, length, contract, state) + case oSUICIDE: + recAddr := vm.stack.Pop().Bytes() + // Purge all memory + deletedMemory := contract.state.NewIterator().Purge() + // Add refunds to the pop'ed address + refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) + account := state.GetAccount(recAddr) + account.Amount.Add(account.Amount, refund) + // Update the refunding address + state.UpdateAccount(recAddr, account) + // Delete the contract + state.trie.Update(string(addr), "") + + fmt.Printf("(%d) => %x\n", deletedMemory, recAddr) + break out + default: + fmt.Printf("Invalid OPCODE: %x\n", op) + } + fmt.Println("") + vm.stack.Print() + pc++ + } + + state.UpdateContract(addr, contract) +} + +func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { + fmt.Printf(" => creating inline tx %x %v %v %v", addr, value, from, length) + j := 0 + dataItems := make([]string, int(length.Uint64())) + for i := from.Uint64(); i < length.Uint64(); i++ { + dataItems[j] = contract.GetMem(j).Str() + j++ + } + + tx := NewTransaction(addr, value, dataItems) + if tx.IsContract() { + contract := MakeContract(tx, state) + state.UpdateContract(tx.Hash()[12:], contract) + } else { + account := state.GetAccount(tx.Recipient) + account.Amount.Add(account.Amount, tx.Value) + state.UpdateAccount(tx.Recipient, account) + } +} + +// Returns an address from the specified contract's address +func contractMemory(state *State, contractAddr []byte, memAddr *big.Int) *big.Int { + contract := state.GetContract(contractAddr) + if contract == nil { + log.Panicf("invalid contract addr %x", contractAddr) + } + val := state.trie.Get(memAddr.String()) + + // decode the object as a big integer + decoder := ethutil.NewValueFromBytes([]byte(val)) + if decoder.IsNil() { + return ethutil.BigFalse + } + + return decoder.BigInt() +} diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go new file mode 100644 index 0000000000..6ceb0ff150 --- /dev/null +++ b/ethchain/vm_test.go @@ -0,0 +1,106 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "testing" +) + +func TestRun(t *testing.T) { + InitFees() + + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "TXSENDER", + "SUICIDE", + }) + + tx := NewTransaction(ContractAddr, big.NewInt(1e17), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} + +func TestRun1(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "0", + "PUSH", "0", + "TXSENDER", + "PUSH", "10000000", + "MKTX", + }) + fmt.Println(ethutil.NewValue(script)) + + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} + +func TestRun2(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "0", + "PUSH", "0", + "TXSENDER", + "PUSH", "10000000", + "MKTX", + }) + fmt.Println(ethutil.NewValue(script)) + + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + fmt.Printf("contract addr %x\n", tx.Hash()[12:]) + contract := MakeContract(tx, state) + vm := &Vm{} + + vm.Process(contract, state, RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: tx.Value, + txData: tx.Data, + }) +} From 1a98bbf1c858ed4bafcc7ffa146a30e40ef919b0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:11:00 +0100 Subject: [PATCH 0107/1237] Added a trie iterator --- ethutil/trie.go | 85 ++++++++++++++++++++++++++++++++++++++++++++ ethutil/trie_test.go | 24 +++++++++++++ 2 files changed, 109 insertions(+) diff --git a/ethutil/trie.go b/ethutil/trie.go index 322f776470..83527d364f 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -70,6 +70,12 @@ func (cache *Cache) Get(key []byte) *Value { return value } +func (cache *Cache) Delete(key []byte) { + delete(cache.nodes, string(key)) + + cache.db.Delete(key) +} + func (cache *Cache) Commit() { // Don't try to commit if it isn't dirty if !cache.IsDirty { @@ -413,3 +419,82 @@ func (t *Trie) Copy() *Trie { return trie } + +type TrieIterator struct { + trie *Trie + key string + value string + + shas [][]byte + values []string +} + +func (t *Trie) NewIterator() *TrieIterator { + return &TrieIterator{trie: t} +} + +// Some time in the near future this will need refactoring :-) +// XXX Note to self, IsSlice == inline node. Str == sha3 to node +func (it *TrieIterator) workNode(currentNode *Value) { + if currentNode.Len() == 2 { + k := CompactDecode(currentNode.Get(0).Str()) + + if currentNode.Get(1).IsSlice() { + it.workNode(currentNode.Get(1)) + } else { + if k[len(k)-1] == 16 { + it.values = append(it.values, currentNode.Get(1).Str()) + } else { + it.shas = append(it.shas, currentNode.Get(1).Bytes()) + it.getNode(currentNode.Get(1).Bytes()) + } + } + } else { + for i := 0; i < currentNode.Len(); i++ { + if i == 16 && currentNode.Get(i).Len() != 0 { + it.values = append(it.values, currentNode.Get(i).Str()) + } else { + if currentNode.Get(i).IsSlice() { + it.workNode(currentNode.Get(i)) + } else { + val := currentNode.Get(i).Str() + if val != "" { + it.shas = append(it.shas, currentNode.Get(1).Bytes()) + it.getNode([]byte(val)) + } + } + } + } + } +} + +func (it *TrieIterator) getNode(node []byte) { + currentNode := it.trie.cache.Get(node) + it.workNode(currentNode) +} + +func (it *TrieIterator) Collect() [][]byte { + if it.trie.Root == "" { + return nil + } + + it.getNode(NewValue(it.trie.Root).Bytes()) + + return it.shas +} + +func (it *TrieIterator) Purge() int { + shas := it.Collect() + for _, sha := range shas { + it.trie.cache.Delete(sha) + } + return len(it.values) +} + +func (it *TrieIterator) Key() string { + return "" +} + +func (it *TrieIterator) Value() string { + return "" +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 9d2c8e19f0..c3a8f224da 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "reflect" "testing" ) @@ -21,6 +22,10 @@ func (db *MemDatabase) Put(key []byte, value []byte) { func (db *MemDatabase) Get(key []byte) ([]byte, error) { return db.db[string(key)], nil } +func (db *MemDatabase) Delete(key []byte) error { + delete(db.db, string(key)) + return nil +} func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } @@ -148,3 +153,22 @@ func TestTrieDeleteWithValue(t *testing.T) { } } + +func TestTrieIterator(t *testing.T) { + _, trie := New() + trie.Update("c", LONG_WORD) + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + + it := trie.NewIterator() + fmt.Println("purging") + fmt.Println("len =", it.Purge()) + /* + for it.Next() { + k := it.Key() + v := it.Value() + + fmt.Println(k, v) + } + */ +} From 5971c82094b79e7c05bfb652c46fac02381b2816 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:11:42 +0100 Subject: [PATCH 0108/1237] Updated opcodes ... again --- ethutil/parsing.go | 102 ++++++++++++++++++++-------------------- ethutil/parsing_test.go | 4 +- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index b43dac0648..553bb97178 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -7,57 +7,57 @@ import ( // Op codes var OpCodes = map[string]byte{ - "STOP": 0, - "ADD": 1, - "MUL": 2, - "SUB": 3, - "DIV": 4, - "SDIV": 5, - "MOD": 6, - "SMOD": 7, - "EXP": 8, - "NEG": 9, - "LT": 10, - "LE": 11, - "GT": 12, - "GE": 13, - "EQ": 14, - "NOT": 15, - "MYADDRESS": 16, - "TXSENDER": 17, - "TXVALUE": 18, - "TXFEE": 19, - "TXDATAN": 20, - "TXDATA": 21, - "BLK_PREVHASH": 22, - "BLK_COINBASE": 23, - "BLK_TIMESTAMP": 24, - "BLK_NUMBER": 25, - "BLK_DIFFICULTY": 26, - "BASEFEE": 27, - "SHA256": 32, - "RIPEMD160": 33, - "ECMUL": 34, - "ECADD": 35, - "ECSIGN": 36, - "ECRECOVER": 37, - "ECVALID": 38, - "SHA3": 39, - "PUSH": 48, - "POP": 49, - "DUP": 50, - "SWAP": 51, - "MLOAD": 52, - "MSTORE": 53, - "SLOAD": 54, - "SSTORE": 55, - "JMP": 56, - "JMPI": 57, - "IND": 58, - "EXTRO": 59, - "BALANCE": 60, - "MKTX": 61, - "SUICIDE": 62, + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "LE": 0x0b, + "GT": 0x0c, + "GE": 0x0d, + "EQ": 0x0e, + "NOT": 0x0f, + "MYADDRESS": 0x10, + "TXSENDER": 0x11, + "TXVALUE": 0x12, + "TXDATAN": 0x13, + "TXDATA": 0x14, + "BLK_PREVHASH": 0x15, + "BLK_COINBASE": 0x16, + "BLK_TIMESTAMP": 0x17, + "BLK_NUMBER": 0x18, + "BLK_DIFFICULTY": 0x19, + "BLK_NONCE": 0x1a, + "BASEFEE": 0x1b, + "SHA256": 0x20, + "RIPEMD160": 0x21, + "ECMUL": 0x22, + "ECADD": 0x23, + "ECSIGN": 0x24, + "ECRECOVER": 0x25, + "ECVALID": 0x26, + "SHA3": 0x27, + "PUSH": 0x30, + "POP": 0x31, + "DUP": 0x32, + "SWAP": 0x33, + "MLOAD": 0x34, + "MSTORE": 0x35, + "SLOAD": 0x36, + "SSTORE": 0x37, + "JMP": 0x38, + "JMPI": 0x39, + "IND": 0x3a, + "EXTRO": 0x3b, + "BALANCE": 0x3c, + "MKTX": 0x3d, + "SUICIDE": 0x3f, } func IsOpCode(s string) bool { diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 482eef3ee8..c406491874 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -1,5 +1,6 @@ package ethutil +/* import ( "math" "testing" @@ -19,14 +20,13 @@ func TestCompile(t *testing.T) { } func TestValidInstr(t *testing.T) { - /* op, args, err := Instr("68163") if err != nil { t.Error("Error decoding instruction") } - */ } func TestInvalidInstr(t *testing.T) { } +*/ From 55c1c220d07c37610c9aa61c583eccb3c8e3829e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:01 +0100 Subject: [PATCH 0109/1237] Added delete to database interfaces --- ethdb/database.go | 4 ++++ ethdb/memory_database.go | 6 ++++++ ethutil/db.go | 1 + 3 files changed, 11 insertions(+) diff --git a/ethdb/database.go b/ethdb/database.go index 76e4b4e4df..1e987920de 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -36,6 +36,10 @@ func (db *LDBDatabase) Get(key []byte) ([]byte, error) { return db.db.Get(key, nil) } +func (db *LDBDatabase) Delete(key []byte) error { + return db.db.Delete(key, nil) +} + func (db *LDBDatabase) LastKnownTD() []byte { data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil) diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index cd9f240005..9e91eb7d69 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -26,6 +26,12 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) { return db.db[string(key)], nil } +func (db *MemDatabase) Delete(key []byte) error { + delete(db.db, string(key)) + + return nil +} + func (db *MemDatabase) Print() { for key, val := range db.db { fmt.Printf("%x(%d): ", key, len(key)) diff --git a/ethutil/db.go b/ethutil/db.go index 3681c4b058..b11d5d7263 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,6 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) + Delete(key []byte) error LastKnownTD() []byte Close() Print() From a3fb7008b2df860b01df71ef7da42b394570d1e2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:24 +0100 Subject: [PATCH 0110/1237] Added make contract --- ethchain/contract.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ethchain/contract.go b/ethchain/contract.go index 68ec39f0b4..dbcbb3697c 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -41,3 +41,31 @@ func (c *Contract) SetAddr(addr []byte, value interface{}) { func (c *Contract) State() *ethutil.Trie { return c.state } + +func (c *Contract) GetMem(num int) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) + + return c.Addr(nb) +} + +func MakeContract(tx *Transaction, state *State) *Contract { + // Create contract if there's no recipient + if tx.IsContract() { + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(value, []byte("")) + state.trie.Update(string(addr), string(contract.RlpEncode())) + for i, val := range tx.Data { + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.Update(string(bytNum), string(ethutil.Encode(val))) + } + } + state.trie.Update(string(addr), string(contract.RlpEncode())) + + return contract + } + + return nil +} From 4cc5b03137e513dd54e9feb07a564398ca53b342 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:32 +0100 Subject: [PATCH 0111/1237] Added opcodes --- ethchain/stack.go | 103 +++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index e08f840824..13b0f247b6 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -9,57 +9,57 @@ type OpCode int // Op codes const ( - oSTOP OpCode = iota - oADD - oMUL - oSUB - oDIV - oSDIV - oMOD - oSMOD - oEXP - oNEG - oLT - oLE - oGT - oGE - oEQ - oNOT - oMYADDRESS - oTXSENDER - oTXVALUE - oTXFEE - oTXDATAN - oTXDATA - oBLK_PREVHASH - oBLK_COINBASE - oBLK_TIMESTAMP - oBLK_NUMBER - oBLK_DIFFICULTY - oBASEFEE - oSHA256 OpCode = 32 - oRIPEMD160 OpCode = 33 - oECMUL OpCode = 34 - oECADD OpCode = 35 - oECSIGN OpCode = 36 - oECRECOVER OpCode = 37 - oECVALID OpCode = 38 - oSHA3 OpCode = 39 - oPUSH OpCode = 48 - oPOP OpCode = 49 - oDUP OpCode = 50 - oSWAP OpCode = 51 - oMLOAD OpCode = 52 - oMSTORE OpCode = 53 - oSLOAD OpCode = 54 - oSSTORE OpCode = 55 - oJMP OpCode = 56 - oJMPI OpCode = 57 - oIND OpCode = 58 - oEXTRO OpCode = 59 - oBALANCE OpCode = 60 - oMKTX OpCode = 61 - oSUICIDE OpCode = 62 + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oLE = 0x0b + oGT = 0x0c + oGE = 0x0d + oEQ = 0x0e + oNOT = 0x0f + oMYADDRESS = 0x10 + oTXSENDER = 0x11 + oTXVALUE = 0x12 + oTXDATAN = 0x13 + oTXDATA = 0x14 + oBLK_PREVHASH = 0x15 + oBLK_COINBASE = 0x16 + oBLK_TIMESTAMP = 0x17 + oBLK_NUMBER = 0x18 + oBLK_DIFFICULTY = 0x19 + oBLK_NONCE = 0x1a + oBASEFEE = 0x1b + oSHA256 = 0x20 + oRIPEMD160 = 0x21 + oECMUL = 0x22 + oECADD = 0x23 + oECSIGN = 0x24 + oECRECOVER = 0x25 + oECVALID = 0x26 + oSHA3 = 0x27 + oPUSH = 0x30 + oPOP = 0x31 + oDUP = 0x32 + oSWAP = 0x33 + oMLOAD = 0x34 + oMSTORE = 0x35 + oSLOAD = 0x36 + oSSTORE = 0x37 + oJMP = 0x38 + oJMPI = 0x39 + oIND = 0x3a + oEXTRO = 0x3b + oBALANCE = 0x3c + oMKTX = 0x3d + oSUICIDE = 0x3f ) // Since the opcodes aren't all in order we can't use a regular slice @@ -83,7 +83,6 @@ var opCodeToString = map[OpCode]string{ oMYADDRESS: "MYADDRESS", oTXSENDER: "TXSENDER", oTXVALUE: "TXVALUE", - oTXFEE: "TXFEE", oTXDATAN: "TXDATAN", oTXDATA: "TXDATA", oBLK_PREVHASH: "BLK_PREVHASH", From 22e2c3429bee515f69250dfdddc419a389e8ccd6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:12:53 +0100 Subject: [PATCH 0112/1237] Infof rather than infoln --- peer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 9538e65003..a8708206f3 100644 --- a/peer.go +++ b/peer.go @@ -390,7 +390,7 @@ func (p *Peer) HandleInbound() { p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) } case ethwire.MsgNotInChainTy: - ethutil.Config.Log.Infoln("Not in chain %x\n", msg.Data) + ethutil.Config.Log.Infof("Not in chain %x\n", msg.Data) // TODO // Unofficial but fun nonetheless @@ -556,7 +556,7 @@ func (p *Peer) CatchupWithPeer() { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Debugln("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) + ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) } } From d8b5bbd48c8e989808058150137d9713d1936b18 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:13:22 +0100 Subject: [PATCH 0113/1237] Added compile --- ethchain/block_manager_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index 853d459d80..df3e56e5eb 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -17,12 +17,13 @@ func TestVm(t *testing.T) { bm := NewBlockManager(nil) block := bm.bc.genesisBlock - ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), []string{ + script := Compile([]string{ "PUSH", "1", "PUSH", "2", "STOP", }) + ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), script) bm.ApplyTransactions(block, []*Transaction{ctrct}) } From d69db6e617478911e90f6627329012578bfd0fe5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:13:42 +0100 Subject: [PATCH 0114/1237] Removed compiling from the transaction --- ethchain/transaction.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2417bbd7d7..39b2bda94d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -24,12 +24,7 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { tx.Nonce = 0 // Serialize the data - tx.Data = make([]string, len(data)) - for i, val := range data { - instr, _ := ethutil.CompileInstr(val) - - tx.Data[i] = string(instr) - } + tx.Data = data return &tx } From b29c1eecd104de58611b9a17a68b48321fd40e87 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:44:18 +0100 Subject: [PATCH 0115/1237] Removed debug print --- ethchain/vm.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index d5f4d7ad6c..9abd9cd411 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -91,7 +91,6 @@ out: tf := new(big.Int).Add(fee, fee2) if contract.Amount.Cmp(tf) < 0 { - fmt.Println("Contract fee", ContractFee) fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) break } @@ -392,7 +391,7 @@ out: fmt.Printf("Invalid OPCODE: %x\n", op) } fmt.Println("") - vm.stack.Print() + //vm.stack.Print() pc++ } From 88a9c62fccd16a782e7d7221daf6b6f207c22097 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:44:29 +0100 Subject: [PATCH 0116/1237] Proper tests --- ethchain/block_manager.go | 420 ++------------------------------- ethchain/block_manager_test.go | 10 +- 2 files changed, 24 insertions(+), 406 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index b82e5a74ab..ad96f6a348 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -6,11 +6,8 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/ethereum/eth-go/ethwire" - "github.com/obscuren/secp256k1-go" "log" - "math" "math/big" - "strconv" "sync" "time" ) @@ -113,9 +110,12 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { // If there's no recipient, it's a contract if tx.IsContract() { block.MakeContract(tx) - bm.ProcessContract(tx, block) } else { - bm.TransactionPool.ProcessTransaction(tx, block) + if contract := block.GetContract(tx.Recipient); contract != nil { + bm.ProcessContract(contract, tx, block) + } else { + bm.TransactionPool.ProcessTransaction(tx, block) + } } } } @@ -300,7 +300,7 @@ func (bm *BlockManager) Stop() { bm.bc.Stop() } -func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { +func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors /* defer func() { @@ -310,402 +310,16 @@ func (bm *BlockManager) ProcessContract(tx *Transaction, block *Block) { }() */ - // Process contract - bm.ProcContract(tx, block, func(opType OpType) bool { - // TODO turn on once big ints are in place - //if !block.PayFee(tx.Hash(), StepFee.Uint64()) { - // return false - //} - - return true // Continue + vm := &Vm{} + vm.Process(contract, NewState(block.state), RuntimeVars{ + address: tx.Hash()[12:], + blockNumber: block.BlockInfo().Number, + sender: tx.Sender(), + prevHash: block.PrevHash, + coinbase: block.Coinbase, + time: block.Time, + diff: block.Difficulty, + txValue: tx.Value, + txData: tx.Data, }) } - -// Contract evaluation is done here. -func (bm *BlockManager) ProcContract(tx *Transaction, block *Block, cb TxCallback) { - addr := tx.Hash()[12:] - // Instruction pointer - pc := 0 - blockInfo := bm.bc.BlockInfo(block) - - contract := block.GetContract(addr) - - if contract == nil { - fmt.Println("Contract not found") - return - } - - Pow256 := ethutil.BigPow(2, 256) - - if ethutil.Config.Debug { - fmt.Printf("# op\n") - } - - stepcount := 0 - totalFee := new(big.Int) - - // helper function for getting a contract's memory address - getMem := func(num int) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) - return contract.Addr(nb) - } -out: - for { - stepcount++ - // The base big int for all calculations. Use this for any results. - base := new(big.Int) - val := getMem(pc) - //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) - op := OpCode(val.Uint()) - - var fee *big.Int = new(big.Int) - var fee2 *big.Int = new(big.Int) - if stepcount > 16 { - fee.Add(fee, StepFee) - } - - // Calculate the fees - switch op { - case oSSTORE: - y, x := bm.stack.Peekn() - val := contract.Addr(ethutil.BigToBytes(x, 256)) - if val.IsEmpty() && len(y.Bytes()) > 0 { - fee2.Add(DataFee, StoreFee) - } else { - fee2.Sub(DataFee, StoreFee) - } - case oSLOAD: - fee.Add(fee, StoreFee) - case oEXTRO, oBALANCE: - fee.Add(fee, ExtroFee) - case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: - fee.Add(fee, CryptoFee) - case oMKTX: - fee.Add(fee, ContractFee) - } - - tf := new(big.Int).Add(fee, fee2) - if contract.Amount.Cmp(tf) < 0 { - break - } - // Add the fee to the total fee. It's subtracted when we're done looping - totalFee.Add(totalFee, tf) - - if !cb(0) { - break - } - - if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s", pc, op.String()) - } - - switch op { - case oSTOP: - fmt.Println("") - break out - case oADD: - x, y := bm.stack.Popn() - // (x + y) % 2 ** 256 - base.Add(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - bm.stack.Push(base) - case oSUB: - x, y := bm.stack.Popn() - // (x - y) % 2 ** 256 - base.Sub(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - bm.stack.Push(base) - case oMUL: - x, y := bm.stack.Popn() - // (x * y) % 2 ** 256 - base.Mul(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - bm.stack.Push(base) - case oDIV: - x, y := bm.stack.Popn() - // floor(x / y) - base.Div(x, y) - // Pop result back on the stack - bm.stack.Push(base) - case oSDIV: - x, y := bm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { - x.Sub(Pow256, x) - } - if y.Cmp(Pow256) > 0 { - y.Sub(Pow256, y) - } - z := new(big.Int) - z.Div(x, y) - if z.Cmp(Pow256) > 0 { - z.Sub(Pow256, z) - } - // Push result on to the stack - bm.stack.Push(z) - case oMOD: - x, y := bm.stack.Popn() - base.Mod(x, y) - bm.stack.Push(base) - case oSMOD: - x, y := bm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { - x.Sub(Pow256, x) - } - if y.Cmp(Pow256) > 0 { - y.Sub(Pow256, y) - } - z := new(big.Int) - z.Mod(x, y) - if z.Cmp(Pow256) > 0 { - z.Sub(Pow256, z) - } - // Push result on to the stack - bm.stack.Push(z) - case oEXP: - x, y := bm.stack.Popn() - base.Exp(x, y, Pow256) - - bm.stack.Push(base) - case oNEG: - base.Sub(Pow256, bm.stack.Pop()) - bm.stack.Push(base) - case oLT: - x, y := bm.stack.Popn() - // x < y - if x.Cmp(y) < 0 { - bm.stack.Push(ethutil.BigTrue) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oLE: - x, y := bm.stack.Popn() - // x <= y - if x.Cmp(y) < 1 { - bm.stack.Push(ethutil.BigTrue) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oGT: - x, y := bm.stack.Popn() - // x > y - if x.Cmp(y) > 0 { - bm.stack.Push(ethutil.BigTrue) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oGE: - x, y := bm.stack.Popn() - // x >= y - if x.Cmp(y) > -1 { - bm.stack.Push(ethutil.BigTrue) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oNOT: - x, y := bm.stack.Popn() - // x != y - if x.Cmp(y) != 0 { - bm.stack.Push(ethutil.BigTrue) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oMYADDRESS: - bm.stack.Push(ethutil.BigD(tx.Hash())) - case oTXSENDER: - bm.stack.Push(ethutil.BigD(tx.Sender())) - case oTXVALUE: - bm.stack.Push(tx.Value) - case oTXDATAN: - bm.stack.Push(big.NewInt(int64(len(tx.Data)))) - case oTXDATA: - v := bm.stack.Pop() - // v >= len(data) - if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 { - bm.stack.Push(ethutil.Big("0")) - } else { - bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()])) - } - case oBLK_PREVHASH: - bm.stack.Push(ethutil.BigD(block.PrevHash)) - case oBLK_COINBASE: - bm.stack.Push(ethutil.BigD(block.Coinbase)) - case oBLK_TIMESTAMP: - bm.stack.Push(big.NewInt(block.Time)) - case oBLK_NUMBER: - bm.stack.Push(big.NewInt(int64(blockInfo.Number))) - case oBLK_DIFFICULTY: - bm.stack.Push(block.Difficulty) - case oBASEFEE: - // e = 10^21 - e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) - d := new(big.Rat) - d.SetInt(block.Difficulty) - c := new(big.Rat) - c.SetFloat64(0.5) - // d = diff / 0.5 - d.Quo(d, c) - // base = floor(d) - base.Div(d.Num(), d.Denom()) - - x := new(big.Int) - x.Div(e, base) - - // x = floor(10^21 / floor(diff^0.5)) - bm.stack.Push(x) - case oSHA256, oSHA3, oRIPEMD160: - // This is probably save - // ceil(pop / 32) - length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0)) - // New buffer which will contain the concatenated popped items - data := new(bytes.Buffer) - for i := 0; i < length; i++ { - // Encode the number to bytes and have it 32bytes long - num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256) - data.WriteString(string(num)) - } - - if op == oSHA256 { - bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) - } else if op == oSHA3 { - bm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) - } else { - bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) - } - case oECMUL: - y := bm.stack.Pop() - x := bm.stack.Pop() - //n := bm.stack.Pop() - - //if ethutil.Big(x).Cmp(ethutil.Big(y)) { - data := new(bytes.Buffer) - data.WriteString(x.String()) - data.WriteString(y.String()) - if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { - // TODO - } else { - // Invalid, push infinity - bm.stack.Push(ethutil.Big("0")) - bm.stack.Push(ethutil.Big("0")) - } - //} else { - // // Invalid, push infinity - // bm.stack.Push("0") - // bm.stack.Push("0") - //} - - case oECADD: - case oECSIGN: - case oECRECOVER: - case oECVALID: - case oPUSH: - pc++ - bm.stack.Push(getMem(pc).BigInt()) - case oPOP: - // Pop current value of the stack - bm.stack.Pop() - case oDUP: - // Dup top stack - x := bm.stack.Pop() - bm.stack.Push(x) - bm.stack.Push(x) - case oSWAP: - // Swap two top most values - x, y := bm.stack.Popn() - bm.stack.Push(y) - bm.stack.Push(x) - case oMLOAD: - x := bm.stack.Pop() - bm.stack.Push(bm.mem[x.String()]) - case oMSTORE: - x, y := bm.stack.Popn() - bm.mem[x.String()] = y - case oSLOAD: - // Load the value in storage and push it on the stack - x := bm.stack.Pop() - // decode the object as a big integer - decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) - if !decoder.IsNil() { - bm.stack.Push(decoder.BigInt()) - } else { - bm.stack.Push(ethutil.BigFalse) - } - case oSSTORE: - // Store Y at index X - y, x := bm.stack.Popn() - addr := ethutil.BigToBytes(x, 256) - fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) - contract.SetAddr(addr, y) - //contract.State().Update(string(idx), string(y)) - case oJMP: - x := int(bm.stack.Pop().Uint64()) - // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) - pc = x - pc-- - case oJMPI: - x := bm.stack.Pop() - // Set pc to x if it's non zero - if x.Cmp(ethutil.BigFalse) != 0 { - pc = int(x.Uint64()) - pc-- - } - case oIND: - bm.stack.Push(big.NewInt(int64(pc))) - case oEXTRO: - memAddr := bm.stack.Pop() - contractAddr := bm.stack.Pop().Bytes() - - // Push the contract's memory on to the stack - bm.stack.Push(getContractMemory(block, contractAddr, memAddr)) - case oBALANCE: - // Pushes the balance of the popped value on to the stack - d := block.State().Get(bm.stack.Pop().String()) - ether := NewAddressFromData([]byte(d)) - bm.stack.Push(ether.Amount) - case oMKTX: - value, addr := bm.stack.Popn() - from, length := bm.stack.Popn() - - j := 0 - dataItems := make([]string, int(length.Uint64())) - for i := from.Uint64(); i < length.Uint64(); i++ { - dataItems[j] = string(bm.mem[strconv.Itoa(int(i))].Bytes()) - j++ - } - // TODO sign it? - tx := NewTransaction(addr.Bytes(), value, dataItems) - // Add the transaction to the tx pool - bm.TransactionPool.QueueTransaction(tx) - case oSUICIDE: - //addr := bm.stack.Pop() - default: - fmt.Println("Invalid OPCODE", op) - } - fmt.Println("") - bm.stack.Print() - pc++ - } - - block.UpdateContract(addr, contract) -} - -// Returns an address from the specified contract's address -func getContractMemory(block *Block, contractAddr []byte, memAddr *big.Int) *big.Int { - contract := block.GetContract(contractAddr) - if contract == nil { - log.Panicf("invalid contract addr %x", contractAddr) - } - val := contract.State().Get(memAddr.String()) - - // decode the object as a big integer - decoder := ethutil.NewValueFromBytes([]byte(val)) - if decoder.IsNil() { - return ethutil.BigFalse - } - - return decoder.BigInt() -} diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index df3e56e5eb..ec4fbe8c5c 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -22,8 +22,12 @@ func TestVm(t *testing.T) { "1", "PUSH", "2", - "STOP", }) - ctrct := NewTransaction(ContractAddr, big.NewInt(200000000), script) - bm.ApplyTransactions(block, []*Transaction{ctrct}) + tx := NewTransaction(ContractAddr, big.NewInt(200000000), script) + addr := tx.Hash()[12:] + bm.ApplyTransactions(block, []*Transaction{tx}) + + tx2 := NewTransaction(addr, big.NewInt(1e17), nil) + tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + bm.ApplyTransactions(block, []*Transaction{tx2}) } From 95a8ebc2495476c5dbe6c35f30629ca11f660b86 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 12:45:21 +0100 Subject: [PATCH 0117/1237] Changed MakeContract on block MakeContract in Block is now using the MakeContract defined in contract.go --- ethchain/block.go | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 0b4f93e8cc..7ad9984be1 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -220,23 +220,9 @@ func (block *Block) Undo() { } func (block *Block) MakeContract(tx *Transaction) { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.Hash()[12:] + contract := MakeContract(tx, NewState(block.state)) - value := tx.Value - contract := NewContract(value, []byte("")) - block.state.Update(string(addr), string(contract.RlpEncode())) - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.Update(string(bytNum), val) - } - } - block.UpdateContract(addr, contract) - - block.contractStates[string(addr)] = contract.state - } + block.contractStates[string(tx.Hash()[12:])] = contract.state } /////// Block Encoding From 6c7255cde2afdff7710af23c9830835398e6b43d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 13:15:34 +0100 Subject: [PATCH 0118/1237] Fixed a minor issue on crashed contracts --- ethchain/block.go | 5 +++-- ethchain/contract.go | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 7ad9984be1..472ae134ac 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -221,8 +221,9 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { contract := MakeContract(tx, NewState(block.state)) - - block.contractStates[string(tx.Hash()[12:])] = contract.state + if contract != nil { + block.contractStates[string(tx.Hash()[12:])] = contract.state + } } /////// Block Encoding diff --git a/ethchain/contract.go b/ethchain/contract.go index dbcbb3697c..14abb05d16 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -65,6 +66,8 @@ func MakeContract(tx *Transaction, state *State) *Contract { state.trie.Update(string(addr), string(contract.RlpEncode())) return contract + } else { + fmt.Println("NO CONTRACT") } return nil From 0afdedb01a8e4203129175dc9dcc213a55906a66 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Feb 2014 13:50:52 +0100 Subject: [PATCH 0119/1237] Some log statements changed to the default logger --- ethchain/block_manager.go | 25 ++++--------------------- ethchain/vm.go | 10 +++++----- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index ad96f6a348..04036dbb11 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -165,37 +165,20 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { if bm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo bm.bc.CurrentBlock.Sync() - // Add the block to the chain - bm.bc.Add(block) - - /* - ethutil.Config.Db.Put(block.Hash(), block.RlpEncode()) - bm.bc.CurrentBlock = block - bm.LastBlockHash = block.Hash() - bm.writeBlockInfo(block) - */ - - /* - txs := bm.TransactionPool.Flush() - var coded = []interface{}{} - for _, tx := range txs { - err := bm.TransactionPool.ValidateTransaction(tx) - if err == nil { - coded = append(coded, tx.RlpEncode()) - } - } - */ // Broadcast the valid block back to the wire //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + // Add the block to the chain + bm.bc.Add(block) + // If there's a block processor present, pass in the block for further // processing if bm.SecondaryBlockProcessor != nil { bm.SecondaryBlockProcessor.ProcessBlock(block) } - log.Printf("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) } else { fmt.Println("total diff failed") } diff --git a/ethchain/vm.go b/ethchain/vm.go index 9abd9cd411..c7a91a9c52 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,7 @@ func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { Pow256 := ethutil.BigPow(2, 256) if ethutil.Config.Debug { - fmt.Printf("# op\n") + ethutil.Config.Log.Debugf("# op\n") } stepcount := 0 @@ -98,7 +98,7 @@ out: totalFee.Add(totalFee, tf) if ethutil.Config.Debug { - fmt.Printf("%-3d %-4s", pc, op.String()) + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) } switch op { @@ -385,12 +385,12 @@ out: // Delete the contract state.trie.Update(string(addr), "") - fmt.Printf("(%d) => %x\n", deletedMemory, recAddr) + ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) break out default: fmt.Printf("Invalid OPCODE: %x\n", op) } - fmt.Println("") + ethutil.Config.Log.Debugln("") //vm.stack.Print() pc++ } @@ -399,7 +399,7 @@ out: } func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { - fmt.Printf(" => creating inline tx %x %v %v %v", addr, value, from, length) + ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := 0 dataItems := make([]string, int(length.Uint64())) for i := from.Uint64(); i < length.Uint64(); i++ { From b30b9ab8cb13ddbc68a4912c9f06116c0f59bc27 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 10:50:53 +0100 Subject: [PATCH 0120/1237] Fixed a minor issue where a string is expected but returns slice --- ethutil/trie.go | 4 ++-- ethutil/trie_test.go | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 83527d364f..a17dc37ad9 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -439,7 +439,7 @@ func (it *TrieIterator) workNode(currentNode *Value) { if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) - if currentNode.Get(1).IsSlice() { + if currentNode.Get(1).Str() == "" { it.workNode(currentNode.Get(1)) } else { if k[len(k)-1] == 16 { @@ -454,7 +454,7 @@ func (it *TrieIterator) workNode(currentNode *Value) { if i == 16 && currentNode.Get(i).Len() != 0 { it.values = append(it.values, currentNode.Get(i).Str()) } else { - if currentNode.Get(i).IsSlice() { + if currentNode.Get(i).Str() == "" { it.workNode(currentNode.Get(i)) } else { val := currentNode.Get(i).Str() diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index c3a8f224da..645c5a2258 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,6 @@ package ethutil import ( - "fmt" "reflect" "testing" ) @@ -160,15 +159,13 @@ func TestTrieIterator(t *testing.T) { trie.Update("ca", LONG_WORD) trie.Update("cat", LONG_WORD) + lenBefore := len(trie.cache.nodes) it := trie.NewIterator() - fmt.Println("purging") - fmt.Println("len =", it.Purge()) - /* - for it.Next() { - k := it.Key() - v := it.Value() + if num := it.Purge(); num != 3 { + t.Errorf("Expected purge to return 3, got %d", num) + } - fmt.Println(k, v) - } - */ + if lenBefore == len(trie.cache.nodes) { + t.Errorf("Expected cached nodes to be deleted") + } } From c7e73ba12d747186002433db54d002ab43bed171 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:20:24 +0100 Subject: [PATCH 0121/1237] Added currency converting --- ethutil/common.go | 35 +++++++++++++++++++++++++++++++++++ ethutil/common_test.go | 17 +++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 ethutil/common.go create mode 100644 ethutil/common_test.go diff --git a/ethutil/common.go b/ethutil/common.go new file mode 100644 index 0000000000..07df6bb138 --- /dev/null +++ b/ethutil/common.go @@ -0,0 +1,35 @@ +package ethutil + +import ( + "fmt" + "math/big" +) + +var ( + Ether = BigPow(10, 18) + Finney = BigPow(10, 15) + Szabo = BigPow(10, 12) + Vito = BigPow(10, 9) + Turing = BigPow(10, 6) + Eins = BigPow(10, 3) + Wei = big.NewInt(1) +) + +func CurrencyToString(num *big.Int) string { + switch { + case num.Cmp(Ether) >= 0: + return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) + case num.Cmp(Finney) >= 0: + return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) + case num.Cmp(Szabo) >= 0: + return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) + case num.Cmp(Vito) >= 0: + return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito)) + case num.Cmp(Turing) >= 0: + return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) + case num.Cmp(Eins) >= 0: + return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins)) + } + + return fmt.Sprintf("%v Wei", num) +} diff --git a/ethutil/common_test.go b/ethutil/common_test.go new file mode 100644 index 0000000000..3a6a37ff57 --- /dev/null +++ b/ethutil/common_test.go @@ -0,0 +1,17 @@ +package ethutil + +import ( + "fmt" + "math/big" + "testing" +) + +func TestCommon(t *testing.T) { + fmt.Println(CurrencyToString(BigPow(10, 19))) + fmt.Println(CurrencyToString(BigPow(10, 16))) + fmt.Println(CurrencyToString(BigPow(10, 13))) + fmt.Println(CurrencyToString(BigPow(10, 10))) + fmt.Println(CurrencyToString(BigPow(10, 7))) + fmt.Println(CurrencyToString(BigPow(10, 4))) + fmt.Println(CurrencyToString(big.NewInt(10))) +} From 4f4175a3e295272025d312c800f65fc1a143a9ca Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:21:03 +0100 Subject: [PATCH 0122/1237] Addad db name for new ldb --- ethdb/database.go | 8 ++++++-- ethereum.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ethdb/database.go b/ethdb/database.go index 1e987920de..d1967f0232 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -11,8 +11,8 @@ type LDBDatabase struct { db *leveldb.DB } -func NewLDBDatabase() (*LDBDatabase, error) { - dbPath := path.Join(ethutil.Config.ExecPath, "database") +func NewLDBDatabase(name string) (*LDBDatabase, error) { + dbPath := path.Join(ethutil.Config.ExecPath, name) // Open the db db, err := leveldb.OpenFile(dbPath, nil) @@ -40,6 +40,10 @@ func (db *LDBDatabase) Delete(key []byte) error { return db.db.Delete(key, nil) } +func (db *LDBDatabase) Db() *leveldb.DB { + return db.db +} + func (db *LDBDatabase) LastKnownTD() []byte { data, _ := db.db.Get([]byte("LastKnownTotalDifficulty"), nil) diff --git a/ethereum.go b/ethereum.go index 725fe5a3d1..90682b396d 100644 --- a/ethereum.go +++ b/ethereum.go @@ -61,7 +61,7 @@ type Ethereum struct { } func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase() + db, err := ethdb.NewLDBDatabase("database") //db, err := ethdb.NewMemDatabase() if err != nil { return nil, err From 507fc7b9d1e227de91b25e18891c4cd44452b222 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:21:35 +0100 Subject: [PATCH 0123/1237] Length checking when fetching contract. Contract always have 3 fields --- ethchain/block.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethchain/block.go b/ethchain/block.go index 472ae134ac..7ca44a47df 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -131,6 +131,11 @@ func (block *Block) GetContract(addr []byte) *Contract { return nil } + value := ethutil.NewValueFromBytes([]byte(data)) + if value.Len() == 2 { + return nil + } + contract := &Contract{} contract.RlpDecode([]byte(data)) From ce07d9bb4c95a118636c4b71e9cba2d81540c4a5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:21:49 +0100 Subject: [PATCH 0124/1237] Error logging on tx processing --- ethchain/block_manager.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 04036dbb11..364a061583 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -92,12 +92,13 @@ func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { } func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { - addrState := bm.addrStateStore.Get(addr) - if addrState == nil { - addrState = bm.WatchAddr(addr) + account := bm.addrStateStore.Get(addr) + if account == nil { + a := bm.bc.CurrentBlock.GetAddr(addr) + account = &AddressState{Nonce: a.Nonce, Account: a} } - return addrState + return account } func (bm *BlockManager) BlockChain() *BlockChain { @@ -114,7 +115,10 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { if contract := block.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { - bm.TransactionPool.ProcessTransaction(tx, block) + err := bm.TransactionPool.ProcessTransaction(tx, block) + if err != nil { + ethutil.Config.Log.Infoln("[BMGR]", err) + } } } } From 1e7b3cbb1343d5362b8ed55d06b1927171f56a41 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:05 +0100 Subject: [PATCH 0125/1237] Removed debug log --- ethchain/contract.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethchain/contract.go b/ethchain/contract.go index 14abb05d16..dbcbb3697c 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -66,8 +65,6 @@ func MakeContract(tx *Transaction, state *State) *Contract { state.trie.Update(string(addr), string(contract.RlpEncode())) return contract - } else { - fmt.Println("NO CONTRACT") } return nil From 4b8c50e2cde130bf278b14040a267aab573dd53e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:18 +0100 Subject: [PATCH 0126/1237] Deprication --- ethchain/transaction.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 39b2bda94d..57df9cdc4d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,7 +29,12 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } +// XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { + return NewTransactionFromBytes(data) +} + +func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} tx.RlpDecode(data) From e98b53bbef8cdbeed54546c75d856d53810e424c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 25 Feb 2014 11:22:27 +0100 Subject: [PATCH 0127/1237] WIP Observing pattern --- ethchain/transaction_pool.go | 41 +++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 1278cc4dc7..cd09bf02ed 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -17,6 +17,17 @@ const ( ) type TxPoolHook chan *Transaction +type TxMsgTy byte + +const ( + TxPre = iota + TxPost +) + +type TxMsg struct { + Tx *Transaction + Type TxMsgTy +} func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { for e := pool.Front(); e != nil; e = e.Next() { @@ -59,6 +70,8 @@ type TxPool struct { BlockManager *BlockManager SecondaryProcessor TxProcessor + + subscribers []chan TxMsg } func NewTxPool() *TxPool { @@ -73,21 +86,17 @@ func NewTxPool() *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { - log.Println("Adding tx to pool") pool.mutex.Lock() pool.pool.PushBack(tx) pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) - log.Println("broadcasting it") } // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { - log.Printf("[TXPL] Processing Tx %x\n", tx.Hash()) - defer func() { if r := recover(); r != nil { log.Println(r) @@ -132,6 +141,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error block.UpdateAddr(tx.Sender(), sender) + log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) + + // Notify the subscribers + pool.notifySubscribers(TxPost, tx) + return } @@ -145,7 +159,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - sender := block.GetAddr(tx.Sender()) + accountState := pool.BlockManager.GetAddrState(tx.Sender()) + sender := accountState.Account totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient @@ -185,9 +200,8 @@ out: // doesn't matter since this is a goroutine pool.addTransaction(tx) - if pool.SecondaryProcessor != nil { - pool.SecondaryProcessor.ProcessTransaction(tx) - } + // Notify the subscribers + pool.notifySubscribers(TxPre, tx) } case <-pool.quit: break out @@ -231,3 +245,14 @@ func (pool *TxPool) Stop() { pool.Flush() } + +func (pool *TxPool) Subscribe(channel chan TxMsg) { + pool.subscribers = append(pool.subscribers, channel) +} + +func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) { + msg := TxMsg{Type: ty, Tx: tx} + for _, subscriber := range pool.subscribers { + subscriber <- msg + } +} From 4fad5958d008328450073e3a98a37b0ca3cac51f Mon Sep 17 00:00:00 2001 From: James Cunningham Date: Wed, 26 Feb 2014 15:26:39 +0000 Subject: [PATCH 0128/1237] Fix error in call to NewIterator function Change number of args passed to NewIterator in print function to reflect changes in the goleveldb project. --- ethdb/database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethdb/database.go b/ethdb/database.go index d1967f0232..d149cbc08c 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -60,7 +60,7 @@ func (db *LDBDatabase) Close() { } func (db *LDBDatabase) Print() { - iter := db.db.NewIterator(nil) + iter := db.db.NewIterator(nil,nil) for iter.Next() { key := iter.Key() value := iter.Value() From c9f3d1c00ba70016be4bb871f9ecd50d456c6985 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 10:36:06 +0100 Subject: [PATCH 0129/1237] leveldb API changed for NewIterator. Fixes #20 --- ethdb/database.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ethdb/database.go b/ethdb/database.go index d1967f0232..3dbff36dea 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -54,13 +54,19 @@ func (db *LDBDatabase) LastKnownTD() []byte { return data } +func (db *LDBDatabase) GetKeys() []*ethutil.Key { + data, _ := db.Get([]byte("KeyRing")) + + return []*ethutil.Key{ethutil.NewKeyFromBytes(data)} +} + func (db *LDBDatabase) Close() { // Close the leveldb database db.db.Close() } func (db *LDBDatabase) Print() { - iter := db.db.NewIterator(nil) + iter := db.db.NewIterator(nil, nil) for iter.Next() { key := iter.Key() value := iter.Value() From c0fcefa3a023c643040b3d9e300980bd32c33dff Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:18:41 +0100 Subject: [PATCH 0130/1237] Added a GetKeys method to support multiple accounts --- ethdb/memory_database.go | 6 ++++++ ethutil/db.go | 1 + ethutil/key.go | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 ethutil/key.go diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index 9e91eb7d69..b0fa64ed78 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -26,6 +26,12 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) { return db.db[string(key)], nil } +func (db *MemDatabase) GetKeys() []*ethutil.Key { + data, _ := db.Get([]byte("KeyRing")) + + return []*ethutil.Key{ethutil.NewKeyFromBytes(data)} +} + func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) diff --git a/ethutil/db.go b/ethutil/db.go index b11d5d7263..abbf4a2b09 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,6 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) + GetKeys() []*Key Delete(key []byte) error LastKnownTD() []byte Close() diff --git a/ethutil/key.go b/ethutil/key.go new file mode 100644 index 0000000000..ec195f2136 --- /dev/null +++ b/ethutil/key.go @@ -0,0 +1,19 @@ +package ethutil + +type Key struct { + PrivateKey []byte + PublicKey []byte +} + +func NewKeyFromBytes(data []byte) *Key { + val := NewValueFromBytes(data) + return &Key{val.Get(0).Bytes(), val.Get(1).Bytes()} +} + +func (k *Key) Address() []byte { + return Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *Key) RlpEncode() []byte { + return EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} From 9d06f9e6fbc20006df6812ed3feb5d8058c0b0a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:01 +0100 Subject: [PATCH 0131/1237] Updated readme#trie --- ethutil/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethutil/README.md b/ethutil/README.md index c98612e1e3..1ed56b71ba 100644 --- a/ethutil/README.md +++ b/ethutil/README.md @@ -53,6 +53,8 @@ trie.Put("doge", "coin") // Look up the key "do" in the trie out := trie.Get("do") fmt.Println(out) // => verb + +trie.Delete("puppy") ``` The patricia trie, in combination with RLP, provides a robust, @@ -82,7 +84,7 @@ type (e.g. `Slice()` returns []interface{}, `Uint()` return 0, etc). `NewEmptyValue()` returns a new \*Value with it's initial value set to a `[]interface{}` -`AppendLint()` appends a list to the current value. +`AppendList()` appends a list to the current value. `Append(v)` appends the value (v) to the current value/list. From 8fa19664e657aca80446e6c3f7868f19ac717a07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:21 +0100 Subject: [PATCH 0132/1237] Added BigCopy --- ethutil/big.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethutil/big.go b/ethutil/big.go index c41d63add6..1a3902fa3e 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -41,3 +41,12 @@ func BigToBytes(num *big.Int, base int) []byte { return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) } + +// Functions like the build in "copy" function +// but works on big integers +func BigCopy(src *big.Int) (ret *big.Int) { + ret = new(big.Int) + ret.Add(ret, src) + + return +} From 3f7ec1a83fe13dc934d92a405ff01b0be6c04ac0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 12:19:45 +0100 Subject: [PATCH 0133/1237] Conform to Db interface --- ethutil/trie_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 645c5a2258..7c398f1de9 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -25,6 +25,7 @@ func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) return nil } +func (db *MemDatabase) GetKeys() []*Key { return nil } func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } From 601340bd464e3ebae0e4fa3407be5fff3bb3fcbf Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 16:45:29 +0100 Subject: [PATCH 0134/1237] Fixed shutting down --- ethereum.go | 2 +- peer.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ethereum.go b/ethereum.go index 90682b396d..b4a8cdb4ad 100644 --- a/ethereum.go +++ b/ethereum.go @@ -295,7 +295,7 @@ func (s *Ethereum) Stop() { s.TxPool.Stop() s.BlockManager.Stop() - s.shutdownChan <- true + close(s.shutdownChan) } // This function will wait for a shutdown and resumes main thread execution diff --git a/peer.go b/peer.go index a8708206f3..9706197146 100644 --- a/peer.go +++ b/peer.go @@ -511,9 +511,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.port = uint16(c.Get(4).Uint()) // Self connect detection - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() - if bytes.Compare(pubkey, p.pubkey) == 0 { + key := ethutil.Config.Db.GetKeys()[0] + if bytes.Compare(key.PublicKey, p.pubkey) == 0 { p.Stop() return From b462ca4aade75049a0fcba23c54e340f0f793dfb Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Feb 2014 16:45:46 +0100 Subject: [PATCH 0135/1237] Bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 5bf56134d1..5fdc8e1c56 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -46,7 +46,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.3.0"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) } From f1b354e6aa6c4b0330e35ae9011784ff1a0b01ab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Mar 2014 02:22:20 +0100 Subject: [PATCH 0136/1237] Reactor implemented --- ethutil/reactor.go | 77 +++++++++++++++++++++++++++++++++++++++++ ethutil/reactor_test.go | 30 ++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 ethutil/reactor.go create mode 100644 ethutil/reactor_test.go diff --git a/ethutil/reactor.go b/ethutil/reactor.go new file mode 100644 index 0000000000..b3f8b9b5b7 --- /dev/null +++ b/ethutil/reactor.go @@ -0,0 +1,77 @@ +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) { + 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.chans = append(e.chans, ch) +} + +// Remove a subscriber +func (e *ReactorEvent) Remove(ch chan React) { + 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{} +} + +// 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}) + } +} diff --git a/ethutil/reactor_test.go b/ethutil/reactor_test.go new file mode 100644 index 0000000000..48c2f0df35 --- /dev/null +++ b/ethutil/reactor_test.go @@ -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") + } +} From d65b4cd0dd49975410374801fae3ece7d7e087b3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Mar 2014 20:42:05 +0100 Subject: [PATCH 0137/1237] Updated block to use state instead of trie directly --- ethchain/block.go | 61 ++++++++++++++++++++---------------- ethchain/block_chain.go | 2 +- ethchain/block_manager.go | 26 +++++++-------- ethchain/state.go | 8 +++++ ethchain/transaction_pool.go | 8 ++--- 5 files changed, 60 insertions(+), 45 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 7ca44a47df..8de57ccedb 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -34,7 +34,8 @@ type Block struct { // The coin base address Coinbase []byte // Block Trie state - state *ethutil.Trie + //state *ethutil.Trie + state *State // Difficulty for the current block Difficulty *big.Int // Creation time @@ -94,7 +95,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = ethutil.NewTrie(ethutil.Config.Db, root) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) for _, tx := range txes { block.MakeContract(tx) @@ -109,15 +110,15 @@ func (block *Block) Hash() []byte { } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) } func (block *Block) PrintHash() { fmt.Println(block) - fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) + fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) } -func (block *Block) State() *ethutil.Trie { +func (block *Block) State() *State { return block.state } @@ -125,6 +126,7 @@ func (block *Block) Transactions() []*Transaction { return block.transactions } +/* func (block *Block) GetContract(addr []byte) *Contract { data := block.state.Get(string(addr)) if data == "" { @@ -152,13 +154,13 @@ func (block *Block) UpdateContract(addr []byte, contract *Contract) { // Make sure the state is synced //contract.State().Sync() - block.state.Update(string(addr), string(contract.RlpEncode())) + block.state.trie.Update(string(addr), string(contract.RlpEncode())) } func (block *Block) GetAddr(addr []byte) *Address { var address *Address - data := block.State().Get(string(addr)) + data := block.state.trie.Get(string(addr)) if data == "" { address = NewAddress(big.NewInt(0)) } else { @@ -168,11 +170,12 @@ func (block *Block) GetAddr(addr []byte) *Address { return address } func (block *Block) UpdateAddr(addr []byte, address *Address) { - block.state.Update(string(addr), string(address.RlpEncode())) + block.state.trie.Update(string(addr), string(address.RlpEncode())) } +*/ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.GetContract(addr) + contract := block.state.GetContract(addr) // If we can't pay the fee return if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { fmt.Println("Contract has insufficient funds", contract.Amount, fee) @@ -182,9 +185,9 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { base := new(big.Int) contract.Amount = base.Sub(contract.Amount, fee) - block.state.Update(string(addr), string(contract.RlpEncode())) + block.state.trie.Update(string(addr), string(contract.RlpEncode())) - data := block.state.Get(string(block.Coinbase)) + data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) ether := NewAddressFromData([]byte(data)) @@ -192,7 +195,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) - block.state.Update(string(block.Coinbase), string(ether.RlpEncode())) + block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) return true } @@ -207,25 +210,29 @@ func (block *Block) BlockInfo() BlockInfo { // Sync the block's state and contract respectively func (block *Block) Sync() { - // Sync all contracts currently in cache - for _, val := range block.contractStates { - val.Sync() - } + /* + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Sync() + } + */ // Sync the block state itself - block.state.Sync() + block.state.trie.Sync() } func (block *Block) Undo() { - // Sync all contracts currently in cache - for _, val := range block.contractStates { - val.Undo() - } + /* + // Sync all contracts currently in cache + for _, val := range block.contractStates { + val.Undo() + } + */ // Sync the block state itself - block.state.Undo() + block.state.Reset() } func (block *Block) MakeContract(tx *Transaction) { - contract := MakeContract(tx, NewState(block.state)) + contract := MakeContract(tx, block.state) if contract != nil { block.contractStates[string(tx.Hash()[12:])] = contract.state } @@ -308,7 +315,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Time = int64(header.Get(6).BigInt().Uint64()) @@ -345,7 +352,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Time = int64(header.Get(6).BigInt().Uint64()) @@ -356,7 +363,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { } func (block *Block) String() string { - return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) + return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } //////////// UNEXPORTED ///////////////// @@ -369,7 +376,7 @@ func (block *Block) header() []interface{} { // Coinbase address block.Coinbase, // root state - block.state.Root, + block.state.trie.Root, // Sha of tx block.TxSha, // Current block Difficulty diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 96d22366d6..026fc1cea9 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -39,7 +39,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash := ZeroHash256 if bc.CurrentBlock != nil { - root = bc.CurrentBlock.State().Root + root = bc.CurrentBlock.state.trie.Root hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 364a061583..8ea71ab31e 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -51,9 +51,9 @@ func AddTestNetFunds(block *Block) { } { //log.Println("2^200 Wei to", addr) codedAddr, _ := hex.DecodeString(addr) - addr := block.GetAddr(codedAddr) + addr := block.state.GetAccount(codedAddr) addr.Amount = ethutil.BigPow(2, 200) - block.UpdateAddr(codedAddr, addr) + block.state.UpdateAccount(codedAddr, addr) } } @@ -71,7 +71,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { if bm.bc.CurrentBlock == nil { AddTestNetFunds(bm.bc.genesisBlock) - bm.bc.genesisBlock.State().Sync() + bm.bc.genesisBlock.state.trie.Sync() // Prepare the genesis block bm.bc.Add(bm.bc.genesisBlock) @@ -86,7 +86,7 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { // Watches any given address and puts it in the address state store func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { - account := bm.bc.CurrentBlock.GetAddr(addr) + account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) } @@ -94,7 +94,7 @@ func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { account := bm.addrStateStore.Get(addr) if account == nil { - a := bm.bc.CurrentBlock.GetAddr(addr) + a := bm.bc.CurrentBlock.state.GetAccount(addr) account = &AddressState{Nonce: a.Nonce, Account: a} } @@ -112,7 +112,7 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { if tx.IsContract() { block.MakeContract(tx) } else { - if contract := block.GetContract(tx.Recipient); contract != nil { + if contract := block.state.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { err := bm.TransactionPool.ProcessTransaction(tx, block) @@ -161,8 +161,8 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return err } - if !block.State().Cmp(bm.bc.CurrentBlock.State()) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().Root, bm.bc.CurrentBlock.State().Root) + if !block.state.Cmp(bm.bc.CurrentBlock.state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) } // Calculate the new total difficulty and sync back to the db @@ -267,17 +267,17 @@ func CalculateUncleReward(block *Block) *big.Int { func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data - addr := processor.GetAddr(block.Coinbase) + addr := processor.state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - processor.UpdateAddr(block.Coinbase, addr) + processor.state.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { - uncleAddr := processor.GetAddr(uncle.Coinbase) + uncleAddr := processor.state.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) - processor.UpdateAddr(uncle.Coinbase, uncleAddr) + processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -298,7 +298,7 @@ func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} - vm.Process(contract, NewState(block.state), RuntimeVars{ + vm.Process(contract, block.state, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, sender: tx.Sender(), diff --git a/ethchain/state.go b/ethchain/state.go index 1a18ea1d79..cff192b545 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -13,6 +13,10 @@ func NewState(trie *ethutil.Trie) *State { return &State{trie: trie} } +func (s *State) Reset() { + s.trie.Undo() +} + func (s *State) GetContract(addr []byte) *Contract { data := s.trie.Get(string(addr)) if data == "" { @@ -54,3 +58,7 @@ func (s *State) GetAccount(addr []byte) (account *Address) { func (s *State) UpdateAccount(addr []byte, account *Address) { s.trie.Update(string(addr), string(account.RlpEncode())) } + +func (s *State) Cmp(other *State) bool { + return s.trie.Cmp(other.trie) +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index cd09bf02ed..7635605709 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -104,7 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } }() // Get the sender - sender := block.GetAddr(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -122,7 +122,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } // Get the receiver - receiver := block.GetAddr(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -136,10 +136,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - block.UpdateAddr(tx.Recipient, receiver) + block.state.UpdateAccount(tx.Recipient, receiver) } - block.UpdateAddr(tx.Sender(), sender) + block.state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) From d2bc57cd34fe4da3ecec3ff95bc4ef9e74589e5d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 00:55:10 +0100 Subject: [PATCH 0138/1237] PoC reactor pattern --- ethutil/common_test.go | 43 ++++++++++++++++++++++++++++++++++-------- ethutil/reactor.go | 9 +++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ethutil/common_test.go b/ethutil/common_test.go index 3a6a37ff57..b5c733ff3a 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -1,17 +1,44 @@ package ethutil import ( - "fmt" "math/big" "testing" ) func TestCommon(t *testing.T) { - fmt.Println(CurrencyToString(BigPow(10, 19))) - fmt.Println(CurrencyToString(BigPow(10, 16))) - fmt.Println(CurrencyToString(BigPow(10, 13))) - fmt.Println(CurrencyToString(BigPow(10, 10))) - fmt.Println(CurrencyToString(BigPow(10, 7))) - fmt.Println(CurrencyToString(BigPow(10, 4))) - fmt.Println(CurrencyToString(big.NewInt(10))) + ether := CurrencyToString(BigPow(10, 19)) + finney := CurrencyToString(BigPow(10, 16)) + szabo := CurrencyToString(BigPow(10, 13)) + vito := CurrencyToString(BigPow(10, 10)) + turing := CurrencyToString(BigPow(10, 7)) + eins := CurrencyToString(BigPow(10, 4)) + wei := CurrencyToString(big.NewInt(10)) + + if ether != "10 Ether" { + t.Error("Got", ether) + } + + if finney != "10 Finney" { + t.Error("Got", finney) + } + + if szabo != "10 Szabo" { + t.Error("Got", szabo) + } + + if vito != "10 Vito" { + t.Error("Got", vito) + } + + if turing != "10 Turing" { + t.Error("Got", turing) + } + + if eins != "10 Eins" { + t.Error("Got", eins) + } + + if wei != "10 Wei" { + t.Error("Got", wei) + } } diff --git a/ethutil/reactor.go b/ethutil/reactor.go index b3f8b9b5b7..f8084986c3 100644 --- a/ethutil/reactor.go +++ b/ethutil/reactor.go @@ -13,6 +13,9 @@ type ReactorEvent struct { // 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 @@ -22,11 +25,17 @@ func (e *ReactorEvent) Post(react React) { // 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:]...) From bfed1c7cac98e135ba176c03bd7b4fe51c0dc932 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 11:03:16 +0100 Subject: [PATCH 0139/1237] Trie's are no longer referenced directly but through State instead --- ethchain/block.go | 65 ++------------------------------------------ ethchain/contract.go | 17 ++++++------ ethchain/state.go | 51 +++++++++++++++++++++++++++++++++- ethchain/vm.go | 4 +-- 4 files changed, 63 insertions(+), 74 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 8de57ccedb..b5739102cc 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -126,54 +126,6 @@ func (block *Block) Transactions() []*Transaction { return block.transactions } -/* -func (block *Block) GetContract(addr []byte) *Contract { - data := block.state.Get(string(addr)) - if data == "" { - return nil - } - - value := ethutil.NewValueFromBytes([]byte(data)) - if value.Len() == 2 { - return nil - } - - contract := &Contract{} - contract.RlpDecode([]byte(data)) - - cachedState := block.contractStates[string(addr)] - if cachedState != nil { - contract.state = cachedState - } else { - block.contractStates[string(addr)] = contract.state - } - - return contract -} -func (block *Block) UpdateContract(addr []byte, contract *Contract) { - // Make sure the state is synced - //contract.State().Sync() - - block.state.trie.Update(string(addr), string(contract.RlpEncode())) -} - -func (block *Block) GetAddr(addr []byte) *Address { - var address *Address - - data := block.state.trie.Get(string(addr)) - if data == "" { - address = NewAddress(big.NewInt(0)) - } else { - address = NewAddressFromData([]byte(data)) - } - - return address -} -func (block *Block) UpdateAddr(addr []byte, address *Address) { - block.state.trie.Update(string(addr), string(address.RlpEncode())) -} -*/ - func (block *Block) PayFee(addr []byte, fee *big.Int) bool { contract := block.state.GetContract(addr) // If we can't pay the fee return @@ -210,23 +162,10 @@ func (block *Block) BlockInfo() BlockInfo { // Sync the block's state and contract respectively func (block *Block) Sync() { - /* - // Sync all contracts currently in cache - for _, val := range block.contractStates { - val.Sync() - } - */ - // Sync the block state itself - block.state.trie.Sync() + block.state.Sync() } func (block *Block) Undo() { - /* - // Sync all contracts currently in cache - for _, val := range block.contractStates { - val.Undo() - } - */ // Sync the block state itself block.state.Reset() } @@ -234,7 +173,7 @@ func (block *Block) Undo() { func (block *Block) MakeContract(tx *Transaction) { contract := MakeContract(tx, block.state) if contract != nil { - block.contractStates[string(tx.Hash()[12:])] = contract.state + block.state.states[string(tx.Hash()[12:])] = contract.state } } diff --git a/ethchain/contract.go b/ethchain/contract.go index dbcbb3697c..21ac828fe9 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -8,18 +8,19 @@ import ( type Contract struct { Amount *big.Int Nonce uint64 - state *ethutil.Trie + //state *ethutil.Trie + state *State } func NewContract(Amount *big.Int, root []byte) *Contract { contract := &Contract{Amount: Amount, Nonce: 0} - contract.state = ethutil.NewTrie(ethutil.Config.Db, string(root)) + contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) return contract } func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.Root}) + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) } func (c *Contract) RlpDecode(data []byte) { @@ -27,18 +28,18 @@ func (c *Contract) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() - c.state = ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()) + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) } func (c *Contract) Addr(addr []byte) *ethutil.Value { - return ethutil.NewValueFromBytes([]byte(c.state.Get(string(addr)))) + return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } func (c *Contract) SetAddr(addr []byte, value interface{}) { - c.state.Update(string(addr), string(ethutil.NewValue(value).Encode())) + c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *Contract) State() *ethutil.Trie { +func (c *Contract) State() *State { return c.state } @@ -59,7 +60,7 @@ func MakeContract(tx *Transaction, state *State) *Contract { for i, val := range tx.Data { if len(val) > 0 { bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.Update(string(bytNum), string(ethutil.Encode(val))) + contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) } } state.trie.Update(string(addr), string(contract.RlpEncode())) diff --git a/ethchain/state.go b/ethchain/state.go index cff192b545..4cd2c58ef4 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -5,16 +5,46 @@ import ( "math/big" ) +// States within the ethereum protocol are used to store anything +// within the merkle trie. States take care of caching and storing +// nested states. It's the general query interface to retrieve: +// * Contracts +// * Accounts type State struct { + // The trie for this structure trie *ethutil.Trie + // Nested states + states map[string]*State } +// Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie} + return &State{trie: trie, states: make(map[string]*State)} } +// Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() + + // Reset all nested states + for _, state := range s.states { + state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + s.trie.Sync() + + // Sync all nested states + for _, state := range s.states { + state.Sync() + } +} + +// Purges the current trie. +func (s *State) Purge() int { + return s.trie.NewIterator().Purge() } func (s *State) GetContract(addr []byte) *Contract { @@ -23,9 +53,28 @@ func (s *State) GetContract(addr []byte) *Contract { return nil } + // Whet get contract is called the retrieved value might + // be an account. The StateManager uses this to check + // to see if the address a tx was sent to is a contract + // or an account + value := ethutil.NewValueFromBytes([]byte(data)) + if value.Len() == 2 { + return nil + } + + // build contract contract := &Contract{} contract.RlpDecode([]byte(data)) + // Check if there's a cached state for this contract + cachedState := s.states[string(addr)] + if cachedState != nil { + contract.state = cachedState + } else { + // If it isn't cached, cache the state + s.states[string(addr)] = contract.state + } + return contract } diff --git a/ethchain/vm.go b/ethchain/vm.go index c7a91a9c52..7e119ac99e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -330,7 +330,7 @@ out: // Load the value in storage and push it on the stack x := vm.stack.Pop() // decode the object as a big integer - decoder := ethutil.NewValueFromBytes([]byte(contract.State().Get(x.String()))) + decoder := contract.Addr(x.Bytes()) if !decoder.IsNil() { vm.stack.Push(decoder.BigInt()) } else { @@ -375,7 +375,7 @@ out: case oSUICIDE: recAddr := vm.stack.Pop().Bytes() // Purge all memory - deletedMemory := contract.state.NewIterator().Purge() + deletedMemory := contract.state.Purge() // Add refunds to the pop'ed address refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) account := state.GetAccount(recAddr) From 9d492b0509d3614072e0f9ed9fd1dc560ba29fc9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 11:05:12 +0100 Subject: [PATCH 0140/1237] Renamed Address to Account --- ethchain/address.go | 30 +++++++++++++++--------------- ethchain/block.go | 2 +- ethchain/block_manager.go | 6 +++--- ethchain/state.go | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/ethchain/address.go b/ethchain/address.go index a228c7566f..aa1709f2cb 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -5,31 +5,31 @@ import ( "math/big" ) -type Address struct { +type Account struct { Amount *big.Int Nonce uint64 } -func NewAddress(amount *big.Int) *Address { - return &Address{Amount: amount, Nonce: 0} +func NewAccount(amount *big.Int) *Account { + return &Account{Amount: amount, Nonce: 0} } -func NewAddressFromData(data []byte) *Address { - address := &Address{} +func NewAccountFromData(data []byte) *Account { + address := &Account{} address.RlpDecode(data) return address } -func (a *Address) AddFee(fee *big.Int) { +func (a *Account) AddFee(fee *big.Int) { a.Amount.Add(a.Amount, fee) } -func (a *Address) RlpEncode() []byte { +func (a *Account) RlpEncode() []byte { return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) } -func (a *Address) RlpDecode(data []byte) { +func (a *Account) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) a.Amount = decoder.Get(0).BigInt() @@ -37,24 +37,24 @@ func (a *Address) RlpDecode(data []byte) { } type AddrStateStore struct { - states map[string]*AddressState + states map[string]*AccountState } func NewAddrStateStore() *AddrStateStore { - return &AddrStateStore{states: make(map[string]*AddressState)} + return &AddrStateStore{states: make(map[string]*AccountState)} } -func (s *AddrStateStore) Add(addr []byte, account *Address) *AddressState { - state := &AddressState{Nonce: account.Nonce, Account: account} +func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState { + state := &AccountState{Nonce: account.Nonce, Account: account} s.states[string(addr)] = state return state } -func (s *AddrStateStore) Get(addr []byte) *AddressState { +func (s *AddrStateStore) Get(addr []byte) *AccountState { return s.states[string(addr)] } -type AddressState struct { +type AccountState struct { Nonce uint64 - Account *Address + Account *Account } diff --git a/ethchain/block.go b/ethchain/block.go index b5739102cc..20af73ba26 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAddressFromData([]byte(data)) + ether := NewAccountFromData([]byte(data)) base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index 8ea71ab31e..b184fa9c91 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -85,17 +85,17 @@ func NewBlockManager(speaker PublicSpeaker) *BlockManager { } // Watches any given address and puts it in the address state store -func (bm *BlockManager) WatchAddr(addr []byte) *AddressState { +func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) } -func (bm *BlockManager) GetAddrState(addr []byte) *AddressState { +func (bm *BlockManager) GetAddrState(addr []byte) *AccountState { account := bm.addrStateStore.Get(addr) if account == nil { a := bm.bc.CurrentBlock.state.GetAccount(addr) - account = &AddressState{Nonce: a.Nonce, Account: a} + account = &AccountState{Nonce: a.Nonce, Account: a} } return account diff --git a/ethchain/state.go b/ethchain/state.go index 4cd2c58ef4..e6649cf225 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -93,18 +93,18 @@ func Compile(code []string) (script []string) { return } -func (s *State) GetAccount(addr []byte) (account *Address) { +func (s *State) GetAccount(addr []byte) (account *Account) { data := s.trie.Get(string(addr)) if data == "" { - account = NewAddress(big.NewInt(0)) + account = NewAccount(big.NewInt(0)) } else { - account = NewAddressFromData([]byte(data)) + account = NewAccountFromData([]byte(data)) } return } -func (s *State) UpdateAccount(addr []byte, account *Address) { +func (s *State) UpdateAccount(addr []byte, account *Account) { s.trie.Update(string(addr), string(account.RlpEncode())) } From c1d0ea7366f1bad134c985dbe1f272d376e5ec9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 3 Mar 2014 11:34:04 +0100 Subject: [PATCH 0141/1237] Updated protocol version to 7 --- peer.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/peer.go b/peer.go index 9706197146..271c8708ea 100644 --- a/peer.go +++ b/peer.go @@ -17,6 +17,8 @@ import ( const ( // The size of the output buffer for writing messages outputBufferSize = 50 + // Current protocol version + ProtocolVersion = 7 ) type DiscReason byte @@ -469,7 +471,7 @@ func (p *Peer) pushHandshake() error { pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(5), uint32(0), p.Version, byte(p.caps), p.port, pubkey, + uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey, }) p.QueueMessage(msg) @@ -496,7 +498,7 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data - if c.Get(0).Uint() != 5 { + if c.Get(0).Uint() != ProtocolVersion { ethutil.Config.Log.Debugln("Invalid peer version. Require protocol v5") p.Stop() return From 8577e9116e87cb67214478a3d86241a3d06b209d Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Mon, 3 Mar 2014 18:13:08 +0100 Subject: [PATCH 0142/1237] Rename .travil.yml to .travis.yml --- ethutil/{.travil.yml => .travis.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ethutil/{.travil.yml => .travis.yml} (100%) diff --git a/ethutil/.travil.yml b/ethutil/.travis.yml similarity index 100% rename from ethutil/.travil.yml rename to ethutil/.travis.yml From 92f2abdf769f52ea8e5e6d02bf326744e926f5b4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Mar 2014 10:42:51 +0100 Subject: [PATCH 0143/1237] Partially refactored server/txpool/block manager/block chain The Ethereum structure now complies to a EthManager interface which is being used by the tx pool, block manager and block chain in order to gain access to each other. It's become simpeler. TODO: BlockManager => StateManager --- ethchain/block_chain.go | 29 +++++++++- ethchain/block_manager.go | 104 +++++++++++++++++++---------------- ethchain/state.go | 38 +++++++++++++ ethchain/transaction_pool.go | 18 ++---- ethereum.go | 35 ++++++++---- ethutil/value.go | 29 ++++++++++ ethutil/value_test.go | 13 +++++ peer.go | 20 ++++--- 8 files changed, 204 insertions(+), 82 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 026fc1cea9..2865e0a21f 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -9,6 +9,7 @@ import ( ) type BlockChain struct { + Ethereum EthManager // The famous, the fabulous Mister GENESIIIIIIS (block) genesisBlock *Block // Last known total difficulty @@ -20,7 +21,7 @@ type BlockChain struct { LastBlockHash []byte } -func NewBlockChain() *BlockChain { +func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) @@ -129,6 +130,21 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { return blocks } +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin + "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex + } { + //log.Println("2^200 Wei to", addr) + codedAddr := ethutil.FromHex(addr) + addr := block.state.GetAccount(codedAddr) + addr.Amount = ethutil.BigPow(2, 200) + block.state.UpdateAccount(codedAddr, addr) + } +} + func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { @@ -139,10 +155,21 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockNumber = info.Number log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + } else { + AddTestNetFunds(bc.genesisBlock) + + bc.genesisBlock.state.trie.Sync() + // Prepare the genesis block + bc.Add(bc.genesisBlock) + + //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + + log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/block_manager.go b/ethchain/block_manager.go index b184fa9c91..fa50304ea6 100644 --- a/ethchain/block_manager.go +++ b/ethchain/block_manager.go @@ -2,11 +2,9 @@ package ethchain import ( "bytes" - "encoding/hex" "fmt" "github.com/ethereum/eth-go/ethutil" - _ "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethwire" "math/big" "sync" "time" @@ -16,14 +14,20 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +type EthManager interface { + StateManager() *BlockManager + BlockChain() *BlockChain + TxPool() *TxPool + Broadcast(msgType ethwire.MsgType, data []interface{}) +} + // TODO rename to state manager type BlockManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex - // The block chain :) + // Canonical block chain bc *BlockChain - // States for addresses. You can watch any address // at any given time addrStateStore *AddrStateStore @@ -33,59 +37,41 @@ type BlockManager struct { // non-persistent key/value memory storage mem map[string]*big.Int - TransactionPool *TxPool - Pow PoW - Speaker PublicSpeaker + Ethereum EthManager SecondaryBlockProcessor BlockProcessor + + // The managed states + // Processor state. Anything processed will be applied to this + // state + procState *State + // Comparative state it used for comparing and validating end + // results + compState *State } -func AddTestNetFunds(block *Block) { - for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - } { - //log.Println("2^200 Wei to", addr) - codedAddr, _ := hex.DecodeString(addr) - addr := block.state.GetAccount(codedAddr) - addr.Amount = ethutil.BigPow(2, 200) - block.state.UpdateAccount(codedAddr, addr) - } -} - -func NewBlockManager(speaker PublicSpeaker) *BlockManager { +func NewBlockManager(ethereum EthManager) *BlockManager { bm := &BlockManager{ - //server: s, - bc: NewBlockChain(), stack: NewStack(), mem: make(map[string]*big.Int), Pow: &EasyPow{}, - Speaker: speaker, + Ethereum: ethereum, addrStateStore: NewAddrStateStore(), + bc: ethereum.BlockChain(), } - if bm.bc.CurrentBlock == nil { - AddTestNetFunds(bm.bc.genesisBlock) - - bm.bc.genesisBlock.state.trie.Sync() - // Prepare the genesis block - bm.bc.Add(bm.bc.genesisBlock) - - //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) - //bm.bc.genesisBlock.PrintHash() - } - - log.Printf("Last block: %x\n", bm.bc.CurrentBlock.Hash()) - return bm } +func (bm *BlockManager) ProcState() *State { + return bm.procState +} + // Watches any given address and puts it in the address state store func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { + //FIXME account := bm.procState.GetAccount(addr) account := bm.bc.CurrentBlock.state.GetAccount(addr) return bm.addrStateStore.Add(addr, account) @@ -105,17 +91,26 @@ func (bm *BlockManager) BlockChain() *BlockChain { return bm.bc } +func (bm *BlockManager) MakeContract(tx *Transaction) { + contract := MakeContract(tx, bm.procState) + if contract != nil { + bm.procState.states[string(tx.Hash()[12:])] = contract.state + } +} + func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract if tx.IsContract() { + //FIXME bm.MakeContract(tx) block.MakeContract(tx) } else { + //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { if contract := block.state.GetContract(tx.Recipient); contract != nil { bm.ProcessContract(contract, tx, block) } else { - err := bm.TransactionPool.ProcessTransaction(tx, block) + err := bm.Ethereum.TxPool().ProcessTransaction(tx, block) if err != nil { ethutil.Config.Log.Infoln("[BMGR]", err) } @@ -124,6 +119,18 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { } } +// The prepare function, prepares the state manager for the next +// "ProcessBlock" action. +func (bm *BlockManager) Prepare(processer *State, comparative *State) { + bm.compState = comparative + bm.procState = processer +} + +// Default prepare function +func (bm *BlockManager) PrepareDefault(block *Block) { + bm.Prepare(bm.BlockChain().CurrentBlock.State(), block.State()) +} + // Block processing and validating with a given (temporarily) state func (bm *BlockManager) ProcessBlock(block *Block) error { // Processing a blocks may never happen simultaneously @@ -161,17 +168,20 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return err } + // if !bm.compState.Cmp(bm.procState) if !block.state.Cmp(bm.bc.CurrentBlock.state) { return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) + //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", bm.compState.trie.Root, bm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db if bm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo bm.bc.CurrentBlock.Sync() + //FIXME bm.procState.Sync() // Broadcast the valid block back to the wire - //bm.Speaker.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + //bm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // Add the block to the chain bm.bc.Add(block) @@ -207,12 +217,6 @@ func (bm *BlockManager) CalculateTD(block *Block) bool { // Set the new total difficulty back to the block chain bm.bc.SetTotalDifficulty(td) - /* - if ethutil.Config.Debug { - log.Println("[BMGR] TD(block) =", td) - } - */ - return true } @@ -268,16 +272,19 @@ func CalculateUncleReward(block *Block) *big.Int { func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data addr := processor.state.GetAccount(block.Coinbase) + //FIXME addr := proc.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) processor.state.UpdateAccount(block.Coinbase, addr) + //FIXME proc.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { uncleAddr := processor.state.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) + //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -298,6 +305,7 @@ func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} + //vm.Process(contract, bm.procState, RuntimeVars{ vm.Process(contract, block.state, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, diff --git a/ethchain/state.go b/ethchain/state.go index e6649cf225..be25fe7b46 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -111,3 +111,41 @@ func (s *State) UpdateAccount(addr []byte, account *Account) { func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } + +type ObjType byte + +const ( + NilTy ObjType = iota + AccountTy + ContractTy + + UnknownTy +) + +// Returns the object stored at key and the type stored at key +// Returns nil if nothing is stored +func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { + // Fetch data from the trie + data := s.trie.Get(string(key)) + // Returns the nil type, indicating nothing could be retrieved. + // Anything using this function should check for this ret val + if data == "" { + return nil, NilTy + } + + var typ ObjType + val := ethutil.NewValueFromBytes([]byte(data)) + // Check the length of the retrieved value. + // Len 2 = Account + // Len 3 = Contract + // Other = invalid for now. If other types emerge, add them here + if val.Len() == 2 { + typ = AccountTy + } else if val.Len() == 3 { + typ = ContractTy + } else { + typ = UnknownTy + } + + return val, typ +} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 7635605709..2c9a26936d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -41,10 +41,6 @@ func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Tra return nil } -type PublicSpeaker interface { - Broadcast(msgType ethwire.MsgType, data []interface{}) -} - type TxProcessor interface { ProcessTransaction(tx *Transaction) } @@ -55,8 +51,7 @@ type TxProcessor interface { // pool is being drained or synced for whatever reason the transactions // will simple queue up and handled when the mutex is freed. type TxPool struct { - //server *Server - Speaker PublicSpeaker + Ethereum EthManager // The mutex for accessing the Tx pool. mutex sync.Mutex // Queueing channel for reading and writing incoming @@ -67,20 +62,19 @@ type TxPool struct { // The actual pool pool *list.List - BlockManager *BlockManager - SecondaryProcessor TxProcessor subscribers []chan TxMsg } -func NewTxPool() *TxPool { +func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ //server: s, mutex: sync.Mutex{}, pool: list.New(), queueChan: make(chan *Transaction, txPoolQueueSize), quit: make(chan bool), + Ethereum: ethereum, } } @@ -91,7 +85,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers - pool.Speaker.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) + pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) } // Process transaction validates the Tx and processes funds from the @@ -152,14 +146,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from // the merkle trie - block := pool.BlockManager.BlockChain().CurrentBlock + block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { return errors.New("No last block on the block chain") } // Get the sender - accountState := pool.BlockManager.GetAddrState(tx.Sender()) + accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) sender := accountState.Account totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) diff --git a/ethereum.go b/ethereum.go index b4a8cdb4ad..2c8b2ccebc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -37,10 +37,12 @@ type Ethereum struct { //db *ethdb.LDBDatabase db ethutil.Database // Block manager for processing new blocks and managing the block chain - BlockManager *ethchain.BlockManager + blockManager *ethchain.BlockManager // The transaction pool. Transaction can be pushed on this pool // for later including in the blocks - TxPool *ethchain.TxPool + txPool *ethchain.TxPool + // The canonical chain + blockChain *ethchain.BlockChain // Peers (NYI) peers *list.List // Nonce @@ -87,19 +89,28 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { serverCaps: caps, nat: nat, } - ethereum.TxPool = ethchain.NewTxPool() - ethereum.TxPool.Speaker = ethereum - ethereum.BlockManager = ethchain.NewBlockManager(ethereum) - - ethereum.TxPool.BlockManager = ethereum.BlockManager - ethereum.BlockManager.TransactionPool = ethereum.TxPool + ethereum.txPool = ethchain.NewTxPool(ethereum) + ethereum.blockChain = ethchain.NewBlockChain(ethereum) + ethereum.blockManager = ethchain.NewBlockManager(ethereum) // Start the tx pool - ethereum.TxPool.Start() + ethereum.txPool.Start() return ethereum, nil } +func (s *Ethereum) BlockChain() *ethchain.BlockChain { + return s.blockChain +} + +func (s *Ethereum) StateManager() *ethchain.BlockManager { + return s.blockManager +} + +func (s *Ethereum) TxPool() *ethchain.TxPool { + return s.txPool +} + func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) @@ -253,7 +264,7 @@ func (s *Ethereum) Start() { if ethutil.Config.Seed { ethutil.Config.Log.Debugln("Seeding") // Testnet seed bootstrapping - resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + resp, err := http.Get("https://www.ethereum.org/servers.poc3.txt") if err != nil { log.Println("Fetching seed failed:", err) return @@ -292,8 +303,8 @@ func (s *Ethereum) Stop() { close(s.quit) - s.TxPool.Stop() - s.BlockManager.Stop() + s.txPool.Stop() + s.blockManager.Stop() close(s.shutdownChan) } diff --git a/ethutil/value.go b/ethutil/value.go index 3dd84d12dd..46681ec2a5 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -224,3 +224,32 @@ func (val *Value) Append(v interface{}) *Value { return val } + +type ValueIterator struct { + value *Value + currentValue *Value + idx int +} + +func (val *Value) NewIterator() *ValueIterator { + return &ValueIterator{value: val} +} + +func (it *ValueIterator) Next() bool { + if it.idx >= it.value.Len() { + return false + } + + it.currentValue = it.value.Get(it.idx) + it.idx++ + + return true +} + +func (it *ValueIterator) Value() *Value { + return it.currentValue +} + +func (it *ValueIterator) Idx() int { + return it.idx +} diff --git a/ethutil/value_test.go b/ethutil/value_test.go index 0e2da53287..a100f44bc8 100644 --- a/ethutil/value_test.go +++ b/ethutil/value_test.go @@ -50,3 +50,16 @@ func TestValueTypes(t *testing.T) { t.Errorf("expected BigInt to return '%v', got %v", bigExp, bigInt.BigInt()) } } + +func TestIterator(t *testing.T) { + value := NewValue([]interface{}{1, 2, 3}) + it := value.NewIterator() + values := []uint64{1, 2, 3} + i := 0 + for it.Next() { + if values[i] != it.Value().Uint() { + t.Errorf("Expected %d, got %d", values[i], it.Value().Uint()) + } + i++ + } +} diff --git a/peer.go b/peer.go index 271c8708ea..22a4c32fd5 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 7 + ProtocolVersion = 8 ) type DiscReason byte @@ -49,7 +49,7 @@ var discReasonToString = []string{ } func (d DiscReason) String() string { - if len(discReasonToString) > int(d) { + if len(discReasonToString) < int(d) { return "Unknown" } @@ -293,7 +293,8 @@ func (p *Peer) HandleInbound() { var err error for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - err = p.ethereum.BlockManager.ProcessBlock(block) + // FIXME p.ethereum.BlockManager.DefaultPrepare(block) + err = p.ethereum.StateManager().ProcessBlock(block) if err != nil { if ethutil.Config.Debug { @@ -332,7 +333,7 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - p.ethereum.TxPool.QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) + p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to @@ -374,15 +375,16 @@ func (p *Peer) HandleInbound() { // Check each SHA block hash from the message and determine whether // the SHA is in the database for i := 0; i < l; i++ { - if data := msg.Data.Get(i).Bytes(); p.ethereum.BlockManager.BlockChain().HasBlock(data) { - parent = p.ethereum.BlockManager.BlockChain().GetBlock(data) + if data := + msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) { + parent = p.ethereum.BlockChain().GetBlock(data) break } } // If a parent is found send back a reply if parent != nil { - chain := p.ethereum.BlockManager.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) + chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { // If no blocks are found we send back a reply with msg not in chain @@ -554,10 +556,10 @@ func (p *Peer) String() string { func (p *Peer) CatchupWithPeer() { if !p.catchingUp { p.catchingUp = true - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash(), uint64(50)}) + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockChain().CurrentBlock.Hash(), uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockManager.BlockChain().CurrentBlock.Hash()[:4]) + ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) } } From 6c6e8b0fd7415a43c67699f145e76daff959d745 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Mar 2014 10:57:32 +0100 Subject: [PATCH 0144/1237] Renamed block manager to state manager --- .../{block_manager.go => state_manager.go} | 126 +++++++++--------- ethereum.go | 12 +- 2 files changed, 69 insertions(+), 69 deletions(-) rename ethchain/{block_manager.go => state_manager.go} (69%) diff --git a/ethchain/block_manager.go b/ethchain/state_manager.go similarity index 69% rename from ethchain/block_manager.go rename to ethchain/state_manager.go index fa50304ea6..7085146dfb 100644 --- a/ethchain/block_manager.go +++ b/ethchain/state_manager.go @@ -15,14 +15,14 @@ type BlockProcessor interface { } type EthManager interface { - StateManager() *BlockManager + StateManager() *StateManager BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) } // TODO rename to state manager -type BlockManager struct { +type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -52,8 +52,8 @@ type BlockManager struct { compState *State } -func NewBlockManager(ethereum EthManager) *BlockManager { - bm := &BlockManager{ +func NewStateManager(ethereum EthManager) *StateManager { + sm := &StateManager{ stack: NewStack(), mem: make(map[string]*big.Int), Pow: &EasyPow{}, @@ -62,57 +62,57 @@ func NewBlockManager(ethereum EthManager) *BlockManager { bc: ethereum.BlockChain(), } - return bm + return sm } -func (bm *BlockManager) ProcState() *State { - return bm.procState +func (sm *StateManager) ProcState() *State { + return sm.procState } // Watches any given address and puts it in the address state store -func (bm *BlockManager) WatchAddr(addr []byte) *AccountState { - //FIXME account := bm.procState.GetAccount(addr) - account := bm.bc.CurrentBlock.state.GetAccount(addr) +func (sm *StateManager) WatchAddr(addr []byte) *AccountState { + //FIXME account := sm.procState.GetAccount(addr) + account := sm.bc.CurrentBlock.state.GetAccount(addr) - return bm.addrStateStore.Add(addr, account) + return sm.addrStateStore.Add(addr, account) } -func (bm *BlockManager) GetAddrState(addr []byte) *AccountState { - account := bm.addrStateStore.Get(addr) +func (sm *StateManager) GetAddrState(addr []byte) *AccountState { + account := sm.addrStateStore.Get(addr) if account == nil { - a := bm.bc.CurrentBlock.state.GetAccount(addr) + a := sm.bc.CurrentBlock.state.GetAccount(addr) account = &AccountState{Nonce: a.Nonce, Account: a} } return account } -func (bm *BlockManager) BlockChain() *BlockChain { - return bm.bc +func (sm *StateManager) BlockChain() *BlockChain { + return sm.bc } -func (bm *BlockManager) MakeContract(tx *Transaction) { - contract := MakeContract(tx, bm.procState) +func (sm *StateManager) MakeContract(tx *Transaction) { + contract := MakeContract(tx, sm.procState) if contract != nil { - bm.procState.states[string(tx.Hash()[12:])] = contract.state + sm.procState.states[string(tx.Hash()[12:])] = contract.state } } -func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract if tx.IsContract() { - //FIXME bm.MakeContract(tx) + //FIXME sm.MakeContract(tx) block.MakeContract(tx) } else { //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { if contract := block.state.GetContract(tx.Recipient); contract != nil { - bm.ProcessContract(contract, tx, block) + sm.ProcessContract(contract, tx, block) } else { - err := bm.Ethereum.TxPool().ProcessTransaction(tx, block) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) if err != nil { - ethutil.Config.Log.Infoln("[BMGR]", err) + ethutil.Config.Log.Infoln("[smGR]", err) } } } @@ -121,78 +121,78 @@ func (bm *BlockManager) ApplyTransactions(block *Block, txs []*Transaction) { // The prepare function, prepares the state manager for the next // "ProcessBlock" action. -func (bm *BlockManager) Prepare(processer *State, comparative *State) { - bm.compState = comparative - bm.procState = processer +func (sm *StateManager) Prepare(processer *State, comparative *State) { + sm.compState = comparative + sm.procState = processer } // Default prepare function -func (bm *BlockManager) PrepareDefault(block *Block) { - bm.Prepare(bm.BlockChain().CurrentBlock.State(), block.State()) +func (sm *StateManager) PrepareDefault(block *Block) { + sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) } // Block processing and validating with a given (temporarily) state -func (bm *BlockManager) ProcessBlock(block *Block) error { +func (sm *StateManager) ProcessBlock(block *Block) error { // Processing a blocks may never happen simultaneously - bm.mutex.Lock() - defer bm.mutex.Unlock() + sm.mutex.Lock() + defer sm.mutex.Unlock() // Defer the Undo on the Trie. If the block processing happened // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. - defer bm.bc.CurrentBlock.Undo() + defer sm.bc.CurrentBlock.Undo() hash := block.Hash() - if bm.bc.HasBlock(hash) { + if sm.bc.HasBlock(hash) { return nil } // Check if we have the parent hash, if it isn't known we discard it // Reasons might be catching up or simply an invalid block - if !bm.bc.HasBlock(block.PrevHash) && bm.bc.CurrentBlock != nil { + if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } // Process the transactions on to current block - bm.ApplyTransactions(bm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) // Block validation - if err := bm.ValidateBlock(block); err != nil { + if err := sm.ValidateBlock(block); err != nil { return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := bm.AccumelateRewards(bm.bc.CurrentBlock, block); err != nil { + if err := sm.AccumelateRewards(sm.bc.CurrentBlock, block); err != nil { return err } - // if !bm.compState.Cmp(bm.procState) - if !block.state.Cmp(bm.bc.CurrentBlock.state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, bm.bc.CurrentBlock.State().trie.Root) - //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", bm.compState.trie.Root, bm.procState.trie.Root) + // if !sm.compState.Cmp(sm.procState) + if !block.state.Cmp(sm.bc.CurrentBlock.state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) + //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db - if bm.CalculateTD(block) { + if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - bm.bc.CurrentBlock.Sync() - //FIXME bm.procState.Sync() + sm.bc.CurrentBlock.Sync() + //FIXME sm.procState.Sync() // Broadcast the valid block back to the wire - //bm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) // Add the block to the chain - bm.bc.Add(block) + sm.bc.Add(block) // If there's a block processor present, pass in the block for further // processing - if bm.SecondaryBlockProcessor != nil { - bm.SecondaryBlockProcessor.ProcessBlock(block) + if sm.SecondaryBlockProcessor != nil { + sm.SecondaryBlockProcessor.ProcessBlock(block) } - ethutil.Config.Log.Infof("[BMGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) } else { fmt.Println("total diff failed") } @@ -200,7 +200,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error { return nil } -func (bm *BlockManager) CalculateTD(block *Block) bool { +func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) @@ -208,14 +208,14 @@ func (bm *BlockManager) CalculateTD(block *Block) bool { // TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty td := new(big.Int) - td = td.Add(bm.bc.TD, uncleDiff) + td = td.Add(sm.bc.TD, uncleDiff) td = td.Add(td, block.Difficulty) // The new TD will only be accepted if the new difficulty is // is greater than the previous. - if td.Cmp(bm.bc.TD) > 0 { + if td.Cmp(sm.bc.TD) > 0 { // Set the new total difficulty back to the block chain - bm.bc.SetTotalDifficulty(td) + sm.bc.SetTotalDifficulty(td) return true } @@ -226,20 +226,20 @@ func (bm *BlockManager) CalculateTD(block *Block) bool { // Validates the current block. Returns an error if the block was invalid, // an uncle or anything that isn't on the current block chain. // Validation validates easy over difficult (dagger takes longer time = difficult) -func (bm *BlockManager) ValidateBlock(block *Block) error { +func (sm *StateManager) ValidateBlock(block *Block) error { // TODO // 2. Check if the difficulty is correct // Check each uncle's previous hash. In order for it to be valid // is if it has the same block hash as the current - previousBlock := bm.bc.GetBlock(block.PrevHash) + previousBlock := sm.bc.GetBlock(block.PrevHash) for _, uncle := range block.Uncles { if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 { return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash) } } - diff := block.Time - bm.bc.CurrentBlock.Time + diff := block.Time - sm.bc.CurrentBlock.Time if diff < 0 { return ValidationError("Block timestamp less then prev block %v", diff) } @@ -250,7 +250,7 @@ func (bm *BlockManager) ValidateBlock(block *Block) error { } // Verify the nonce of the block. Return an error if it's not valid - if !bm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { + if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) } @@ -269,7 +269,7 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error { +func (sm *StateManager) AccumelateRewards(processor *Block, block *Block) error { // Get the coinbase rlp data addr := processor.state.GetAccount(block.Coinbase) //FIXME addr := proc.GetAccount(block.Coinbase) @@ -290,11 +290,11 @@ func (bm *BlockManager) AccumelateRewards(processor *Block, block *Block) error return nil } -func (bm *BlockManager) Stop() { - bm.bc.Stop() +func (sm *StateManager) Stop() { + sm.bc.Stop() } -func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { +func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors /* defer func() { @@ -305,7 +305,7 @@ func (bm *BlockManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} - //vm.Process(contract, bm.procState, RuntimeVars{ + //vm.Process(contract, sm.procState, RuntimeVars{ vm.Process(contract, block.state, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, diff --git a/ethereum.go b/ethereum.go index 2c8b2ccebc..342f4f573e 100644 --- a/ethereum.go +++ b/ethereum.go @@ -36,8 +36,8 @@ type Ethereum struct { // DB interface //db *ethdb.LDBDatabase db ethutil.Database - // Block manager for processing new blocks and managing the block chain - blockManager *ethchain.BlockManager + // State manager for processing new blocks and managing the over all states + stateManager *ethchain.StateManager // The transaction pool. Transaction can be pushed on this pool // for later including in the blocks txPool *ethchain.TxPool @@ -91,7 +91,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { } ethereum.txPool = ethchain.NewTxPool(ethereum) ethereum.blockChain = ethchain.NewBlockChain(ethereum) - ethereum.blockManager = ethchain.NewBlockManager(ethereum) + ethereum.stateManager = ethchain.NewStateManager(ethereum) // Start the tx pool ethereum.txPool.Start() @@ -103,8 +103,8 @@ func (s *Ethereum) BlockChain() *ethchain.BlockChain { return s.blockChain } -func (s *Ethereum) StateManager() *ethchain.BlockManager { - return s.blockManager +func (s *Ethereum) StateManager() *ethchain.StateManager { + return s.stateManager } func (s *Ethereum) TxPool() *ethchain.TxPool { @@ -304,7 +304,7 @@ func (s *Ethereum) Stop() { close(s.quit) s.txPool.Stop() - s.blockManager.Stop() + s.stateManager.Stop() close(s.shutdownChan) } From be543a6d178063a60d404a373ced296ed6d4744c Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:03:24 +0100 Subject: [PATCH 0145/1237] Removed comments --- ethchain/fees.go | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index 02f09fa04e..c0a5d2d880 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -30,46 +30,4 @@ func InitFees() { ExtroFee.Mul(ExtroFee, TxFeeRat) CryptoFee.Mul(CryptoFee, TxFeeRat) ContractFee.Mul(ContractFee, TxFeeRat) - /* - // Base for 2**64 - b60 := new(big.Int) - b60.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) - // Base for 2**80 - b80 := new(big.Int) - b80.Exp(big.NewInt(2), big.NewInt(80), big.NewInt(0)) - - StepFee.Exp(big.NewInt(10), big.NewInt(16), big.NewInt(0)) - //StepFee.Div(b60, big.NewInt(64)) - //fmt.Println("StepFee:", StepFee) - - TxFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) - //fmt.Println("TxFee:", TxFee) - - ContractFee.Exp(big.NewInt(2), big.NewInt(64), big.NewInt(0)) - //fmt.Println("ContractFee:", ContractFee) - - MemFee.Div(b60, big.NewInt(4)) - //fmt.Println("MemFee:", MemFee) - - DataFee.Div(b60, big.NewInt(16)) - //fmt.Println("DataFee:", DataFee) - - CryptoFee.Div(b60, big.NewInt(16)) - //fmt.Println("CrytoFee:", CryptoFee) - - ExtroFee.Div(b60, big.NewInt(16)) - //fmt.Println("ExtroFee:", ExtroFee) - - Period1Reward.Mul(b80, big.NewInt(1024)) - //fmt.Println("Period1Reward:", Period1Reward) - - Period2Reward.Mul(b80, big.NewInt(512)) - //fmt.Println("Period2Reward:", Period2Reward) - - Period3Reward.Mul(b80, big.NewInt(256)) - //fmt.Println("Period3Reward:", Period3Reward) - - Period4Reward.Mul(b80, big.NewInt(128)) - //fmt.Println("Period4Reward:", Period4Reward) - */ } From e7770b2332067ab0492fe46374713dbdf4ea1ac0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:06:54 +0100 Subject: [PATCH 0146/1237] Added miner state --- ethchain/state_manager.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7085146dfb..0923b017e5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -21,7 +21,6 @@ type EthManager interface { Broadcast(msgType ethwire.MsgType, data []interface{}) } -// TODO rename to state manager type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex @@ -50,6 +49,8 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { From f80984491a503f2e6cc0b5845744e943854ecade Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:09:55 +0100 Subject: [PATCH 0147/1237] Removed comments --- ethutil/trie.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index a17dc37ad9..c67f750bc7 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -219,18 +219,6 @@ func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{ } func (t *Trie) Put(node interface{}) interface{} { - /* - enc := Encode(node) - if len(enc) >= 32 { - var sha []byte - sha = Sha3Bin(enc) - //t.db.Put([]byte(sha), enc) - - return sha - } - return node - */ - /* TODO? c := Conv(t.Root) From ea873304cad4b6a9f02a6686df44da8364304905 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 6 Mar 2014 13:10:39 +0100 Subject: [PATCH 0148/1237] No longer dev --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6c49cc2dc..3553a5e351 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge). +of Concept 3". 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. @@ -35,7 +35,7 @@ get a node and connectivity going. Build ======= -This is the Developer package. For the development client please see +This is the Developer package. For the Ethereal client please see [Ethereum(G)](https://github.com/ethereum/go-ethereum). `go get -u github.com/ethereum/eth-go` From 8162aff8cfb76bf53dd06a19cf12208f7946349d Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Thu, 6 Mar 2014 19:01:38 +0100 Subject: [PATCH 0149/1237] Add DNS Bootstrapping --- ethereum.go | 53 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/ethereum.go b/ethereum.go index 342f4f573e..4dd29f2e66 100644 --- a/ethereum.go +++ b/ethereum.go @@ -262,21 +262,46 @@ func (s *Ethereum) Start() { go s.ReapDeadPeerHandler() if ethutil.Config.Seed { - ethutil.Config.Log.Debugln("Seeding") - // Testnet seed bootstrapping - resp, err := http.Get("https://www.ethereum.org/servers.poc3.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } + ethutil.Config.Log.Debugln("Seeding") + // DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if(err == nil) { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := n.Port + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if(err == nil) { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, strconv.Itoa(int(port))) + log.Println("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) + } + } else { + log.Println("Couldn't resolve :", target) + } + } + // Connect to Peer list + s.ProcessPeerList(peers) + } else { + // Fallback to servers.poc3.txt + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } - s.ConnectToPeer(string(body)) + s.ConnectToPeer(string(body)) + } } } From e2e338929f8c1fb0bc424d0f5ca3353c6f36ec77 Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Thu, 6 Mar 2014 19:03:26 +0100 Subject: [PATCH 0150/1237] Fix Whitespace --- ethereum.go | 74 ++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/ethereum.go b/ethereum.go index 4dd29f2e66..6c19a13f97 100644 --- a/ethereum.go +++ b/ethereum.go @@ -262,46 +262,46 @@ func (s *Ethereum) Start() { go s.ReapDeadPeerHandler() if ethutil.Config.Seed { - ethutil.Config.Log.Debugln("Seeding") - // DNS Bootstrapping - _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") - if(err == nil) { - peers := []string{} - // Iterate SRV nodes - for _, n := range nodes { - target := n.Target - port := n.Port - // Resolve target to ip (Go returns list, so may resolve to multiple ips?) - addr, err := net.LookupHost(target) - if(err == nil) { - for _, a := range addr { - // Build string out of SRV port and Resolved IP - peer := net.JoinHostPort(a, strconv.Itoa(int(port))) - log.Println("Found DNS Bootstrap Peer:", peer) - peers = append(peers, peer) - } - } else { - log.Println("Couldn't resolve :", target) + ethutil.Config.Log.Debugln("Seeding") + // DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if(err == nil) { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := n.Port + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if(err == nil) { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, strconv.Itoa(int(port))) + log.Println("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) } + } else { + log.Println("Couldn't resolve :", target) } - // Connect to Peer list - s.ProcessPeerList(peers) - } else { - // Fallback to servers.poc3.txt - resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } - - s.ConnectToPeer(string(body)) } + // Connect to Peer list + s.ProcessPeerList(peers) + } else { + // Fallback to servers.poc3.txt + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } + + s.ConnectToPeer(string(body)) + } } } From 9d887234eafb5884df9b2a90e3cb876688af0c21 Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Thu, 6 Mar 2014 19:11:38 +0100 Subject: [PATCH 0151/1237] Small Optimization on port --- ethereum.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index 6c19a13f97..795f2cd527 100644 --- a/ethereum.go +++ b/ethereum.go @@ -270,13 +270,13 @@ func (s *Ethereum) Start() { // Iterate SRV nodes for _, n := range nodes { target := n.Target - port := n.Port + port := strconv.Itoa(int(n.Port)) // Resolve target to ip (Go returns list, so may resolve to multiple ips?) addr, err := net.LookupHost(target) if(err == nil) { for _, a := range addr { // Build string out of SRV port and Resolved IP - peer := net.JoinHostPort(a, strconv.Itoa(int(port))) + peer := net.JoinHostPort(a, port) log.Println("Found DNS Bootstrap Peer:", peer) peers = append(peers, peer) } From 694ef4704176c4c2329b56e4cd5320f558513efb Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Fri, 7 Mar 2014 11:11:11 +0100 Subject: [PATCH 0152/1237] gofmt -w ethereum.go --- ethereum.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum.go b/ethereum.go index 795f2cd527..fb97c34b1a 100644 --- a/ethereum.go +++ b/ethereum.go @@ -264,8 +264,8 @@ func (s *Ethereum) Start() { if ethutil.Config.Seed { ethutil.Config.Log.Debugln("Seeding") // DNS Bootstrapping - _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") - if(err == nil) { + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if err == nil { peers := []string{} // Iterate SRV nodes for _, n := range nodes { @@ -273,7 +273,7 @@ func (s *Ethereum) Start() { port := strconv.Itoa(int(n.Port)) // Resolve target to ip (Go returns list, so may resolve to multiple ips?) addr, err := net.LookupHost(target) - if(err == nil) { + if err == nil { for _, a := range addr { // Build string out of SRV port and Resolved IP peer := net.JoinHostPort(a, port) From 685ea3e9a944cc982bf5afc5b3e29c935a6e4c0b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 7 Mar 2014 11:26:35 +0100 Subject: [PATCH 0153/1237] Wip keychains --- ethchain/keypair.go | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 ethchain/keypair.go diff --git a/ethchain/keypair.go b/ethchain/keypair.go new file mode 100644 index 0000000000..9fdc95972b --- /dev/null +++ b/ethchain/keypair.go @@ -0,0 +1,74 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *Account + state *State +} + +func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { + keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} + + return keyPair +} + +func (k *KeyPair) Address() []byte { + return ethutil.Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) Account() *Account { + if k.account == nil { + k.account = k.state.GetAccount(k.Address()) + } + + return k.account +} + +// Create transaction, creates a new and signed transaction, ready for processing +func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + tx := NewTransaction(receiver, value, data) + tx.Nonce = k.account.Nonce + + // Sign the transaction with the private key in this key chain + tx.Sign(k.PrivateKey) + + return tx +} + +func (k *KeyPair) RlpEncode() []byte { + return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing(state *State) *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + it := ethutil.NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + keyRing.Add(NewKeyPairFromValue(v)) + } + } + + return keyRing +} From d5efeab8f92509dec3cafcafb36e1856bb084f12 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 10 Mar 2014 11:53:02 +0100 Subject: [PATCH 0154/1237] Initial smart-miner stuff --- ethchain/block_chain.go | 1 + ethchain/dagger.go | 24 ++++++++++++++++-------- ethchain/state_manager.go | 15 +++++++++++++++ ethchain/transaction_pool.go | 8 +++++++- ethereum.go | 8 ++++++++ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2865e0a21f..93970a2c56 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -136,6 +136,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 5b4f8b2cd0..c33b3c14ec 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block) []byte + Search(block *Block, breakChan chan bool) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,15 +19,23 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block) []byte { +func (pow *EasyPow) Search(block *Block, breakChan chan bool) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) - hash := block.HashNoNonce() diff := block.Difficulty + for { - sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) - if pow.Verify(hash, diff, sha) { - return sha + select { + case shouldbreak := <-breakChan: + if shouldbreak { + log.Println("Got signal: Breaking out mining.") + return nil + } + default: + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + if pow.Verify(hash, diff, sha) { + return sha + } } } @@ -98,9 +106,9 @@ func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { for k := 0; k < amountOfRoutines; k++ { go dag.Find(obj, resChan) - } - // Wait for each go routine to finish + // Wait for each go routine to finish + } for k := 0; k < amountOfRoutines; k++ { // Get the result from the channel. 0 = quit if r := <-resChan; r != 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7085146dfb..2652f3f29f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -19,6 +19,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) + Reactor() *ethutil.ReactorEngine } // TODO rename to state manager @@ -50,6 +51,9 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + // Mining state, solely used for mining + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -69,6 +73,10 @@ func (sm *StateManager) ProcState() *State { return sm.procState } +func (sm *StateManager) MiningState() *State { + return sm.miningState +} + // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { //FIXME account := sm.procState.GetAccount(addr) @@ -97,6 +105,8 @@ func (sm *StateManager) MakeContract(tx *Transaction) { sm.procState.states[string(tx.Hash()[12:])] = contract.state } } +func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) { +} func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract @@ -126,6 +136,10 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) { sm.procState = processer } +func (sm *StateManager) PrepareMiningState() { + sm.miningState = sm.BlockChain().CurrentBlock.State() +} + // Default prepare function func (sm *StateManager) PrepareDefault(block *Block) { sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) @@ -193,6 +207,7 @@ func (sm *StateManager) ProcessBlock(block *Block) error { } ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + sm.Ethereum.Reactor().Post("newBlock", block) } else { fmt.Println("total diff failed") } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 2c9a26936d..345764d092 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,6 +91,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { + log.Println("Processing TX") defer func() { if r := recover(); r != nil { log.Println(r) @@ -137,7 +138,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) - // Notify the subscribers pool.notifySubscribers(TxPost, tx) return @@ -174,6 +174,7 @@ out: for { select { case tx := <-pool.queueChan: + log.Println("Received new Tx to queue") hash := tx.Hash() foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { return bytes.Compare(tx.Hash(), hash) == 0 @@ -190,9 +191,14 @@ out: log.Println("Validating Tx failed", err) } } else { + log.Println("Transaction ok, adding") // Call blocking version. At this point it // doesn't matter since this is a goroutine pool.addTransaction(tx) + log.Println("Added") + + // Notify the subscribers + pool.Ethereum.Reactor().Post("newTx", tx) // Notify the subscribers pool.notifySubscribers(TxPre, tx) diff --git a/ethereum.go b/ethereum.go index 342f4f573e..302f3c04fc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -60,6 +60,8 @@ type Ethereum struct { // Specifies the desired amount of maximum peers MaxPeers int + + reactor *ethutil.ReactorEngine } func New(caps Caps, usePnp bool) (*Ethereum, error) { @@ -89,6 +91,8 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { serverCaps: caps, nat: nat, } + ethereum.reactor = ethutil.NewReactorEngine() + ethereum.txPool = ethchain.NewTxPool(ethereum) ethereum.blockChain = ethchain.NewBlockChain(ethereum) ethereum.stateManager = ethchain.NewStateManager(ethereum) @@ -99,6 +103,10 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { return ethereum, nil } +func (s *Ethereum) Reactor() *ethutil.ReactorEngine { + return s.reactor +} + func (s *Ethereum) BlockChain() *ethchain.BlockChain { return s.blockChain } From b15a4985e89b1fbf67731bde2e4cef45b3fdf347 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 10:33:03 +0100 Subject: [PATCH 0155/1237] Moved on to the state manager --- ethchain/state_manager.go | 49 ++++++++++++++++++------------------ ethchain/transaction_pool.go | 4 +-- peer.go | 3 ++- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 0923b017e5..c2a31ff6c8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -62,6 +62,7 @@ func NewStateManager(ethereum EthManager) *StateManager { addrStateStore: NewAddrStateStore(), bc: ethereum.BlockChain(), } + sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm } @@ -72,8 +73,8 @@ func (sm *StateManager) ProcState() *State { // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { - //FIXME account := sm.procState.GetAccount(addr) - account := sm.bc.CurrentBlock.state.GetAccount(addr) + //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) + account := sm.procState.GetAccount(addr) return sm.addrStateStore.Add(addr, account) } @@ -104,16 +105,16 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { for _, tx := range txs { // If there's no recipient, it's a contract if tx.IsContract() { - //FIXME sm.MakeContract(tx) - block.MakeContract(tx) + sm.MakeContract(tx) + //XXX block.MakeContract(tx) } else { - //FIXME if contract := procState.GetContract(tx.Recipient); contract != nil { - if contract := block.state.GetContract(tx.Recipient); contract != nil { + if contract := sm.procState.GetContract(tx.Recipient); contract != nil { + //XXX if contract := block.state.GetContract(tx.Recipient); contract != nil { sm.ProcessContract(contract, tx, block) } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) if err != nil { - ethutil.Config.Log.Infoln("[smGR]", err) + ethutil.Config.Log.Infoln("[STATE]", err) } } } @@ -165,21 +166,21 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(sm.bc.CurrentBlock, block); err != nil { + if err := sm.AccumelateRewards(block); err != nil { return err } // if !sm.compState.Cmp(sm.procState) - if !block.state.Cmp(sm.bc.CurrentBlock.state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) - //FIXME return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + if !sm.compState.Cmp(sm.procState) { + //XXX return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - sm.bc.CurrentBlock.Sync() - //FIXME sm.procState.Sync() + //XXX sm.bc.CurrentBlock.Sync() + sm.procState.Sync() // Broadcast the valid block back to the wire //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) @@ -193,7 +194,7 @@ func (sm *StateManager) ProcessBlock(block *Block) error { sm.SecondaryBlockProcessor.ProcessBlock(block) } - ethutil.Config.Log.Infof("[smGR] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) } else { fmt.Println("total diff failed") } @@ -270,22 +271,22 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(processor *Block, block *Block) error { +func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - addr := processor.state.GetAccount(block.Coinbase) - //FIXME addr := proc.GetAccount(block.Coinbase) + //XXX addr := processor.state.GetAccount(block.Coinbase) + addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - processor.state.UpdateAccount(block.Coinbase, addr) - //FIXME proc.UpdateAccount(block.Coinbase, addr) + //XXX processor.state.UpdateAccount(block.Coinbase, addr) + sm.procState.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { - uncleAddr := processor.state.GetAccount(uncle.Coinbase) + uncleAddr := sm.procState.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) - processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) - //FIXME proc.UpdateAccount(uncle.Coinbase, uncleAddr) + //processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) + sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr) } return nil @@ -306,8 +307,8 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo */ vm := &Vm{} - //vm.Process(contract, sm.procState, RuntimeVars{ - vm.Process(contract, block.state, RuntimeVars{ + //vm.Process(contract, block.state, RuntimeVars{ + vm.Process(contract, sm.procState, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, sender: tx.Sender(), diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 2c9a26936d..fdc3863036 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -233,11 +233,11 @@ func (pool *TxPool) Start() { } func (pool *TxPool) Stop() { - log.Println("[TXP] Stopping...") - close(pool.quit) pool.Flush() + + log.Println("[TXP] Stopped") } func (pool *TxPool) Subscribe(channel chan TxMsg) { diff --git a/peer.go b/peer.go index 22a4c32fd5..89b567fb63 100644 --- a/peer.go +++ b/peer.go @@ -293,7 +293,8 @@ func (p *Peer) HandleInbound() { var err error for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - // FIXME p.ethereum.BlockManager.DefaultPrepare(block) + + p.ethereum.StateManager().PrepareDefault(block) err = p.ethereum.StateManager().ProcessBlock(block) if err != nil { From 3274e0a2496e622a847b213bb5ba0272650ef06c Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 17 Mar 2014 10:37:29 +0100 Subject: [PATCH 0156/1237] Removed extra invalid nonce return --- ethchain/transaction_pool.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 345764d092..b8366d2746 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -109,11 +109,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } if sender.Nonce != tx.Nonce { - if ethutil.Config.Debug { - return fmt.Errorf("Invalid nonce %d(%d) continueing anyway", tx.Nonce, sender.Nonce) - } else { - return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) - } + return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) } // Get the receiver From 8ea7e21f64842380833cce7aafa52b909cb8426b Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 17 Mar 2014 10:37:37 +0100 Subject: [PATCH 0157/1237] Merge --- README.md | 4 +-- ethchain/dagger.go | 23 +++++++++--- ethchain/keypair.go | 74 +++++++++++++++++++++++++++++++++++++++ ethchain/state_manager.go | 1 - ethereum.go | 51 ++++++++++++++++++++------- ethutil/trie.go | 12 ------- 6 files changed, 132 insertions(+), 33 deletions(-) create mode 100644 ethchain/keypair.go diff --git a/README.md b/README.md index f6c49cc2dc..3553a5e351 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge). +of Concept 3". 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. @@ -35,7 +35,7 @@ get a node and connectivity going. Build ======= -This is the Developer package. For the development client please see +This is the Developer package. For the Ethereal client please see [Ethereum(G)](https://github.com/ethereum/go-ethereum). `go get -u github.com/ethereum/eth-go` diff --git a/ethchain/dagger.go b/ethchain/dagger.go index c33b3c14ec..4d2034e20b 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block, breakChan chan bool) []byte + Search(block *Block, minerChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,19 +19,32 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, breakChan chan bool) []byte { +func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty + i := int64(0) + start := time.Now().UnixNano() for { select { - case shouldbreak := <-breakChan: - if shouldbreak { - log.Println("Got signal: Breaking out mining.") + case chanMessage := <-minerChan: + if _, ok := chanMessage.Resource.(*Block); ok { + log.Println("BREAKING OUT: BLOCK") + return nil + } + if _, ok := chanMessage.Resource.(*Transaction); ok { + log.Println("BREAKING OUT: TX") return nil } default: + i++ + if i%1234567 == 0 { + elapsed := time.Now().UnixNano() - start + hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 + log.Println("Hashing @", int64(hashes), "khash") + } + sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) if pow.Verify(hash, diff, sha) { return sha diff --git a/ethchain/keypair.go b/ethchain/keypair.go new file mode 100644 index 0000000000..9fdc95972b --- /dev/null +++ b/ethchain/keypair.go @@ -0,0 +1,74 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *Account + state *State +} + +func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { + keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} + + return keyPair +} + +func (k *KeyPair) Address() []byte { + return ethutil.Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) Account() *Account { + if k.account == nil { + k.account = k.state.GetAccount(k.Address()) + } + + return k.account +} + +// Create transaction, creates a new and signed transaction, ready for processing +func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + tx := NewTransaction(receiver, value, data) + tx.Nonce = k.account.Nonce + + // Sign the transaction with the private key in this key chain + tx.Sign(k.PrivateKey) + + return tx +} + +func (k *KeyPair) RlpEncode() []byte { + return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing(state *State) *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + it := ethutil.NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + keyRing.Add(NewKeyPairFromValue(v)) + } + } + + return keyRing +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 2652f3f29f..39dece40ee 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -22,7 +22,6 @@ type EthManager interface { Reactor() *ethutil.ReactorEngine } -// TODO rename to state manager type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex diff --git a/ethereum.go b/ethereum.go index 302f3c04fc..c906a6954f 100644 --- a/ethereum.go +++ b/ethereum.go @@ -271,20 +271,45 @@ func (s *Ethereum) Start() { if ethutil.Config.Seed { ethutil.Config.Log.Debugln("Seeding") - // Testnet seed bootstrapping - resp, err := http.Get("https://www.ethereum.org/servers.poc3.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } + // DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if err == nil { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := strconv.Itoa(int(n.Port)) + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if err == nil { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, port) + log.Println("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) + } + } else { + log.Println("Couldn't resolve :", target) + } + } + // Connect to Peer list + s.ProcessPeerList(peers) + } else { + // Fallback to servers.poc3.txt + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } - s.ConnectToPeer(string(body)) + s.ConnectToPeer(string(body)) + } } } diff --git a/ethutil/trie.go b/ethutil/trie.go index a17dc37ad9..c67f750bc7 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -219,18 +219,6 @@ func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{ } func (t *Trie) Put(node interface{}) interface{} { - /* - enc := Encode(node) - if len(enc) >= 32 { - var sha []byte - sha = Sha3Bin(enc) - //t.db.Put([]byte(sha), enc) - - return sha - } - return node - */ - /* TODO? c := Conv(t.Root) From 07578fe25f475bb81ad308f592de2d89016d8431 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 11:13:35 +0100 Subject: [PATCH 0158/1237] Pretty print nonce --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c2a31ff6c8..e67f0f680f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -253,7 +253,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { - return ValidationError("Block's nonce is invalid (= %v)", block.Nonce) + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Hex(block.Nonce)) } return nil From 2b9b02812e9c6f81b9e5422d5bd4f5ea425412df Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 11:14:00 +0100 Subject: [PATCH 0159/1237] Log --- peer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/peer.go b/peer.go index 89b567fb63..4e927ada46 100644 --- a/peer.go +++ b/peer.go @@ -301,6 +301,7 @@ func (p *Peer) HandleInbound() { if ethutil.Config.Debug { ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash()) ethutil.Config.Log.Infof("[PEER] %v\n", err) + ethutil.Config.Log.Infoln(block) } break } else { From 826c827e6b1922604601f15361c962aef6f7f1a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 11:15:09 +0100 Subject: [PATCH 0160/1237] Added a copy method to state --- ethchain/state.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethchain/state.go b/ethchain/state.go index be25fe7b46..b9c2c576d5 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -112,6 +112,10 @@ func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } +func (s *State) Copy() *State { + return NewState(s.trie.Copy()) +} + type ObjType byte const ( From 344e827061c896a17124a65686bdc3fbbd03d7bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Mar 2014 12:08:16 +0100 Subject: [PATCH 0161/1237] Added client string to configuration Clients can set their own client string which will be send to connected peers during the handshake. --- ethutil/config.go | 15 +++++++++------ peer.go | 3 +-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index 5fdc8e1c56..436c12b926 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -6,6 +6,7 @@ import ( "os" "os/user" "path" + "runtime" ) type LogType byte @@ -19,12 +20,13 @@ const ( type config struct { Db Database - Log *Logger - ExecPath string - Debug bool - Ver string - Pubkey []byte - Seed bool + Log *Logger + ExecPath string + Debug bool + Ver string + ClientString string + Pubkey []byte + Seed bool } var Config *config @@ -48,6 +50,7 @@ func ReadConfig(base string) *config { Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) + Config.ClientString = fmt.Sprintf("/Ethereum(G) v%s/%s", Config.Ver, runtime.GOOS) } return Config diff --git a/peer.go b/peer.go index 4e927ada46..24a5e97c95 100644 --- a/peer.go +++ b/peer.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "net" - "runtime" "strconv" "strings" "sync/atomic" @@ -158,7 +157,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, - Version: fmt.Sprintf("/Ethereum(G) v%s/%s", ethutil.Config.Ver, runtime.GOOS), + Version: ethutil.Config.ClientString, } // Set up the connection in another goroutine so we don't block the main thread From ae837c4719855384921fcaadb1a575942dc9833d Mon Sep 17 00:00:00 2001 From: Maran Date: Thu, 20 Mar 2014 11:20:29 +0100 Subject: [PATCH 0162/1237] More mining rework --- ethchain/block.go | 3 + ethchain/block_chain.go | 3 +- ethchain/dagger.go | 16 ++-- ethchain/state_manager.go | 28 ++----- ethchain/transaction_pool.go | 9 +-- ethminer/miner.go | 149 +++++++++++++++++++++++++++++++++++ peer.go | 2 +- 7 files changed, 171 insertions(+), 39 deletions(-) create mode 100644 ethminer/miner.go diff --git a/ethchain/block.go b/ethchain/block.go index 20af73ba26..d42aa7d83e 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -304,6 +304,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { func (block *Block) String() string { return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) } +func (block *Block) GetRoot() interface{} { + return block.state.trie.Root +} //////////// UNEXPORTED ///////////////// func (block *Block) header() []interface{} { diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 93970a2c56..90ad4516a0 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -44,7 +44,6 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } - block := CreateBlock( root, hash, @@ -181,8 +180,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { // Add a block to the chain and record addition information func (bc *BlockChain) Add(block *Block) { bc.writeBlockInfo(block) - // Prepare the genesis block + bc.CurrentBlock = block bc.LastBlockHash = block.Hash() diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 4d2034e20b..a80a9d4216 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -11,7 +11,7 @@ import ( ) type PoW interface { - Search(block *Block, minerChan chan ethutil.React) []byte + Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -19,7 +19,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty @@ -28,15 +28,9 @@ func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte { for { select { - case chanMessage := <-minerChan: - if _, ok := chanMessage.Resource.(*Block); ok { - log.Println("BREAKING OUT: BLOCK") - return nil - } - if _, ok := chanMessage.Resource.(*Transaction); ok { - log.Println("BREAKING OUT: TX") - return nil - } + case <-reactChan: + log.Println("[pow] Received reactor event; breaking out.") + return nil default: i++ if i%1234567 == 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3be9407450..46d8228d9c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,9 +50,6 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State - - // Mining state, solely used for mining - miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -65,7 +62,6 @@ func NewStateManager(ethereum EthManager) *StateManager { bc: ethereum.BlockChain(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() - return sm } @@ -73,10 +69,6 @@ func (sm *StateManager) ProcState() *State { return sm.procState } -func (sm *StateManager) MiningState() *State { - return sm.miningState -} - // Watches any given address and puts it in the address state store func (sm *StateManager) WatchAddr(addr []byte) *AccountState { //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) @@ -105,8 +97,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) { sm.procState.states[string(tx.Hash()[12:])] = contract.state } } -func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) { -} func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract @@ -136,17 +126,13 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) { sm.procState = processer } -func (sm *StateManager) PrepareMiningState() { - sm.miningState = sm.BlockChain().CurrentBlock.State() -} - // Default prepare function func (sm *StateManager) PrepareDefault(block *Block) { sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) } // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(block *Block) error { +func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -155,7 +141,6 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // nodes this won't happen because Commit would have been called // before that. defer sm.bc.CurrentBlock.Undo() - hash := block.Hash() if sm.bc.HasBlock(hash) { @@ -207,7 +192,9 @@ func (sm *StateManager) ProcessBlock(block *Block) error { } ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) - sm.Ethereum.Reactor().Post("newBlock", block) + if dontReact == false { + sm.Ethereum.Reactor().Post("newBlock", block) + } } else { fmt.Println("total diff failed") } @@ -285,15 +272,16 @@ func CalculateUncleReward(block *Block) *big.Int { } func (sm *StateManager) AccumelateRewards(block *Block) error { + // Get the coinbase rlp data //XXX addr := processor.state.GetAccount(block.Coinbase) addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - //XXX processor.state.UpdateAccount(block.Coinbase, addr) - sm.procState.UpdateAccount(block.Coinbase, addr) - + var acc []byte + copy(acc, block.Coinbase) + sm.procState.UpdateAccount(acc, addr) for _, uncle := range block.Uncles { uncleAddr := sm.procState.GetAccount(uncle.Coinbase) uncleAddr.AddFee(CalculateUncleReward(uncle)) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index b0df1b6c0c..26827c2891 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,7 +91,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { - log.Println("Processing TX") defer func() { if r := recover(); r != nil { log.Println(r) @@ -105,11 +104,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // funds won't invalidate this transaction but simple ignores it. totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) if sender.Amount.Cmp(totAmount) < 0 { - return errors.New("Insufficient amount in sender's account") + return errors.New("[TXPL] Insufficient amount in sender's account") } if sender.Nonce != tx.Nonce { - return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce) + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce) } // Get the receiver @@ -145,7 +144,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { - return errors.New("No last block on the block chain") + return errors.New("[TXPL] No last block on the block chain") } // Get the sender @@ -156,7 +155,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. if sender.Amount.Cmp(totAmount) < 0 { - return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) + return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } // Increment the nonce making each tx valid only once to prevent replay diff --git a/ethminer/miner.go b/ethminer/miner.go new file mode 100644 index 0000000000..f4f697abaa --- /dev/null +++ b/ethminer/miner.go @@ -0,0 +1,149 @@ +package ethminer + +import ( + "bytes" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "log" +) + +type Miner struct { + pow ethchain.PoW + ethereum ethchain.EthManager + coinbase []byte + reactChan chan ethutil.React + txs []*ethchain.Transaction + uncles []*ethchain.Block + block *ethchain.Block + powChan chan []byte + quitChan chan ethutil.React +} + +func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { + 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 + quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread + + ethereum.Reactor().Subscribe("newBlock", reactChan) + ethereum.Reactor().Subscribe("newTx", reactChan) + + // We need the quit chan to be a Reactor event. + // The POW search method is actually blocking and if we don't + // listen to the reactor events inside of the pow itself + // The miner overseer will never get the reactor events themselves + // Only after the miner will find the sha + ethereum.Reactor().Subscribe("newBlock", quitChan) + ethereum.Reactor().Subscribe("newTx", quitChan) + + miner := Miner{ + pow: ðchain.EasyPow{}, + ethereum: ethereum, + coinbase: coinbase, + reactChan: reactChan, + powChan: powChan, + quitChan: quitChan, + } + + // Insert initial TXs in our little miner 'pool' + miner.txs = ethereum.TxPool().Flush() + miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) + + return miner +} +func (miner *Miner) Start() { + // Prepare inital block + miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) + go func() { miner.listener() }() +} +func (miner *Miner) listener() { + for { + select { + case chanMessage := <-miner.reactChan: + if block, ok := chanMessage.Resource.(*ethchain.Block); ok { + log.Println("[miner] Got new block via Reactor") + if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { + // TODO: Perhaps continue mining to get some uncle rewards + log.Println("[miner] New top block found resetting state") + + // Filter out which Transactions we have that were not in this block + var newtxs []*ethchain.Transaction + for _, tx := range miner.txs { + found := false + for _, othertx := range block.Transactions() { + if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 { + found = true + } + } + if found == false { + newtxs = append(newtxs, tx) + } + } + miner.txs = newtxs + + // Setup a fresh state to mine on + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) + + } else { + if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { + log.Println("[miner] Adding uncle block") + miner.uncles = append(miner.uncles, block) + miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) + } + } + } + + if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { + log.Println("[miner] Got new transaction from Reactor", tx) + found := false + for _, ctx := range miner.txs { + if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { + break + } + + } + if found == false { + log.Println("[miner] We did not know about this transaction, adding") + miner.txs = append(miner.txs, tx) + miner.block.SetTransactions(miner.txs) + } else { + log.Println("[miner] We already had this transaction, ignoring") + } + } + default: + log.Println("[miner] Mining on block. Includes", len(miner.txs), "transactions") + + // Apply uncles + if len(miner.uncles) > 0 { + miner.block.SetUncles(miner.uncles) + } + + // Apply all transactions to the block + miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions()) + miner.ethereum.StateManager().AccumelateRewards(miner.block) + + // Search the nonce + log.Println("[miner] Initialision complete, starting mining") + miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) + if miner.block.Nonce != nil { + miner.ethereum.StateManager().PrepareDefault(miner.block) + err := miner.ethereum.StateManager().ProcessBlock(miner.block, true) + if err != nil { + log.Println("Error result from process block:", err) + log.Println(miner.block) + } else { + + if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { + log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) + } + miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) + log.Printf("[miner] 🔨 Mined block %x\n", miner.block.Hash()) + log.Println(miner.block) + + miner.txs = []*ethchain.Transaction{} // Move this somewhere neat + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) + } + } + } + } +} diff --git a/peer.go b/peer.go index 4e927ada46..6b914710d7 100644 --- a/peer.go +++ b/peer.go @@ -295,7 +295,7 @@ func (p *Peer) HandleInbound() { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) p.ethereum.StateManager().PrepareDefault(block) - err = p.ethereum.StateManager().ProcessBlock(block) + err = p.ethereum.StateManager().ProcessBlock(block, true) if err != nil { if ethutil.Config.Debug { From bdc0d1b7ad4e2a4ff78f287f088c13a5d6ab2148 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:24:02 +0100 Subject: [PATCH 0163/1237] Added AddFunds method --- ethchain/address.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ethchain/address.go b/ethchain/address.go index aa1709f2cb..f1f27a1a5a 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -22,7 +22,11 @@ func NewAccountFromData(data []byte) *Account { } func (a *Account) AddFee(fee *big.Int) { - a.Amount.Add(a.Amount, fee) + a.AddFunds(fee) +} + +func (a *Account) AddFunds(funds *big.Int) { + a.Amount.Add(a.Amount, funds) } func (a *Account) RlpEncode() []byte { From c135b389fe358006bd3586097e1b17232b0c86e6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:24:53 +0100 Subject: [PATCH 0164/1237] Commented out code due to rewrite vm --- ethchain/block_manager_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethchain/block_manager_test.go b/ethchain/block_manager_test.go index ec4fbe8c5c..3a1e5f5104 100644 --- a/ethchain/block_manager_test.go +++ b/ethchain/block_manager_test.go @@ -1,5 +1,6 @@ package ethchain +/* import ( _ "fmt" "github.com/ethereum/eth-go/ethdb" @@ -14,9 +15,10 @@ func TestVm(t *testing.T) { db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db - bm := NewBlockManager(nil) + bm := NewStateManager(nil) block := bm.bc.genesisBlock + bm.Prepare(block.State(), block.State()) script := Compile([]string{ "PUSH", "1", @@ -31,3 +33,4 @@ func TestVm(t *testing.T) { tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) bm.ApplyTransactions(block, []*Transaction{tx2}) } +*/ From 82d0f65dab253e215349ea685382bca9672378d8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:25:11 +0100 Subject: [PATCH 0165/1237] Comply to Callee structure --- ethchain/contract.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethchain/contract.go b/ethchain/contract.go index 21ac828fe9..10c5e2df67 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -43,12 +43,17 @@ func (c *Contract) State() *State { return c.state } -func (c *Contract) GetMem(num int) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(int64(num)), 256) +func (c *Contract) GetMem(num int64) *ethutil.Value { + nb := ethutil.BigToBytes(big.NewInt(num), 256) return c.Addr(nb) } +// Return the gas back to the origin. Used by the Virtual machine or Closures +func (c *Contract) ReturnGas(val *big.Int, state *State) { + c.Amount.Add(c.Amount, val) +} + func MakeContract(tx *Transaction, state *State) *Contract { // Create contract if there's no recipient if tx.IsContract() { From 38ea6a6d5dffb7573b29541c2a6687145bdcc495 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:07 +0100 Subject: [PATCH 0166/1237] Closures and vm based on closures Status: Work in progress --- ethchain/closure.go | 68 +++++++++++++++++++++++++++++++ ethchain/vm.go | 98 ++++++++++++++++++++++++++++++++++++++++++--- ethchain/vm_test.go | 56 ++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 ethchain/closure.go diff --git a/ethchain/closure.go b/ethchain/closure.go new file mode 100644 index 0000000000..4ef43a2da4 --- /dev/null +++ b/ethchain/closure.go @@ -0,0 +1,68 @@ +package ethchain + +// TODO Re write VM to use values instead of big integers? + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type Callee interface { + ReturnGas(*big.Int, *State) +} + +type ClosureBody interface { + Callee + ethutil.RlpEncodable + GetMem(int64) *ethutil.Value +} + +// Basic inline closure object which implement the 'closure' interface +type Closure struct { + callee Callee + object ClosureBody + state *State + + gas *big.Int + val *big.Int +} + +// Create a new closure for the given data items +func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { + return &Closure{callee, object, state, gas, val} +} + +// Retuns the x element in data slice +func (c *Closure) GetMem(x int64) *ethutil.Value { + m := c.object.GetMem(x) + if m == nil { + return ethutil.EmptyValue() + } + + return m +} + +func (c *Closure) Return(ret []byte) []byte { + // Return the remaining gas to the callee + // If no callee is present return it to + // the origin (i.e. contract or tx) + if c.callee != nil { + c.callee.ReturnGas(c.gas, c.state) + } else { + c.object.ReturnGas(c.gas, c.state) + // TODO incase it's a POST contract we gotta serialise the contract again. + // But it's not yet defined + } + + return ret +} + +// Implement the Callee interface +func (c *Closure) ReturnGas(gas *big.Int, state *State) { + // Return the gas to the closure + c.gas.Add(c.gas, gas) +} + +func (c *Closure) GetGas() *big.Int { + return c.gas +} diff --git a/ethchain/vm.go b/ethchain/vm.go index 7e119ac99e..861b041d8a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -32,13 +32,101 @@ type RuntimeVars struct { txData []string } +func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byte { + // If the amount of gas supplied is less equal to 0 + if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { + // TODO Do something + } + + // Memory for the current closure + var mem []byte + // New stack (should this be shared?) + stack := NewStack() + // Instruction pointer + pc := int64(0) + // Current address + //addr := vars.address + step := 0 + + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } + + for { + step++ + // Get the memory location of pc + val := closure.GetMem(pc) + // Get the opcode (it must be an opcode!) + op := OpCode(val.Uint()) + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + + // TODO Get each instruction cost properly + fee := new(big.Int) + fee.Add(fee, big.NewInt(1000)) + + if closure.GetGas().Cmp(fee) < 0 { + return closure.Return(nil) + } + + switch op { + case oSTOP: + return closure.Return(nil) + case oPUSH: + pc++ + val := closure.GetMem(pc).BigInt() + stack.Push(val) + case oMSTORE: + // Pop value of the stack + val := stack.Pop() + // Set the bytes to the memory field + mem = append(mem, ethutil.BigToBytes(val, 256)...) + case oCALL: + // Pop return size and offset + retSize, retOffset := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // TODO remove me. + fmt.Sprintln(inSize, inOffset) + // Pop gas and value of the stack. + gas, value := stack.Popn() + // Closure addr + addr := stack.Pop() + + contract := state.GetContract(addr.Bytes()) + closure := NewClosure(closure, contract, state, gas, value) + ret := vm.RunClosure(closure, state, vars) + + // Ensure that memory is large enough to hold the returned data + totSize := new(big.Int).Add(retOffset, retSize) + lenSize := big.NewInt(int64(len(mem))) + // Resize the current memory slice so that the return value may fit + if totSize.Cmp(lenSize) > 0 { + diff := new(big.Int).Sub(totSize, lenSize) + newSlice := make([]byte, diff.Int64()+1) + mem = append(mem, newSlice...) + } + copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) + case oRETURN: + size, offset := stack.Popn() + ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] + + return closure.Return(ret) + } + + pc++ + } +} + +// Old VM code func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { vm.mem = make(map[string]*big.Int) vm.stack = NewStack() addr := vars.address // tx.Hash()[12:] // Instruction pointer - pc := 0 + pc := int64(0) if contract == nil { fmt.Println("Contract not found") @@ -344,7 +432,7 @@ out: contract.SetAddr(addr, y) //contract.State().Update(string(idx), string(y)) case oJMP: - x := int(vm.stack.Pop().Uint64()) + x := vm.stack.Pop().Int64() // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) pc = x pc-- @@ -352,7 +440,7 @@ out: x := vm.stack.Pop() // Set pc to x if it's non zero if x.Cmp(ethutil.BigFalse) != 0 { - pc = int(x.Uint64()) + pc = x.Int64() pc-- } case oIND: @@ -400,9 +488,9 @@ out: func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) - j := 0 + j := int64(0) dataItems := make([]string, int(length.Uint64())) - for i := from.Uint64(); i < length.Uint64(); i++ { + for i := from.Int64(); i < length.Int64(); i++ { dataItems[j] = contract.GetMem(j).Str() j++ } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 6ceb0ff150..4e72c92492 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -8,6 +8,8 @@ import ( "testing" ) +/* + func TestRun(t *testing.T) { InitFees() @@ -104,3 +106,57 @@ func TestRun2(t *testing.T) { txData: tx.Data, }) } +*/ + +// XXX Full stack test +func TestRun3(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + script := Compile([]string{ + "PUSH", "300", + "MSTORE", + "PUSH", "300", + "MSTORE", + "PUSH", "62", + "PUSH", "0", + "RETURN", + }) + tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + addr := tx.Hash()[12:] + fmt.Printf("addr contract %x\n", addr) + contract := MakeContract(tx, state) + state.UpdateContract(addr, contract) + + callerScript := Compile([]string{ + "PUSH", "62", // REND + "PUSH", "0", // RSTART + "PUSH", "22", // MEND + "PUSH", "15", // MSTART + "PUSH", "1000", /// Gas + "PUSH", "0", /// value + "PUSH", string(addr), // Sender + "CALL", + }) + callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerAddr := callerTx.Hash()[12:] + executer := NewTransaction(ContractAddr, ethutil.Big("10000"), nil) + + executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) + callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + + vm := &Vm{} + vm.RunClosure(callerClosure, state, RuntimeVars{ + address: callerAddr, + blockNumber: 1, + sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + txValue: big.NewInt(10000), + txData: nil, + }) +} From 59d8dc39505981d1ae07b05a71d3f4cf1f33319a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:30 +0100 Subject: [PATCH 0167/1237] Fixed issue with stack where it sliced of the wrong values --- ethchain/stack.go | 86 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 13b0f247b6..349e7817a4 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -60,6 +61,10 @@ const ( oBALANCE = 0x3c oMKTX = 0x3d oSUICIDE = 0x3f + + // TODO FIX OPCODES + oCALL = 0x40 + oRETURN = 0x41 ) // Since the opcodes aren't all in order we can't use a regular slice @@ -114,6 +119,9 @@ var opCodeToString = map[OpCode]string{ oBALANCE: "BALANCE", oMKTX: "MKTX", oSUICIDE: "SUICIDE", + + oCALL: "CALL", + oRETURN: "RETURN", } func (o OpCode) String() string { @@ -141,35 +149,27 @@ func NewStack() *Stack { } func (st *Stack) Pop() *big.Int { - s := len(st.data) - - str := st.data[s-1] - st.data = st.data[:s-1] + str := st.data[0] + st.data = st.data[1:] return str } func (st *Stack) Popn() (*big.Int, *big.Int) { - s := len(st.data) - - ints := st.data[s-2:] - st.data = st.data[:s-2] + ints := st.data[:2] + st.data = st.data[2:] return ints[0], ints[1] } func (st *Stack) Peek() *big.Int { - s := len(st.data) - - str := st.data[s-1] + str := st.data[0] return str } func (st *Stack) Peekn() (*big.Int, *big.Int) { - s := len(st.data) - - ints := st.data[s-2:] + ints := st.data[:2] return ints[0], ints[1] } @@ -188,3 +188,61 @@ func (st *Stack) Print() { } fmt.Println("#############") } + +////////////// TODO this will eventually become the main stack once the big ints are removed from the VM +type ValueStack struct { + data []*ethutil.Value +} + +func NewValueStack() *ValueStack { + return &ValueStack{} +} + +func (st *ValueStack) Pop() *ethutil.Value { + s := len(st.data) + + str := st.data[s-1] + st.data = st.data[:s-1] + + return str +} + +func (st *ValueStack) Popn() (*ethutil.Value, *ethutil.Value) { + s := len(st.data) + + ints := st.data[s-2:] + st.data = st.data[:s-2] + + return ints[0], ints[1] +} + +func (st *ValueStack) Peek() *ethutil.Value { + s := len(st.data) + + str := st.data[s-1] + + return str +} + +func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { + s := len(st.data) + + ints := st.data[s-2:] + + return ints[0], ints[1] +} + +func (st *ValueStack) Push(d *ethutil.Value) { + st.data = append(st.data, d) +} +func (st *ValueStack) Print() { + fmt.Println("### STACK ###") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("#############") +} From c17381b853e2d762787ca30c5ce45aeece99dfd1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:26:51 +0100 Subject: [PATCH 0168/1237] Moved code around --- ethchain/state.go | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index b9c2c576d5..b84d60c6ca 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -79,20 +79,10 @@ func (s *State) GetContract(addr []byte) *Contract { } func (s *State) UpdateContract(addr []byte, contract *Contract) { + s.states[string(addr)] = contract.state s.trie.Update(string(addr), string(contract.RlpEncode())) } -func Compile(code []string) (script []string) { - script = make([]string, len(code)) - for i, val := range code { - instr, _ := ethutil.CompileInstr(val) - - script[i] = string(instr) - } - - return -} - func (s *State) GetAccount(addr []byte) (account *Account) { data := s.trie.Get(string(addr)) if data == "" { @@ -153,3 +143,31 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { return val, typ } + +func (s *State) Put(key, object []byte) { + s.trie.Update(string(key), string(object)) +} + +// Script compilation functions +// Compiles strings to machine code +func Compile(code []string) (script []string) { + script = make([]string, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = string(instr) + } + + return +} + +func CompileToValues(code []string) (script []*ethutil.Value) { + script = make([]*ethutil.Value, len(code)) + for i, val := range code { + instr, _ := ethutil.CompileInstr(val) + + script[i] = ethutil.NewValue(instr) + } + + return +} From 3520771d68df1e9becfb29cc2f85d7042f3fb9d1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:09 +0100 Subject: [PATCH 0169/1237] Comply to Callee interface --- ethchain/transaction.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 57df9cdc4d..07e7ea970e 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,6 +29,15 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } +// Implements Callee +func (tx *Transaction) ReturnGas(value *big.Int, state *State) { + // Return the value back to the sender + sender := tx.Sender() + account := state.GetAccount(sender) + account.AddFunds(value) + state.UpdateAccount(sender, account) +} + // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) From c642094cac6ee6fb0215d7510cc57a719c2a2689 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:26 +0100 Subject: [PATCH 0170/1237] Added encoder interface --- ethutil/rlp.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index e633f5f1dc..33ec0d3598 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -9,6 +9,10 @@ import ( "math/big" ) +type RlpEncodable interface { + RlpEncode() []byte +} + type RlpEncoder struct { rlpData []byte } From f21eb88ad1cf54b342187e8d3b55374a695cd524 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 17:27:48 +0100 Subject: [PATCH 0171/1237] Some minor updates --- ethutil/config.go | 6 +++++- ethutil/parsing.go | 10 +++++++++- ethutil/trie_test.go | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index 436c12b926..54b066fb95 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,12 +50,16 @@ func ReadConfig(base string) *config { Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) - Config.ClientString = fmt.Sprintf("/Ethereum(G) v%s/%s", Config.Ver, runtime.GOOS) + Config.SetClientString("/Ethereum(G)") } return Config } +func (c *config) SetClientString(str string) { + Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) +} + type LoggerType byte const ( diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 553bb97178..459cdc284f 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -58,6 +58,10 @@ var OpCodes = map[string]byte{ "BALANCE": 0x3c, "MKTX": 0x3d, "SUICIDE": 0x3f, + + // TODO FIX OPCODES + "CALL": 0x40, + "RETURN": 0x41, } func IsOpCode(s string) bool { @@ -76,7 +80,11 @@ func CompileInstr(s string) ([]byte, error) { } num := new(big.Int) - num.SetString(s, 0) + _, success := num.SetString(s, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(s)) + } return num.Bytes(), nil } diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 7c398f1de9..79e5de9211 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,6 +1,7 @@ package ethutil import ( + "fmt" "reflect" "testing" ) From c68ff9886bdd59294bc2bf0a6b8bf9b83645cc9a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 19:50:53 +0100 Subject: [PATCH 0172/1237] Fixed MSTORE and added some more commets --- ethchain/closure.go | 16 ++++++++++++---- ethchain/stack.go | 1 + ethchain/vm.go | 46 +++++++++++++++++++++++++++++++++------------ ethchain/vm_test.go | 6 ++++-- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 4ef43a2da4..204fbce060 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -21,15 +21,17 @@ type ClosureBody interface { type Closure struct { callee Callee object ClosureBody - state *State + State *State gas *big.Int val *big.Int + + args []byte } // Create a new closure for the given data items func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, state, gas, val} + return &Closure{callee, object, state, gas, val, nil} } // Retuns the x element in data slice @@ -42,14 +44,20 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) Call(vm *Vm, args []byte) []byte { + c.args = args + + return vm.RunClosure(c) +} + func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the callee // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.gas, c.state) + c.callee.ReturnGas(c.gas, c.State) } else { - c.object.ReturnGas(c.gas, c.state) + c.object.ReturnGas(c.gas, c.State) // TODO incase it's a POST contract we gotta serialise the contract again. // But it's not yet defined } diff --git a/ethchain/stack.go b/ethchain/stack.go index 349e7817a4..bfb19614ee 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -235,6 +235,7 @@ func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { func (st *ValueStack) Push(d *ethutil.Value) { st.data = append(st.data, d) } + func (st *ValueStack) Print() { fmt.Println("### STACK ###") if len(st.data) > 0 { diff --git a/ethchain/vm.go b/ethchain/vm.go index 861b041d8a..2fa78a748c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -18,6 +18,8 @@ type Vm struct { mem map[string]*big.Int vars RuntimeVars + + state *State } type RuntimeVars struct { @@ -32,7 +34,11 @@ type RuntimeVars struct { txData []string } -func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byte { +func NewVm(state *State, vars RuntimeVars) *Vm { + return &Vm{vars: vars, state: state} +} + +func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -71,17 +77,28 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt } switch op { - case oSTOP: + case oSTOP: // Stop the closure return closure.Return(nil) - case oPUSH: + case oPUSH: // Push PC+1 on to the stack pc++ val := closure.GetMem(pc).BigInt() stack.Push(val) - case oMSTORE: + case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack - val := stack.Pop() - // Set the bytes to the memory field - mem = append(mem, ethutil.BigToBytes(val, 256)...) + val, mStart := stack.Popn() + // Ensure that memory is large enough to hold the data + // If it isn't resize the memory slice so that it may hold the value + bytesLen := big.NewInt(32) + totSize := new(big.Int).Add(mStart, bytesLen) + lenSize := big.NewInt(int64(len(mem))) + if totSize.Cmp(lenSize) > 0 { + // Calculate the diff between the sizes + diff := new(big.Int).Sub(totSize, lenSize) + // Create a new empty slice and append it + newSlice := make([]byte, diff.Int64()+1) + mem = append(mem, newSlice...) + } + copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256)) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() @@ -93,20 +110,25 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt gas, value := stack.Popn() // Closure addr addr := stack.Pop() - - contract := state.GetContract(addr.Bytes()) - closure := NewClosure(closure, contract, state, gas, value) - ret := vm.RunClosure(closure, state, vars) + // Fetch the contract which will serve as the closure body + contract := vm.state.GetContract(addr.Bytes()) + // Create a new callable closure + closure := NewClosure(closure, contract, vm.state, gas, value) + // Executer the closure and get the return value (if any) + ret := closure.Call(vm, nil) // Ensure that memory is large enough to hold the returned data + // If it isn't resize the memory slice so that it may hold the value totSize := new(big.Int).Add(retOffset, retSize) lenSize := big.NewInt(int64(len(mem))) - // Resize the current memory slice so that the return value may fit if totSize.Cmp(lenSize) > 0 { + // Calculate the diff between the sizes diff := new(big.Int).Sub(totSize, lenSize) + // Create a new empty slice and append it newSlice := make([]byte, diff.Int64()+1) mem = append(mem, newSlice...) } + // Copy over the returned values to the memory given the offset and size copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) case oRETURN: size, offset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 4e72c92492..654ddb5663 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -117,8 +117,10 @@ func TestRun3(t *testing.T) { script := Compile([]string{ "PUSH", "300", + "PUSH", "0", "MSTORE", "PUSH", "300", + "PUSH", "31", "MSTORE", "PUSH", "62", "PUSH", "0", @@ -147,8 +149,7 @@ func TestRun3(t *testing.T) { executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) - vm := &Vm{} - vm.RunClosure(callerClosure, state, RuntimeVars{ + vm := NewVm(state, RuntimeVars{ address: callerAddr, blockNumber: 1, sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), @@ -159,4 +160,5 @@ func TestRun3(t *testing.T) { txValue: big.NewInt(10000), txData: nil, }) + callerClosure.Call(vm, nil) } From f3d27bf5d878120346f8cdd0744e7f1f8e1ee631 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 22:51:20 +0100 Subject: [PATCH 0173/1237] Rewrote opcodes again --- ethchain/stack.go | 301 ++++++++++++++++++-------------------- ethchain/state_manager.go | 3 +- ethchain/vm.go | 41 ++---- ethutil/parsing.go | 117 ++++++++------- 4 files changed, 217 insertions(+), 245 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index bfb19614ee..429c31d082 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,7 +2,7 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" + _ "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -10,116 +10,136 @@ type OpCode int // Op codes const ( - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oLE = 0x0b - oGT = 0x0c - oGE = 0x0d - oEQ = 0x0e - oNOT = 0x0f - oMYADDRESS = 0x10 - oTXSENDER = 0x11 - oTXVALUE = 0x12 - oTXDATAN = 0x13 - oTXDATA = 0x14 - oBLK_PREVHASH = 0x15 - oBLK_COINBASE = 0x16 - oBLK_TIMESTAMP = 0x17 - oBLK_NUMBER = 0x18 - oBLK_DIFFICULTY = 0x19 - oBLK_NONCE = 0x1a - oBASEFEE = 0x1b - oSHA256 = 0x20 - oRIPEMD160 = 0x21 - oECMUL = 0x22 - oECADD = 0x23 - oECSIGN = 0x24 - oECRECOVER = 0x25 - oECVALID = 0x26 - oSHA3 = 0x27 - oPUSH = 0x30 - oPOP = 0x31 - oDUP = 0x32 - oSWAP = 0x33 - oMLOAD = 0x34 - oMSTORE = 0x35 - oSLOAD = 0x36 - oSSTORE = 0x37 - oJMP = 0x38 - oJMPI = 0x39 - oIND = 0x3a - oEXTRO = 0x3b - oBALANCE = 0x3c - oMKTX = 0x3d - oSUICIDE = 0x3f + // 0x0 range - arithmetic ops + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oGT = 0x0b + oEQ = 0x0c + oNOT = 0x0d - // TODO FIX OPCODES - oCALL = 0x40 - oRETURN = 0x41 + // 0x10 range - bit ops + oAND = 0x10 + oOR = 0x11 + oXOR = 0x12 + oBYTE = 0x13 + + // 0x20 range - crypto + oSHA3 = 0x20 + + // 0x30 range - closure state + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oRETURNDATASIZE = 0x37 + oTXGASPRICE = 0x38 + + // 0x40 range - block operations + oPREVHASH = 0x40 + oPREVNONCE = 0x41 + oCOINBASE = 0x42 + oTIMESTAMP = 0x43 + oNUMBER = 0x44 + oDIFFICULTY = 0x45 + oGASLIMIT = 0x46 + + // 0x50 range - 'storage' and execution + oPUSH = 0x50 + oPOP = 0x51 + oDUP = 0x52 + oSWAP = 0x53 + oMLOAD = 0x54 + oMSTORE = 0x55 + oMSTORE8 = 0x56 + oSLOAD = 0x57 + oSSTORE = 0x58 + oJUMP = 0x59 + oJUMPI = 0x5a + oPC = 0x5b + oMEMSIZE = 0x5c + + // 0x60 range - closures + oCREATE = 0x60 + oCALL = 0x61 + oRETURN = 0x62 ) // Since the opcodes aren't all in order we can't use a regular slice var opCodeToString = map[OpCode]string{ - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oLE: "LE", - oGT: "GT", - oGE: "GE", - oEQ: "EQ", - oNOT: "NOT", - oMYADDRESS: "MYADDRESS", - oTXSENDER: "TXSENDER", - oTXVALUE: "TXVALUE", - oTXDATAN: "TXDATAN", - oTXDATA: "TXDATA", - oBLK_PREVHASH: "BLK_PREVHASH", - oBLK_COINBASE: "BLK_COINBASE", - oBLK_TIMESTAMP: "BLK_TIMESTAMP", - oBLK_NUMBER: "BLK_NUMBER", - oBLK_DIFFICULTY: "BLK_DIFFICULTY", - oBASEFEE: "BASEFEE", - oSHA256: "SHA256", - oRIPEMD160: "RIPEMD160", - oECMUL: "ECMUL", - oECADD: "ECADD", - oECSIGN: "ECSIGN", - oECRECOVER: "ECRECOVER", - oECVALID: "ECVALID", - oSHA3: "SHA3", - oPUSH: "PUSH", - oPOP: "POP", - oDUP: "DUP", - oSWAP: "SWAP", - oMLOAD: "MLOAD", - oMSTORE: "MSTORE", - oSLOAD: "SLOAD", - oSSTORE: "SSTORE", - oJMP: "JMP", - oJMPI: "JMPI", - oIND: "IND", - oEXTRO: "EXTRO", - oBALANCE: "BALANCE", - oMKTX: "MKTX", - oSUICIDE: "SUICIDE", + // 0x0 range - arithmetic ops + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oGT: "GT", + oEQ: "EQ", + oNOT: "NOT", + // 0x10 range - bit ops + oAND: "AND", + oOR: "OR", + oXOR: "XOR", + oBYTE: "BYTE", + + // 0x20 range - crypto + oSHA3: "SHA3", + + // 0x30 range - closure state + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oRETURNDATASIZE: "RETURNDATASIZE", + oTXGASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + oPREVHASH: "PREVHASH", + oPREVNONCE: "PREVNONCE", + oCOINBASE: "COINBASE", + oTIMESTAMP: "TIMESTAMP", + oNUMBER: "NUMBER", + oDIFFICULTY: "DIFFICULTY", + oGASLIMIT: "GASLIMIT", + + // 0x50 range - 'storage' and execution + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oMSTORE8: "MSTORE8", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJUMP: "JUMP", + oJUMPI: "JUMPI", + oPC: "PC", + oMEMSIZE: "MEMSIZE", + + // 0x60 range - closures + oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", } @@ -189,61 +209,26 @@ func (st *Stack) Print() { fmt.Println("#############") } -////////////// TODO this will eventually become the main stack once the big ints are removed from the VM -type ValueStack struct { - data []*ethutil.Value +type Memory struct { + store []byte } -func NewValueStack() *ValueStack { - return &ValueStack{} -} - -func (st *ValueStack) Pop() *ethutil.Value { - s := len(st.data) - - str := st.data[s-1] - st.data = st.data[:s-1] - - return str -} - -func (st *ValueStack) Popn() (*ethutil.Value, *ethutil.Value) { - s := len(st.data) - - ints := st.data[s-2:] - st.data = st.data[:s-2] - - return ints[0], ints[1] -} - -func (st *ValueStack) Peek() *ethutil.Value { - s := len(st.data) - - str := st.data[s-1] - - return str -} - -func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) { - s := len(st.data) - - ints := st.data[s-2:] - - return ints[0], ints[1] -} - -func (st *ValueStack) Push(d *ethutil.Value) { - st.data = append(st.data, d) -} - -func (st *ValueStack) Print() { - fmt.Println("### STACK ###") - if len(st.data) > 0 { - for i, val := range st.data { - fmt.Printf("%-3d %v\n", i, val) +func (m *Memory) Set(offset, size int64, value []byte) { + totSize := offset + size + lenSize := int64(len(m.store)) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff+1) + // Resize slice + m.store = append(m.store, newSlice...) } - } else { - fmt.Println("-- empty --") } - fmt.Println("#############") + copy(m.store[offset:offset+size+1], value) +} + +func (m *Memory) Get(offset, size int64) []byte { + return m.store[offset : offset+size] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e67f0f680f..14686b217f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -306,8 +306,8 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() */ + /*TODO to be fixed and replaced by the new vm vm := &Vm{} - //vm.Process(contract, block.state, RuntimeVars{ vm.Process(contract, sm.procState, RuntimeVars{ address: tx.Hash()[12:], blockNumber: block.BlockInfo().Number, @@ -319,4 +319,5 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo txValue: tx.Value, txData: tx.Data, }) + */ } diff --git a/ethchain/vm.go b/ethchain/vm.go index 2fa78a748c..6479409f87 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -1,12 +1,12 @@ package ethchain import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/secp256k1-go" + _ "github.com/obscuren/secp256k1-go" "log" - "math" + _ "math" "math/big" ) @@ -45,7 +45,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } // Memory for the current closure - var mem []byte + mem := &Memory{} // New stack (should this be shared?) stack := NewStack() // Instruction pointer @@ -86,19 +86,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() - // Ensure that memory is large enough to hold the data - // If it isn't resize the memory slice so that it may hold the value - bytesLen := big.NewInt(32) - totSize := new(big.Int).Add(mStart, bytesLen) - lenSize := big.NewInt(int64(len(mem))) - if totSize.Cmp(lenSize) > 0 { - // Calculate the diff between the sizes - diff := new(big.Int).Sub(totSize, lenSize) - // Create a new empty slice and append it - newSlice := make([]byte, diff.Int64()+1) - mem = append(mem, newSlice...) - } - copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() @@ -116,23 +104,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) - - // Ensure that memory is large enough to hold the returned data - // If it isn't resize the memory slice so that it may hold the value - totSize := new(big.Int).Add(retOffset, retSize) - lenSize := big.NewInt(int64(len(mem))) - if totSize.Cmp(lenSize) > 0 { - // Calculate the diff between the sizes - diff := new(big.Int).Sub(totSize, lenSize) - // Create a new empty slice and append it - newSlice := make([]byte, diff.Int64()+1) - mem = append(mem, newSlice...) - } - // Copy over the returned values to the memory given the offset and size - copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() - ret := mem[offset.Int64() : offset.Int64()+size.Int64()+1] + ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret) } @@ -141,6 +116,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } +/* // Old VM code func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { vm.mem = make(map[string]*big.Int) @@ -507,6 +483,7 @@ out: state.UpdateContract(addr, contract) } +*/ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 459cdc284f..9ff2827a0c 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -7,61 +7,70 @@ import ( // Op codes var OpCodes = map[string]byte{ - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "LE": 0x0b, - "GT": 0x0c, - "GE": 0x0d, - "EQ": 0x0e, - "NOT": 0x0f, - "MYADDRESS": 0x10, - "TXSENDER": 0x11, - "TXVALUE": 0x12, - "TXDATAN": 0x13, - "TXDATA": 0x14, - "BLK_PREVHASH": 0x15, - "BLK_COINBASE": 0x16, - "BLK_TIMESTAMP": 0x17, - "BLK_NUMBER": 0x18, - "BLK_DIFFICULTY": 0x19, - "BLK_NONCE": 0x1a, - "BASEFEE": 0x1b, - "SHA256": 0x20, - "RIPEMD160": 0x21, - "ECMUL": 0x22, - "ECADD": 0x23, - "ECSIGN": 0x24, - "ECRECOVER": 0x25, - "ECVALID": 0x26, - "SHA3": 0x27, - "PUSH": 0x30, - "POP": 0x31, - "DUP": 0x32, - "SWAP": 0x33, - "MLOAD": 0x34, - "MSTORE": 0x35, - "SLOAD": 0x36, - "SSTORE": 0x37, - "JMP": 0x38, - "JMPI": 0x39, - "IND": 0x3a, - "EXTRO": 0x3b, - "BALANCE": 0x3c, - "MKTX": 0x3d, - "SUICIDE": 0x3f, + // 0x0 range - arithmetic ops + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "GT": 0x0b, + "EQ": 0x0c, + "NOT": 0x0d, - // TODO FIX OPCODES - "CALL": 0x40, - "RETURN": 0x41, + // 0x10 range - bit ops + "AND": 0x10, + "OR": 0x11, + "XOR": 0x12, + "BYTE": 0x13, + + // 0x20 range - crypto + "SHA3": 0x20, + + // 0x30 range - closure state + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "RETURNDATASIZE": 0x37, + "TXGASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "PREVNONCE": 0x41, + "COINBASE": 0x42, + "TIMESTAMP": 0x43, + "NUMBER": 0x44, + "DIFFICULTY": 0x45, + "GASLIMIT": 0x46, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MEMSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, } func IsOpCode(s string) bool { From 7705b23f248156878d00c301fbbadafedaf7e3d2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 23:17:53 +0100 Subject: [PATCH 0174/1237] Removed caller from tx and added "callership" to account. Transactions can no longer serve as callers. Accounts are now the initial callee of closures. Transactions now serve as transport to call closures. --- ethchain/address.go | 24 ++++++++++++++++-------- ethchain/block.go | 2 +- ethchain/closure.go | 4 ++-- ethchain/state.go | 4 ++-- ethchain/transaction.go | 9 --------- ethchain/vm.go | 4 ++++ ethchain/vm_test.go | 13 ++++++------- 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/ethchain/address.go b/ethchain/address.go index f1f27a1a5a..9c6acbe087 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -6,19 +6,20 @@ import ( ) type Account struct { - Amount *big.Int - Nonce uint64 + Address []byte + Amount *big.Int + Nonce uint64 } -func NewAccount(amount *big.Int) *Account { - return &Account{Amount: amount, Nonce: 0} +func NewAccount(address []byte, amount *big.Int) *Account { + return &Account{address, amount, 0} } -func NewAccountFromData(data []byte) *Account { - address := &Account{} - address.RlpDecode(data) +func NewAccountFromData(address, data []byte) *Account { + account := &Account{Address: address} + account.RlpDecode(data) - return address + return account } func (a *Account) AddFee(fee *big.Int) { @@ -29,6 +30,13 @@ func (a *Account) AddFunds(funds *big.Int) { a.Amount.Add(a.Amount, funds) } +// Implements Callee +func (a *Account) ReturnGas(value *big.Int, state *State) { + // Return the value back to the sender + a.AddFunds(value) + state.UpdateAccount(a.Address, a) +} + func (a *Account) RlpEncode() []byte { return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) } diff --git a/ethchain/block.go b/ethchain/block.go index 20af73ba26..1f63c2c9e0 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAccountFromData([]byte(data)) + ether := NewAccountFromData(block.Coinbase, []byte(data)) base = new(big.Int) ether.Amount = base.Add(ether.Amount, fee) diff --git a/ethchain/closure.go b/ethchain/closure.go index 204fbce060..9453ce22cb 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -26,7 +26,7 @@ type Closure struct { gas *big.Int val *big.Int - args []byte + Args []byte } // Create a new closure for the given data items @@ -45,7 +45,7 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { } func (c *Closure) Call(vm *Vm, args []byte) []byte { - c.args = args + c.Args = args return vm.RunClosure(c) } diff --git a/ethchain/state.go b/ethchain/state.go index b84d60c6ca..b6750d62d2 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -86,9 +86,9 @@ func (s *State) UpdateContract(addr []byte, contract *Contract) { func (s *State) GetAccount(addr []byte) (account *Account) { data := s.trie.Get(string(addr)) if data == "" { - account = NewAccount(big.NewInt(0)) + account = NewAccount(addr, big.NewInt(0)) } else { - account = NewAccountFromData([]byte(data)) + account = NewAccountFromData(addr, []byte(data)) } return diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 07e7ea970e..57df9cdc4d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -29,15 +29,6 @@ func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { return &tx } -// Implements Callee -func (tx *Transaction) ReturnGas(value *big.Int, state *State) { - // Return the value back to the sender - sender := tx.Sender() - account := state.GetAccount(sender) - account.AddFunds(value) - state.UpdateAccount(sender, account) -} - // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) diff --git a/ethchain/vm.go b/ethchain/vm.go index 6479409f87..3d85e2c09c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -87,6 +87,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + case oCALLDATA: + offset := stack.Pop() + mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 654ddb5663..30c8a110e3 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -133,10 +133,10 @@ func TestRun3(t *testing.T) { state.UpdateContract(addr, contract) callerScript := Compile([]string{ - "PUSH", "62", // REND - "PUSH", "0", // RSTART - "PUSH", "22", // MEND - "PUSH", "15", // MSTART + "PUSH", "62", // ret size + "PUSH", "0", // ret offset + "PUSH", "32", // arg size + "PUSH", "63", // arg offset "PUSH", "1000", /// Gas "PUSH", "0", /// value "PUSH", string(addr), // Sender @@ -144,10 +144,9 @@ func TestRun3(t *testing.T) { }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) callerAddr := callerTx.Hash()[12:] - executer := NewTransaction(ContractAddr, ethutil.Big("10000"), nil) - executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) - callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + account := NewAccount(ContractAddr, big.NewInt(10000000)) + callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ address: callerAddr, From f567f89b994bf28f908410223084a6702d05d156 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 20 Mar 2014 23:38:16 +0100 Subject: [PATCH 0175/1237] Added address to account and contract Contract and account now both have an address field or method for the sake of simplicity. --- ethchain/closure.go | 1 + ethchain/contract.go | 38 +++++++++++++++++++++++++------------- ethchain/state.go | 7 ++++--- ethchain/vm.go | 7 +++---- ethchain/vm_test.go | 11 +++++------ 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 9453ce22cb..0eef866d0b 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -15,6 +15,7 @@ type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value + Address() []byte } // Basic inline closure object which implement the 'closure' interface diff --git a/ethchain/contract.go b/ethchain/contract.go index 10c5e2df67..93d2b68ba3 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -9,26 +9,22 @@ type Contract struct { Amount *big.Int Nonce uint64 //state *ethutil.Trie - state *State + state *State + address []byte } -func NewContract(Amount *big.Int, root []byte) *Contract { - contract := &Contract{Amount: Amount, Nonce: 0} +func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { + contract := &Contract{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) return contract } -func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) -} +func NewContractFromBytes(address, data []byte) *Contract { + contract := &Contract{address: address} + contract.RlpDecode(data) -func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + return contract } func (c *Contract) Addr(addr []byte) *ethutil.Value { @@ -54,13 +50,29 @@ func (c *Contract) ReturnGas(val *big.Int, state *State) { c.Amount.Add(c.Amount, val) } +func (c *Contract) Address() []byte { + return c.address +} + +func (c *Contract) RlpEncode() []byte { + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) +} + +func (c *Contract) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) +} + func MakeContract(tx *Transaction, state *State) *Contract { // Create contract if there's no recipient if tx.IsContract() { addr := tx.Hash()[12:] value := tx.Value - contract := NewContract(value, []byte("")) + contract := NewContract(addr, value, []byte("")) state.trie.Update(string(addr), string(contract.RlpEncode())) for i, val := range tx.Data { if len(val) > 0 { diff --git a/ethchain/state.go b/ethchain/state.go index b6750d62d2..c9b35da21e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -63,8 +63,7 @@ func (s *State) GetContract(addr []byte) *Contract { } // build contract - contract := &Contract{} - contract.RlpDecode([]byte(data)) + contract := NewContractFromBytes(addr, []byte(data)) // Check if there's a cached state for this contract cachedState := s.states[string(addr)] @@ -78,7 +77,9 @@ func (s *State) GetContract(addr []byte) *Contract { return contract } -func (s *State) UpdateContract(addr []byte, contract *Contract) { +func (s *State) UpdateContract(contract *Contract) { + addr := contract.Address() + s.states[string(addr)] = contract.state s.trie.Update(string(addr), string(contract.RlpEncode())) } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d85e2c09c..ba19231cc0 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -23,14 +23,12 @@ type Vm struct { } type RuntimeVars struct { - address []byte + origin []byte blockNumber uint64 - sender []byte prevHash []byte coinbase []byte time int64 diff *big.Int - txValue *big.Int txData []string } @@ -108,6 +106,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, nil) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: size, offset := stack.Popn() @@ -501,7 +500,7 @@ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, tx := NewTransaction(addr, value, dataItems) if tx.IsContract() { contract := MakeContract(tx, state) - state.UpdateContract(tx.Hash()[12:], contract) + state.UpdateContract(contract) } else { account := state.GetAccount(tx.Recipient) account.Amount.Add(account.Amount, tx.Value) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 30c8a110e3..1dca5cfb7c 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -130,7 +130,7 @@ func TestRun3(t *testing.T) { addr := tx.Hash()[12:] fmt.Printf("addr contract %x\n", addr) contract := MakeContract(tx, state) - state.UpdateContract(addr, contract) + state.UpdateContract(contract) callerScript := Compile([]string{ "PUSH", "62", // ret size @@ -143,21 +143,20 @@ func TestRun3(t *testing.T) { "CALL", }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) - callerAddr := callerTx.Hash()[12:] + // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - address: callerAddr, + origin: account.Address, blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), time: 1, diff: big.NewInt(256), - txValue: big.NewInt(10000), - txData: nil, + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, }) callerClosure.Call(vm, nil) } From 9cf8ce9ef82bfb37fea92bbea6a8d326af00adc8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 00:04:31 +0100 Subject: [PATCH 0176/1237] New tx methods and added new vm to state manager --- ethchain/state_manager.go | 16 +++++++--------- ethchain/transaction.go | 21 +++++++++++++++------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 14686b217f..50c7773497 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -305,19 +305,17 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo } }() */ - - /*TODO to be fixed and replaced by the new vm - vm := &Vm{} - vm.Process(contract, sm.procState, RuntimeVars{ - address: tx.Hash()[12:], + caller := sm.procState.GetAccount(tx.Sender()) + closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) + vm := NewVm(sm.procState, RuntimeVars{ + origin: caller.Address, blockNumber: block.BlockInfo().Number, - sender: tx.Sender(), prevHash: block.PrevHash, coinbase: block.Coinbase, time: block.Time, diff: block.Difficulty, - txValue: tx.Value, - txData: tx.Data, + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, }) - */ + closure.Call(vm, nil) } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 57df9cdc4d..3b07c81d45 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,22 +13,31 @@ type Transaction struct { Nonce uint64 Recipient []byte Value *big.Int + Gas *big.Int + Gasprice *big.Int Data []string - Memory []int v byte r, s []byte } func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { - tx := Transaction{Recipient: to, Value: value} - tx.Nonce = 0 - - // Serialize the data - tx.Data = data + tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} return &tx } +func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { + return &Transaction{Value: value, Gasprice: gasprice, Data: data} +} + +func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { + return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} +} + +func NewTx(to []byte, value *big.Int, data []string) *Transaction { + return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} +} + // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) From fa1db8d2dcbc12fd9b343e6572c541d92fe7cb55 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 11:54:36 +0100 Subject: [PATCH 0177/1237] Implemented closure arguments --- ethchain/stack.go | 28 +++++-- ethchain/vm.go | 184 +++++++++++++++++++++++++++++++++++++++++--- ethchain/vm_test.go | 29 +++++-- ethutil/parsing.go | 6 +- 4 files changed, 225 insertions(+), 22 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 429c31d082..c75d02ddac 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -68,12 +68,16 @@ const ( oJUMP = 0x59 oJUMPI = 0x5a oPC = 0x5b - oMEMSIZE = 0x5c + oMSIZE = 0x5c // 0x60 range - closures oCREATE = 0x60 oCALL = 0x61 oRETURN = 0x62 + + // 0x70 range - other + oLOG = 0x70 // XXX Unofficial + oSUICIDE = 0x7f ) // Since the opcodes aren't all in order we can't use a regular slice @@ -136,12 +140,16 @@ var opCodeToString = map[OpCode]string{ oJUMP: "JUMP", oJUMPI: "JUMPI", oPC: "PC", - oMEMSIZE: "MEMSIZE", + oMSIZE: "MSIZE", // 0x60 range - closures oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", + + // 0x70 range - other + oLOG: "LOG", + oSUICIDE: "SUICIDE", } func (o OpCode) String() string { @@ -215,20 +223,30 @@ type Memory struct { func (m *Memory) Set(offset, size int64, value []byte) { totSize := offset + size - lenSize := int64(len(m.store)) + lenSize := int64(len(m.store) - 1) if totSize > lenSize { // Calculate the diff between the sizes diff := totSize - lenSize if diff > 0 { // Create a new empty slice and append it - newSlice := make([]byte, diff+1) + newSlice := make([]byte, diff-1) // Resize slice m.store = append(m.store, newSlice...) } } - copy(m.store[offset:offset+size+1], value) + copy(m.store[offset:offset+size], value) } func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } + +func (m *Memory) Print() { + fmt.Println("### MEM ###") + if len(m.store) > 0 { + fmt.Println(m.store) + } else { + fmt.Println("-- empty --") + } + fmt.Println("###########") +} diff --git a/ethchain/vm.go b/ethchain/vm.go index ba19231cc0..3d2ee4c860 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - "fmt" + _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" "log" @@ -36,6 +36,8 @@ func NewVm(state *State, vars RuntimeVars) *Vm { return &Vm{vars: vars, state: state} } +var Pow256 = ethutil.BigPow(2, 256) + func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { @@ -48,9 +50,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack := NewStack() // Instruction pointer pc := int64(0) - // Current address - //addr := vars.address + // Current step count step := 0 + // The base for all big integer arithmetic + base := new(big.Int) if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") @@ -75,27 +78,171 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } switch op { + case oLOG: + stack.Print() + mem.Print() case oSTOP: // Stop the closure return closure.Return(nil) + + // 0x20 range + case oADD: + x, y := stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oSUB: + x, y := stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oMUL: + x, y := stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + stack.Push(base) + case oDIV: + x, y := stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + stack.Push(base) + case oSDIV: + x, y := stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Div(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + stack.Push(z) + case oMOD: + x, y := stack.Popn() + base.Mod(x, y) + stack.Push(base) + case oSMOD: + x, y := stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Mod(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + stack.Push(z) + case oEXP: + x, y := stack.Popn() + base.Exp(x, y, Pow256) + + stack.Push(base) + case oNEG: + base.Sub(Pow256, stack.Pop()) + stack.Push(base) + case oLT: + x, y := stack.Popn() + // x < y + if x.Cmp(y) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oGT: + x, y := stack.Popn() + // x > y + if x.Cmp(y) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oNOT: + x, y := stack.Popn() + // x != y + if x.Cmp(y) != 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + // 0x10 range + case oAND: + case oOR: + case oXOR: + case oBYTE: + + // 0x20 range + case oSHA3: + + // 0x30 range + case oADDRESS: + case oBALANCE: + case oORIGIN: + case oCALLER: + case oCALLVALUE: + case oCALLDATA: + offset := stack.Pop() + mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + case oCALLDATASIZE: + case oRETURNDATASIZE: + case oTXGASPRICE: + + // 0x40 range + case oPREVHASH: + case oPREVNONCE: + case oCOINBASE: + case oTIMESTAMP: + case oNUMBER: + case oDIFFICULTY: + case oGASLIMIT: + + // 0x50 range case oPUSH: // Push PC+1 on to the stack pc++ val := closure.GetMem(pc).BigInt() stack.Push(val) + case oPOP: + case oDUP: + case oSWAP: + case oMLOAD: + offset := stack.Pop() + stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) case oMSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + case oMSTORE8: + case oSLOAD: + case oSSTORE: + case oJUMP: + case oJUMPI: + case oPC: + case oMSIZE: - case oCALLDATA: - offset := stack.Pop() - mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + // 0x60 range case oCALL: // Pop return size and offset retSize, retOffset := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() - // TODO remove me. - fmt.Sprintln(inSize, inOffset) + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) // Pop gas and value of the stack. gas, value := stack.Popn() // Closure addr @@ -105,7 +252,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Create a new callable closure closure := NewClosure(closure, contract, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, nil) + ret := closure.Call(vm, args) mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: @@ -113,6 +260,25 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret) + case oSUICIDE: + /* + recAddr := stack.Pop().Bytes() + // Purge all memory + deletedMemory := contract.state.Purge() + // Add refunds to the pop'ed address + refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) + account := state.GetAccount(recAddr) + account.Amount.Add(account.Amount, refund) + // Update the refunding address + state.UpdateAccount(recAddr, account) + // Delete the contract + state.trie.Update(string(addr), "") + + ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) + break out + */ + default: + ethutil.Config.Log.Debugln("Invalid opcode", op) } pc++ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 1dca5cfb7c..ce8c7a4de3 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -119,11 +120,13 @@ func TestRun3(t *testing.T) { "PUSH", "300", "PUSH", "0", "MSTORE", - "PUSH", "300", - "PUSH", "31", - "MSTORE", - "PUSH", "62", + + "PUSH", "32", + "CALLDATA", + + "PUSH", "64", "PUSH", "0", + "LOG", "RETURN", }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) @@ -133,14 +136,21 @@ func TestRun3(t *testing.T) { state.UpdateContract(contract) callerScript := Compile([]string{ - "PUSH", "62", // ret size + "PUSH", "1337", // Argument + "PUSH", "65", // argument mem offset + "MSTORE", + "PUSH", "64", // ret size "PUSH", "0", // ret offset + "PUSH", "32", // arg size - "PUSH", "63", // arg offset + "PUSH", "65", // arg offset "PUSH", "1000", /// Gas "PUSH", "0", /// value "PUSH", string(addr), // Sender "CALL", + "PUSH", "64", + "PUSH", "0", + "RETURN", }) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) @@ -158,5 +168,10 @@ func TestRun3(t *testing.T) { // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - callerClosure.Call(vm, nil) + ret := callerClosure.Call(vm, nil) + + exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57} + if bytes.Compare(ret, exp) != 0 { + t.Errorf("expected return value to be %v, got %v", exp, ret) + } } diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 9ff2827a0c..b2e9d9fee7 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -65,12 +65,16 @@ var OpCodes = map[string]byte{ "JUMP": 0x59, "JUMPI": 0x5a, "PC": 0x5b, - "MEMSIZE": 0x5c, + "MSIZE": 0x5c, // 0x60 range - closures "CREATE": 0x60, "CALL": 0x61, "RETURN": 0x62, + + // 0x70 range - other + "LOG": 0x70, + "SUICIDE": 0x7f, } func IsOpCode(s string) bool { From 2ea4c632d1673b762c1af11582364d9faa08c413 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 14:47:55 +0100 Subject: [PATCH 0178/1237] Closure return, arguments fixed. Added proper tests --- ethchain/address.go | 10 +++++--- ethchain/closure.go | 24 ++++++++++++------ ethchain/stack.go | 52 +++++++++++++++++++-------------------- ethchain/state_manager.go | 2 +- ethchain/vm.go | 33 +++++++++++++++++++++---- ethchain/vm_test.go | 3 +-- ethutil/parsing.go | 28 ++++++++++----------- 7 files changed, 92 insertions(+), 60 deletions(-) diff --git a/ethchain/address.go b/ethchain/address.go index 9c6acbe087..0b3ef7c057 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -6,7 +6,7 @@ import ( ) type Account struct { - Address []byte + address []byte Amount *big.Int Nonce uint64 } @@ -16,7 +16,7 @@ func NewAccount(address []byte, amount *big.Int) *Account { } func NewAccountFromData(address, data []byte) *Account { - account := &Account{Address: address} + account := &Account{address: address} account.RlpDecode(data) return account @@ -30,11 +30,15 @@ func (a *Account) AddFunds(funds *big.Int) { a.Amount.Add(a.Amount, funds) } +func (a *Account) Address() []byte { + return a.address +} + // Implements Callee func (a *Account) ReturnGas(value *big.Int, state *State) { // Return the value back to the sender a.AddFunds(value) - state.UpdateAccount(a.Address, a) + state.UpdateAccount(a.address, a) } func (a *Account) RlpEncode() []byte { diff --git a/ethchain/closure.go b/ethchain/closure.go index 0eef866d0b..f8e692f61c 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -9,13 +9,13 @@ import ( type Callee interface { ReturnGas(*big.Int, *State) + Address() []byte } type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value - Address() []byte } // Basic inline closure object which implement the 'closure' interface @@ -24,8 +24,8 @@ type Closure struct { object ClosureBody State *State - gas *big.Int - val *big.Int + Gas *big.Int + Value *big.Int Args []byte } @@ -45,6 +45,10 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) Address() []byte { + return c.object.Address() +} + func (c *Closure) Call(vm *Vm, args []byte) []byte { c.Args = args @@ -56,9 +60,9 @@ func (c *Closure) Return(ret []byte) []byte { // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.gas, c.State) + c.callee.ReturnGas(c.Gas, c.State) } else { - c.object.ReturnGas(c.gas, c.State) + c.object.ReturnGas(c.Gas, c.State) // TODO incase it's a POST contract we gotta serialise the contract again. // But it's not yet defined } @@ -69,9 +73,13 @@ func (c *Closure) Return(ret []byte) []byte { // Implement the Callee interface func (c *Closure) ReturnGas(gas *big.Int, state *State) { // Return the gas to the closure - c.gas.Add(c.gas, gas) + c.Gas.Add(c.Gas, gas) } -func (c *Closure) GetGas() *big.Int { - return c.gas +func (c *Closure) Object() ClosureBody { + return c.object +} + +func (c *Closure) Callee() Callee { + return c.callee } diff --git a/ethchain/stack.go b/ethchain/stack.go index c75d02ddac..b64b759fda 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -36,24 +36,22 @@ const ( oSHA3 = 0x20 // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATA = 0x35 - oCALLDATASIZE = 0x36 - oRETURNDATASIZE = 0x37 - oTXGASPRICE = 0x38 + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oGASPRICE = 0x37 // 0x40 range - block operations oPREVHASH = 0x40 - oPREVNONCE = 0x41 - oCOINBASE = 0x42 - oTIMESTAMP = 0x43 - oNUMBER = 0x44 - oDIFFICULTY = 0x45 - oGASLIMIT = 0x46 + oCOINBASE = 0x41 + oTIMESTAMP = 0x42 + oNUMBER = 0x43 + oDIFFICULTY = 0x44 + oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution oPUSH = 0x50 @@ -108,19 +106,17 @@ var opCodeToString = map[OpCode]string{ oSHA3: "SHA3", // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", - oCALLDATASIZE: "CALLDATASIZE", - oRETURNDATASIZE: "RETURNDATASIZE", - oTXGASPRICE: "TXGASPRICE", + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oGASPRICE: "TXGASPRICE", // 0x40 range - block operations oPREVHASH: "PREVHASH", - oPREVNONCE: "PREVNONCE", oCOINBASE: "COINBASE", oTIMESTAMP: "TIMESTAMP", oNUMBER: "NUMBER", @@ -244,7 +240,11 @@ func (m *Memory) Get(offset, size int64) []byte { func (m *Memory) Print() { fmt.Println("### MEM ###") if len(m.store) > 0 { - fmt.Println(m.store) + addr := 0 + for i := 0; i+32 < len(m.store); i += 32 { + fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) + addr++ + } } else { fmt.Println("-- empty --") } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 50c7773497..3b55077405 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -308,7 +308,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ - origin: caller.Address, + origin: caller.Address(), blockNumber: block.BlockInfo().Number, prevHash: block.PrevHash, coinbase: block.Coinbase, diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d2ee4c860..8b5bb93c0c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -40,7 +40,7 @@ var Pow256 = ethutil.BigPow(2, 256) func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 - if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { + if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something } @@ -73,7 +73,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { fee := new(big.Int) fee.Add(fee, big.NewInt(1000)) - if closure.GetGas().Cmp(fee) < 0 { + if closure.Gas.Cmp(fee) < 0 { return closure.Return(nil) } @@ -192,25 +192,37 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x30 range case oADDRESS: + stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: + stack.Push(closure.Value) case oORIGIN: + stack.Push(ethutil.BigD(vm.vars.origin)) case oCALLER: + stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: + // FIXME: Original value of the call, not the current value + stack.Push(closure.Value) case oCALLDATA: offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: - case oRETURNDATASIZE: - case oTXGASPRICE: + stack.Push(big.NewInt(int64(len(closure.Args)))) + case oGASPRICE: + // TODO // 0x40 range case oPREVHASH: - case oPREVNONCE: + stack.Push(ethutil.BigD(vm.vars.prevHash)) case oCOINBASE: + stack.Push(ethutil.BigD(vm.vars.coinbase)) case oTIMESTAMP: + stack.Push(big.NewInt(vm.vars.time)) case oNUMBER: + stack.Push(big.NewInt(int64(vm.vars.blockNumber))) case oDIFFICULTY: + stack.Push(vm.vars.diff) case oGASLIMIT: + // TODO // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -218,8 +230,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val := closure.GetMem(pc).BigInt() stack.Push(val) case oPOP: + stack.Pop() case oDUP: + stack.Push(stack.Peek()) case oSWAP: + x, y := stack.Popn() + stack.Push(y) + stack.Push(x) case oMLOAD: offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) @@ -228,7 +245,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + val, mStart := stack.Popn() + base.And(val, new(big.Int).SetInt64(0xff)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + loc := stack.Pop() + val := closure.GetMem(loc.Int64()) + stack.Push(val.BigInt()) case oSSTORE: case oJUMP: case oJUMPI: diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index ce8c7a4de3..16cbf51b7d 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -126,7 +126,6 @@ func TestRun3(t *testing.T) { "PUSH", "64", "PUSH", "0", - "LOG", "RETURN", }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) @@ -159,7 +158,7 @@ func TestRun3(t *testing.T) { callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - origin: account.Address, + origin: account.Address(), blockNumber: 1, prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), diff --git a/ethutil/parsing.go b/ethutil/parsing.go index b2e9d9fee7..f244026230 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -33,24 +33,22 @@ var OpCodes = map[string]byte{ "SHA3": 0x20, // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATA": 0x35, - "CALLDATASIZE": 0x36, - "RETURNDATASIZE": 0x37, - "TXGASPRICE": 0x38, + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, // 0x40 range - block operations "PREVHASH": 0x40, - "PREVNONCE": 0x41, - "COINBASE": 0x42, - "TIMESTAMP": 0x43, - "NUMBER": 0x44, - "DIFFICULTY": 0x45, - "GASLIMIT": 0x46, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution "PUSH": 0x50, From b52b1fca89fd56549ecc0f086d96a39d6009e568 Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 21 Mar 2014 15:06:23 +0100 Subject: [PATCH 0179/1237] Initial block reorganisation code --- ethchain/block_chain.go | 97 ++++++++++++++++++++++++++++++ ethchain/state_manager.go | 4 +- ethminer/miner.go | 19 +++--- peer.go | 121 +++++++++++++++++++++++++++++++------- 4 files changed, 210 insertions(+), 31 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 90ad4516a0..6eea146528 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" "log" "math" "math/big" @@ -24,6 +25,7 @@ type BlockChain struct { func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + bc.Ethereum = ethereum bc.setLastBlock() @@ -77,6 +79,101 @@ func (bc *BlockChain) HasBlock(hash []byte) bool { return len(data) != 0 } +// TODO: At one point we might want to save a block by prevHash in the db to optimise this... +func (bc *BlockChain) HasBlockWithPrevHash(hash []byte) bool { + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(hash, block.PrevHash) == 0 { + return true + } + } + return false +} + +func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { + blockDiff := new(big.Int) + + for _, uncle := range block.Uncles { + blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) + } + blockDiff = blockDiff.Add(blockDiff, block.Difficulty) + + return blockDiff +} + +// Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one +func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) { + // 1. Calculate TD of the current chain + // 2. Calculate TD of the new chain + // Reset state to the correct one + + chainDifficulty := new(big.Int) + + // Calculate the entire chain until the block we both have + // Start with the newest block we got, all the way back to the common block we both know + for i := 0; i < (msg.Data.Len() - 1); i++ { + block := NewBlockFromRlpValue(msg.Data.Get(i)) + if bytes.Compare(block.Hash(), commonBlockHash) == 0 { + log.Println("[BCHAIN] We have found the common parent block, breaking") + break + } + chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) + } + + log.Println("[BCHAIN] Incoming chain difficulty:", chainDifficulty) + + curChainDifficulty := new(big.Int) + block := bc.CurrentBlock + + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(block.Hash(), commonBlockHash) == 0 { + log.Println("[BCHAIN] We have found the common parent block, breaking") + break + } + curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) + } + + log.Println("[BCHAIN] Current chain difficulty:", curChainDifficulty) + if chainDifficulty.Cmp(curChainDifficulty) == 1 { + log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") + bc.ResetTillBlockHash(commonBlockHash) + } else { + log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + } +} +func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { + lastBlock := bc.CurrentBlock + returnTo := bc.GetBlock(hash) + + // TODO: REFACTOR TO FUNCTION, Used multiple times + bc.CurrentBlock = returnTo + bc.LastBlockHash = returnTo.Hash() + info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = info.Number + // END TODO + + bc.Ethereum.StateManager().PrepareDefault(returnTo) + err := ethutil.Config.Db.Delete(lastBlock.Hash()) + if err != nil { + return err + } + + var block *Block + for ; block != nil; block = bc.GetBlock(block.PrevHash) { + if bytes.Compare(block.Hash(), hash) == 0 { + log.Println("[CHAIN] We have arrived at the the common parent block, breaking") + break + } + err = ethutil.Config.Db.Delete(block.Hash()) + if err != nil { + return err + } + } + log.Println("[CHAIN] Split chain deleted and reverted to common parent block.") + return nil +} + func (bc *BlockChain) GenesisBlock() *Block { return bc.genesisBlock } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 46d8228d9c..9118db211e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -201,7 +201,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { return nil } - func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { @@ -215,6 +214,9 @@ func (sm *StateManager) CalculateTD(block *Block) bool { // The new TD will only be accepted if the new difficulty is // is greater than the previous. + fmt.Println("new block td:", td) + fmt.Println("cur block td:", sm.bc.TD) + if td.Cmp(sm.bc.TD) > 0 { // Set the new total difficulty back to the block chain sm.bc.SetTotalDifficulty(td) diff --git a/ethminer/miner.go b/ethminer/miner.go index f4f697abaa..cb752e3dec 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -61,10 +61,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - log.Println("[miner] Got new block via Reactor") + log.Println("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - log.Println("[miner] New top block found resetting state") + log.Println("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -86,7 +86,7 @@ func (miner *Miner) listener() { } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { - log.Println("[miner] Adding uncle block") + log.Println("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } @@ -94,7 +94,7 @@ func (miner *Miner) listener() { } if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { - log.Println("[miner] Got new transaction from Reactor", tx) + log.Println("[MINER] Got new transaction from Reactor", tx) found := false for _, ctx := range miner.txs { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { @@ -103,15 +103,15 @@ func (miner *Miner) listener() { } if found == false { - log.Println("[miner] We did not know about this transaction, adding") + log.Println("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) miner.block.SetTransactions(miner.txs) } else { - log.Println("[miner] We already had this transaction, ignoring") + log.Println("[MINER] We already had this transaction, ignoring") } } default: - log.Println("[miner] Mining on block. Includes", len(miner.txs), "transactions") + log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions") // Apply uncles if len(miner.uncles) > 0 { @@ -123,7 +123,7 @@ func (miner *Miner) listener() { miner.ethereum.StateManager().AccumelateRewards(miner.block) // Search the nonce - log.Println("[miner] Initialision complete, starting mining") + log.Println("[MINER] Initialision complete, starting mining") miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) if miner.block.Nonce != nil { miner.ethereum.StateManager().PrepareDefault(miner.block) @@ -137,8 +137,7 @@ func (miner *Miner) listener() { log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) } miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) - log.Printf("[miner] 🔨 Mined block %x\n", miner.block.Hash()) - log.Println(miner.block) + log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) diff --git a/peer.go b/peer.go index 6b914710d7..2cc9404006 100644 --- a/peer.go +++ b/peer.go @@ -126,7 +126,8 @@ type Peer struct { pubkey []byte // Indicated whether the node is catching up or not - catchingUp bool + catchingUp bool + blocksRequested int Version string } @@ -136,15 +137,16 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() return &Peer{ - outputQueue: make(chan *ethwire.Msg, outputBufferSize), - quit: make(chan bool), - ethereum: ethereum, - conn: conn, - inbound: inbound, - disconnect: 0, - connected: 1, - port: 30303, - pubkey: pubkey, + outputQueue: make(chan *ethwire.Msg, outputBufferSize), + quit: make(chan bool), + ethereum: ethereum, + conn: conn, + inbound: inbound, + disconnect: 0, + connected: 1, + port: 30303, + pubkey: pubkey, + blocksRequested: 10, } } @@ -291,11 +293,62 @@ func (p *Peer) HandleInbound() { // Get all blocks and process them var block, lastBlock *ethchain.Block var err error + + // 1. Compare the first block over the wire's prev-hash with the hash of your last block + // 2. If these two values are the same you can just link the chains together. + // [1:0,2:1,3:2] <- Current blocks (format block:previous_block) + // [1:0,2:1,3:2,4:3,5:4] <- incoming blocks + // == [1,2,3,4,5] + // 3. If the values are not the same we will have to go back and calculate the chain with the highest total difficulty + // [1:0,2:1,3:2,11:3,12:11,13:12] + // [1:0,2:1,3:2,4:3,5:4,6:5] + + // [3:2,11:3,12:11,13:12] + // [3:2,4:3,5:4,6:5] + // Heb ik dit blok? + // Nee: heb ik een blok met PrevHash 3? + // Ja: DIVERSION + // Nee; Adding to chain + + // See if we can find a common ancestor + // 1. Get the earliest block in the package. + // 2. Do we have this block? + // 3. Yes: Let's continue what we are doing + // 4. No: Let's request more blocks back. + + if msg.Data.Len()-1 > 1 { + lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) + if p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { + fmt.Println("[PEER] We found a common ancestor, let's continue.") + } else { + fmt.Println("[PEER] No common ancestor found, requesting more blocks.") + p.blocksRequested = p.blocksRequested * 2 + p.catchingUp = false + p.SyncWithBlocks() + } + + for i := msg.Data.Len() - 1; i >= 0; i-- { + block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) + // Do we have this block on our chain? + if p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { + fmt.Println("[PEER] Block found, checking next one.") + } else { + // We don't have this block, but we do have a block with the same prevHash, diversion time! + if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { + fmt.Printf("[PEER] Local and foreign chain have diverted after %x, we are going to get freaky with it!\n", block.PrevHash) + p.ethereum.StateManager().BlockChain().FindCanonicalChain(msg, block.PrevHash) + } else { + fmt.Println("[PEER] Both local and foreign chain have same parent. Continue normally") + } + } + } + } + for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) p.ethereum.StateManager().PrepareDefault(block) - err = p.ethereum.StateManager().ProcessBlock(block, true) + err = p.ethereum.StateManager().ProcessBlock(block, false) if err != nil { if ethutil.Config.Debug { @@ -305,6 +358,7 @@ func (p *Peer) HandleInbound() { } break } else { + ethutil.Config.Log.Infof("[PEER] Block %x added\n", block.Hash()) lastBlock = block } } @@ -314,7 +368,7 @@ func (p *Peer) HandleInbound() { if ethchain.IsParentErr(err) { ethutil.Config.Log.Infoln("Attempting to catch up") p.catchingUp = false - p.CatchupWithPeer() + p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } else if ethchain.IsValidationErr(err) { // TODO } @@ -327,7 +381,7 @@ func (p *Peer) HandleInbound() { ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false - p.CatchupWithPeer() + p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } } case ethwire.MsgTxTy: @@ -374,11 +428,11 @@ func (p *Peer) HandleInbound() { // Amount of parents in the canonical chain //amountOfBlocks := msg.Data.Get(l).AsUint() amountOfBlocks := uint64(100) + // Check each SHA block hash from the message and determine whether // the SHA is in the database for i := 0; i < l; i++ { - if data := - msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) { + if data := msg.Data.Get(i).Bytes(); p.ethereum.StateManager().BlockChain().HasBlock(data) { parent = p.ethereum.BlockChain().GetBlock(data) break } @@ -386,9 +440,12 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { + ethutil.Config.Log.Infof("[PEER] Found conical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) + ethutil.Config.Log.Infof("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { + ethutil.Config.Log.Infof("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain lastHash := msg.Data.Get(l - 1) @@ -527,7 +584,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } // Catch up with the connected peer - p.CatchupWithPeer() + // p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) + p.SyncWithBlocks() // Set the peer's caps p.caps = Caps(c.Get(3).Byte()) @@ -554,14 +612,37 @@ func (p *Peer) String() string { return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) } - -func (p *Peer) CatchupWithPeer() { +func (p *Peer) SyncWithBlocks() { if !p.catchingUp { p.catchingUp = true - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{p.ethereum.BlockChain().CurrentBlock.Hash(), uint64(50)}) + // FIXME: THIS SHOULD NOT BE NEEDED + if p.blocksRequested == 0 { + p.blocksRequested = 10 + } + fmt.Printf("Currenb lock %x\n", p.ethereum.BlockChain().CurrentBlock.Hash()) + fmt.Println("Amount:", p.blocksRequested) + blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested) + + var hashes []interface{} + for _, block := range blocks { + hashes = append(hashes, block.Hash()) + } + fmt.Printf("Requesting hashes from network: %x", hashes) + + msgInfo := append(hashes, uint64(50)) + + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) + p.QueueMessage(msg) + } +} + +func (p *Peer) CatchupWithPeer(blockHash []byte) { + if !p.catchingUp { + p.catchingUp = true + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) + ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", blockHash[:4]) } } From 9a9e252cabdc6283d7f4e523860f0e4addf62152 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 15:27:18 +0100 Subject: [PATCH 0180/1237] Changes 'compiler' to work with any type --- ethchain/vm_test.go | 28 ++++++++++++-------------- ethutil/parsing.go | 48 +++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 16cbf51b7d..047531e09f 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -130,27 +129,26 @@ func TestRun3(t *testing.T) { }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) addr := tx.Hash()[12:] - fmt.Printf("addr contract %x\n", addr) contract := MakeContract(tx, state) state.UpdateContract(contract) - callerScript := Compile([]string{ - "PUSH", "1337", // Argument - "PUSH", "65", // argument mem offset + callerScript := ethutil.Compile( + "PUSH", 1337, // Argument + "PUSH", 65, // argument mem offset "MSTORE", - "PUSH", "64", // ret size - "PUSH", "0", // ret offset + "PUSH", 64, // ret size + "PUSH", 0, // ret offset - "PUSH", "32", // arg size - "PUSH", "65", // arg offset - "PUSH", "1000", /// Gas - "PUSH", "0", /// value - "PUSH", string(addr), // Sender + "PUSH", 32, // arg size + "PUSH", 65, // arg offset + "PUSH", 1000, /// Gas + "PUSH", 0, /// value + "PUSH", addr, // Sender "CALL", - "PUSH", "64", - "PUSH", "0", + "PUSH", 64, + "PUSH", 0, "RETURN", - }) + ) callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) // Contract addr as test address diff --git a/ethutil/parsing.go b/ethutil/parsing.go index f244026230..8929f08294 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -84,20 +84,30 @@ func IsOpCode(s string) bool { return false } -func CompileInstr(s string) ([]byte, error) { - isOp := IsOpCode(s) - if isOp { - return []byte{OpCodes[s]}, nil +func CompileInstr(s interface{}) ([]byte, error) { + switch s.(type) { + case string: + str := s.(string) + isOp := IsOpCode(str) + if isOp { + return []byte{OpCodes[str]}, nil + } + + num := new(big.Int) + _, success := num.SetString(str, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(str)) + } + + return num.Bytes(), nil + case int: + return big.NewInt(int64(s.(int))).Bytes(), nil + case []byte: + return BigD(s.([]byte)).Bytes(), nil } - num := new(big.Int) - _, success := num.SetString(s, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(s)) - } - - return num.Bytes(), nil + return nil, nil } func Instr(instr string) (int, []string, error) { @@ -118,3 +128,17 @@ func Instr(instr string) (int, []string, error) { return op, args[1:7], nil } + +// Script compilation functions +// Compiles strings to machine code +func Compile(instructions ...interface{}) (script []string) { + script = make([]string, len(instructions)) + + for i, val := range instructions { + instr, _ := CompileInstr(val) + + script[i] = string(instr) + } + + return +} From 01c1bce9c5dfa2b2bcdf934afec3f206823f895f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 18:22:47 +0100 Subject: [PATCH 0181/1237] Removed regular ints from the virtual machine and closures --- ethchain/closure.go | 9 +++++++-- ethchain/contract.go | 9 +++++++-- ethchain/stack.go | 4 ++++ ethchain/vm.go | 21 +++++++++++++++------ ethutil/common.go | 6 ++++++ 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index f8e692f61c..2e809aa9dc 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -15,7 +15,8 @@ type Callee interface { type ClosureBody interface { Callee ethutil.RlpEncodable - GetMem(int64) *ethutil.Value + GetMem(*big.Int) *ethutil.Value + SetMem(*big.Int, *ethutil.Value) } // Basic inline closure object which implement the 'closure' interface @@ -36,7 +37,7 @@ func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.I } // Retuns the x element in data slice -func (c *Closure) GetMem(x int64) *ethutil.Value { +func (c *Closure) GetMem(x *big.Int) *ethutil.Value { m := c.object.GetMem(x) if m == nil { return ethutil.EmptyValue() @@ -45,6 +46,10 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { + c.object.SetMem(x, val) +} + func (c *Closure) Address() []byte { return c.object.Address() } diff --git a/ethchain/contract.go b/ethchain/contract.go index 93d2b68ba3..f7ae017534 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -39,12 +39,17 @@ func (c *Contract) State() *State { return c.state } -func (c *Contract) GetMem(num int64) *ethutil.Value { - nb := ethutil.BigToBytes(big.NewInt(num), 256) +func (c *Contract) GetMem(num *big.Int) *ethutil.Value { + nb := ethutil.BigToBytes(num, 256) return c.Addr(nb) } +func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.state.trie.Update(string(addr), string(val.Encode())) +} + // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *Contract) ReturnGas(val *big.Int, state *State) { c.Amount.Add(c.Amount, val) diff --git a/ethchain/stack.go b/ethchain/stack.go index b64b759fda..3c2899e623 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -237,6 +237,10 @@ func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } +func (m *Memory) Len() int { + return len(m.store) +} + func (m *Memory) Print() { fmt.Println("### MEM ###") if len(m.store) > 0 { diff --git a/ethchain/vm.go b/ethchain/vm.go index 8b5bb93c0c..bc3a9edaff 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -49,7 +49,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // New stack (should this be shared?) stack := NewStack() // Instruction pointer - pc := int64(0) + pc := big.NewInt(0) // Current step count step := 0 // The base for all big integer arithmetic @@ -226,7 +226,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack - pc++ + pc.Add(pc, ethutil.Big1) + val := closure.GetMem(pc).BigInt() stack.Push(val) case oPOP: @@ -250,14 +251,22 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: loc := stack.Pop() - val := closure.GetMem(loc.Int64()) + val := closure.GetMem(loc) stack.Push(val.BigInt()) case oSSTORE: + val, loc := stack.Popn() + closure.SetMem(loc, ethutil.NewValue(val)) case oJUMP: + pc = stack.Pop() case oJUMPI: + pos, cond := stack.Popn() + if cond.Cmp(big.NewInt(0)) > 0 { + pc = pos + } case oPC: + stack.Push(pc) case oMSIZE: - + stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCALL: // Pop return size and offset @@ -304,7 +313,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { ethutil.Config.Log.Debugln("Invalid opcode", op) } - pc++ + pc.Add(pc, ethutil.Big1) } } @@ -682,7 +691,7 @@ func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, j := int64(0) dataItems := make([]string, int(length.Uint64())) for i := from.Int64(); i < length.Int64(); i++ { - dataItems[j] = contract.GetMem(j).Str() + dataItems[j] = contract.GetMem(big.NewInt(j)).Str() j++ } diff --git a/ethutil/common.go b/ethutil/common.go index 07df6bb138..f15b10e6da 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -33,3 +33,9 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Wei", num) } + +var ( + Big1 = big.NewInt(1) + Big0 = big.NewInt(0) + Big256 = big.NewInt(0xff) +) From 6a86c517c4f4b372cad0ae1d92e926a482eac5ba Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 22 Mar 2014 11:47:27 +0100 Subject: [PATCH 0182/1237] Removed old VM code --- README.md | 2 +- ethchain/state.go | 4 + ethchain/vm.go | 369 ---------------------------------------------- 3 files changed, 5 insertions(+), 370 deletions(-) diff --git a/README.md b/README.md index 3553a5e351..0f0a33edb0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 3". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 3.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethchain/state.go b/ethchain/state.go index c9b35da21e..1860647f2a 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -149,6 +149,10 @@ func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } +func (s *State) Root() interface{} { + return s.trie.Root +} + // Script compilation functions // Compiles strings to machine code func Compile(code []string) (script []string) { diff --git a/ethchain/vm.go b/ethchain/vm.go index bc3a9edaff..126592b25d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -317,375 +317,6 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } -/* -// Old VM code -func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { - vm.mem = make(map[string]*big.Int) - vm.stack = NewStack() - - addr := vars.address // tx.Hash()[12:] - // Instruction pointer - pc := int64(0) - - if contract == nil { - fmt.Println("Contract not found") - return - } - - Pow256 := ethutil.BigPow(2, 256) - - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } - - stepcount := 0 - totalFee := new(big.Int) - -out: - for { - stepcount++ - // The base big int for all calculations. Use this for any results. - base := new(big.Int) - val := contract.GetMem(pc) - //fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb) - op := OpCode(val.Uint()) - - var fee *big.Int = new(big.Int) - var fee2 *big.Int = new(big.Int) - if stepcount > 16 { - fee.Add(fee, StepFee) - } - - // Calculate the fees - switch op { - case oSSTORE: - y, x := vm.stack.Peekn() - val := contract.Addr(ethutil.BigToBytes(x, 256)) - if val.IsEmpty() && len(y.Bytes()) > 0 { - fee2.Add(DataFee, StoreFee) - } else { - fee2.Sub(DataFee, StoreFee) - } - case oSLOAD: - fee.Add(fee, StoreFee) - case oEXTRO, oBALANCE: - fee.Add(fee, ExtroFee) - case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: - fee.Add(fee, CryptoFee) - case oMKTX: - fee.Add(fee, ContractFee) - } - - tf := new(big.Int).Add(fee, fee2) - if contract.Amount.Cmp(tf) < 0 { - fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) - break - } - // Add the fee to the total fee. It's subtracted when we're done looping - totalFee.Add(totalFee, tf) - - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - - switch op { - case oSTOP: - fmt.Println("") - break out - case oADD: - x, y := vm.stack.Popn() - // (x + y) % 2 ** 256 - base.Add(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base) - case oSUB: - x, y := vm.stack.Popn() - // (x - y) % 2 ** 256 - base.Sub(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base) - case oMUL: - x, y := vm.stack.Popn() - // (x * y) % 2 ** 256 - base.Mul(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base) - case oDIV: - x, y := vm.stack.Popn() - // floor(x / y) - base.Div(x, y) - // Pop result back on the stack - vm.stack.Push(base) - case oSDIV: - x, y := vm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { - x.Sub(Pow256, x) - } - if y.Cmp(Pow256) > 0 { - y.Sub(Pow256, y) - } - z := new(big.Int) - z.Div(x, y) - if z.Cmp(Pow256) > 0 { - z.Sub(Pow256, z) - } - // Push result on to the stack - vm.stack.Push(z) - case oMOD: - x, y := vm.stack.Popn() - base.Mod(x, y) - vm.stack.Push(base) - case oSMOD: - x, y := vm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { - x.Sub(Pow256, x) - } - if y.Cmp(Pow256) > 0 { - y.Sub(Pow256, y) - } - z := new(big.Int) - z.Mod(x, y) - if z.Cmp(Pow256) > 0 { - z.Sub(Pow256, z) - } - // Push result on to the stack - vm.stack.Push(z) - case oEXP: - x, y := vm.stack.Popn() - base.Exp(x, y, Pow256) - - vm.stack.Push(base) - case oNEG: - base.Sub(Pow256, vm.stack.Pop()) - vm.stack.Push(base) - case oLT: - x, y := vm.stack.Popn() - // x < y - if x.Cmp(y) < 0 { - vm.stack.Push(ethutil.BigTrue) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oLE: - x, y := vm.stack.Popn() - // x <= y - if x.Cmp(y) < 1 { - vm.stack.Push(ethutil.BigTrue) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oGT: - x, y := vm.stack.Popn() - // x > y - if x.Cmp(y) > 0 { - vm.stack.Push(ethutil.BigTrue) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oGE: - x, y := vm.stack.Popn() - // x >= y - if x.Cmp(y) > -1 { - vm.stack.Push(ethutil.BigTrue) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oNOT: - x, y := vm.stack.Popn() - // x != y - if x.Cmp(y) != 0 { - vm.stack.Push(ethutil.BigTrue) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oMYADDRESS: - vm.stack.Push(ethutil.BigD(addr)) - case oTXSENDER: - vm.stack.Push(ethutil.BigD(vars.sender)) - case oTXVALUE: - vm.stack.Push(vars.txValue) - case oTXDATAN: - vm.stack.Push(big.NewInt(int64(len(vars.txData)))) - case oTXDATA: - v := vm.stack.Pop() - // v >= len(data) - if v.Cmp(big.NewInt(int64(len(vars.txData)))) >= 0 { - vm.stack.Push(ethutil.Big("0")) - } else { - vm.stack.Push(ethutil.Big(vars.txData[v.Uint64()])) - } - case oBLK_PREVHASH: - vm.stack.Push(ethutil.BigD(vars.prevHash)) - case oBLK_COINBASE: - vm.stack.Push(ethutil.BigD(vars.coinbase)) - case oBLK_TIMESTAMP: - vm.stack.Push(big.NewInt(vars.time)) - case oBLK_NUMBER: - vm.stack.Push(big.NewInt(int64(vars.blockNumber))) - case oBLK_DIFFICULTY: - vm.stack.Push(vars.diff) - case oBASEFEE: - // e = 10^21 - e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) - d := new(big.Rat) - d.SetInt(vars.diff) - c := new(big.Rat) - c.SetFloat64(0.5) - // d = diff / 0.5 - d.Quo(d, c) - // base = floor(d) - base.Div(d.Num(), d.Denom()) - - x := new(big.Int) - x.Div(e, base) - - // x = floor(10^21 / floor(diff^0.5)) - vm.stack.Push(x) - case oSHA256, oSHA3, oRIPEMD160: - // This is probably save - // ceil(pop / 32) - length := int(math.Ceil(float64(vm.stack.Pop().Uint64()) / 32.0)) - // New buffer which will contain the concatenated popped items - data := new(bytes.Buffer) - for i := 0; i < length; i++ { - // Encode the number to bytes and have it 32bytes long - num := ethutil.NumberToBytes(vm.stack.Pop().Bytes(), 256) - data.WriteString(string(num)) - } - - if op == oSHA256 { - vm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) - } else if op == oSHA3 { - vm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) - } else { - vm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) - } - case oECMUL: - y := vm.stack.Pop() - x := vm.stack.Pop() - //n := vm.stack.Pop() - - //if ethutil.Big(x).Cmp(ethutil.Big(y)) { - data := new(bytes.Buffer) - data.WriteString(x.String()) - data.WriteString(y.String()) - if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { - // TODO - } else { - // Invalid, push infinity - vm.stack.Push(ethutil.Big("0")) - vm.stack.Push(ethutil.Big("0")) - } - //} else { - // // Invalid, push infinity - // vm.stack.Push("0") - // vm.stack.Push("0") - //} - - case oECADD: - case oECSIGN: - case oECRECOVER: - case oECVALID: - case oPUSH: - pc++ - vm.stack.Push(contract.GetMem(pc).BigInt()) - case oPOP: - // Pop current value of the stack - vm.stack.Pop() - case oDUP: - // Dup top stack - x := vm.stack.Pop() - vm.stack.Push(x) - vm.stack.Push(x) - case oSWAP: - // Swap two top most values - x, y := vm.stack.Popn() - vm.stack.Push(y) - vm.stack.Push(x) - case oMLOAD: - x := vm.stack.Pop() - vm.stack.Push(vm.mem[x.String()]) - case oMSTORE: - x, y := vm.stack.Popn() - vm.mem[x.String()] = y - case oSLOAD: - // Load the value in storage and push it on the stack - x := vm.stack.Pop() - // decode the object as a big integer - decoder := contract.Addr(x.Bytes()) - if !decoder.IsNil() { - vm.stack.Push(decoder.BigInt()) - } else { - vm.stack.Push(ethutil.BigFalse) - } - case oSSTORE: - // Store Y at index X - y, x := vm.stack.Popn() - addr := ethutil.BigToBytes(x, 256) - fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) - contract.SetAddr(addr, y) - //contract.State().Update(string(idx), string(y)) - case oJMP: - x := vm.stack.Pop().Int64() - // Set pc to x - 1 (minus one so the incrementing at the end won't effect it) - pc = x - pc-- - case oJMPI: - x := vm.stack.Pop() - // Set pc to x if it's non zero - if x.Cmp(ethutil.BigFalse) != 0 { - pc = x.Int64() - pc-- - } - case oIND: - vm.stack.Push(big.NewInt(int64(pc))) - case oEXTRO: - memAddr := vm.stack.Pop() - contractAddr := vm.stack.Pop().Bytes() - - // Push the contract's memory on to the stack - vm.stack.Push(contractMemory(state, contractAddr, memAddr)) - case oBALANCE: - // Pushes the balance of the popped value on to the stack - account := state.GetAccount(vm.stack.Pop().Bytes()) - vm.stack.Push(account.Amount) - case oMKTX: - addr, value := vm.stack.Popn() - from, length := vm.stack.Popn() - - makeInlineTx(addr.Bytes(), value, from, length, contract, state) - case oSUICIDE: - recAddr := vm.stack.Pop().Bytes() - // Purge all memory - deletedMemory := contract.state.Purge() - // Add refunds to the pop'ed address - refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) - account := state.GetAccount(recAddr) - account.Amount.Add(account.Amount, refund) - // Update the refunding address - state.UpdateAccount(recAddr, account) - // Delete the contract - state.trie.Update(string(addr), "") - - ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) - break out - default: - fmt.Printf("Invalid OPCODE: %x\n", op) - } - ethutil.Config.Log.Debugln("") - //vm.stack.Print() - pc++ - } - - state.UpdateContract(addr, contract) -} -*/ - func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := int64(0) From 274d5cc91c45349ec8d7a1f5a20ef29896b38b2e Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 10:24:06 +0100 Subject: [PATCH 0183/1237] FindCanonicalChain returns true or false when we are on the Canonical chain or not --- ethchain/block_chain.go | 5 ++++- peer.go | 14 +++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6eea146528..f25f0ca5ae 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -103,7 +103,8 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { } // Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one -func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) { +// Return true if we are the using the canonical chain false if not +func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) bool { // 1. Calculate TD of the current chain // 2. Calculate TD of the new chain // Reset state to the correct one @@ -138,8 +139,10 @@ func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byt if chainDifficulty.Cmp(curChainDifficulty) == 1 { log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") bc.ResetTillBlockHash(commonBlockHash) + return false } else { log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + return true } } func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { diff --git a/peer.go b/peer.go index 2cc9404006..22bbe7a4c0 100644 --- a/peer.go +++ b/peer.go @@ -316,11 +316,18 @@ func (p *Peer) HandleInbound() { // 3. Yes: Let's continue what we are doing // 4. No: Let's request more blocks back. + // Make sure we are actually receiving anything if msg.Data.Len()-1 > 1 { + // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find + // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) if p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { fmt.Println("[PEER] We found a common ancestor, let's continue.") } else { + + // If we can't find a common ancenstor we need to request more blocks. + // FIXME: At one point this won't scale anymore since we are not asking for an offset + // we just keep increasing the amount of blocks. fmt.Println("[PEER] No common ancestor found, requesting more blocks.") p.blocksRequested = p.blocksRequested * 2 p.catchingUp = false @@ -329,14 +336,16 @@ func (p *Peer) HandleInbound() { for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - // Do we have this block on our chain? + // Do we have this block on our chain? If so we can continue if p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { fmt.Println("[PEER] Block found, checking next one.") } else { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { fmt.Printf("[PEER] Local and foreign chain have diverted after %x, we are going to get freaky with it!\n", block.PrevHash) - p.ethereum.StateManager().BlockChain().FindCanonicalChain(msg, block.PrevHash) + if p.ethereum.StateManager().BlockChain().FindCanonicalChain(msg, block.PrevHash) { + return + } } else { fmt.Println("[PEER] Both local and foreign chain have same parent. Continue normally") } @@ -358,7 +367,6 @@ func (p *Peer) HandleInbound() { } break } else { - ethutil.Config.Log.Infof("[PEER] Block %x added\n", block.Hash()) lastBlock = block } } From ec6ec62dd4f3c4132c79b33fc20467ba98c16f10 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 10:56:52 +0100 Subject: [PATCH 0184/1237] Remove some xtra logs --- ethchain/dagger.go | 4 ++-- ethchain/state_manager.go | 3 --- peer.go | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index a80a9d4216..9d2df40694 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - log.Println("[pow] Received reactor event; breaking out.") + log.Println("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - log.Println("Hashing @", int64(hashes), "khash") + log.Println("[POW] Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5692a1d88c..d907141a47 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -214,9 +214,6 @@ func (sm *StateManager) CalculateTD(block *Block) bool { // The new TD will only be accepted if the new difficulty is // is greater than the previous. - fmt.Println("new block td:", td) - fmt.Println("cur block td:", sm.bc.TD) - if td.Cmp(sm.bc.TD) > 0 { // Set the new total difficulty back to the block chain sm.bc.SetTotalDifficulty(td) diff --git a/peer.go b/peer.go index b8e75c6866..63059bcfb6 100644 --- a/peer.go +++ b/peer.go @@ -316,7 +316,7 @@ func (p *Peer) HandleInbound() { // 4. No: Let's request more blocks back. // Make sure we are actually receiving anything - if msg.Data.Len()-1 > 1 { + if msg.Data.Len()-1 > 1 && p.catchingUp { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) From e0b6091d7ef709902f534c1a4b57151f0171e03c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 24 Mar 2014 13:20:34 +0100 Subject: [PATCH 0185/1237] Test fixes and removed old code. Added VM gas fees --- ethchain/stack.go | 8 +-- ethchain/vm.go | 48 +++++++++++++- ethchain/vm_test.go | 147 +++++++++++++------------------------------ ethutil/common.go | 1 + ethutil/parsing.go | 2 +- ethutil/rlp_test.go | 6 ++ ethutil/trie_test.go | 2 +- 7 files changed, 103 insertions(+), 111 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 3c2899e623..57165c4326 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -202,7 +202,7 @@ func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println("### STACK ###") + fmt.Println("### stack ###") if len(st.data) > 0 { for i, val := range st.data { fmt.Printf("%-3d %v\n", i, val) @@ -242,15 +242,15 @@ func (m *Memory) Len() int { } func (m *Memory) Print() { - fmt.Println("### MEM ###") + fmt.Printf("### mem %d bytes ###\n", len(m.store)) if len(m.store) > 0 { addr := 0 - for i := 0; i+32 < len(m.store); i += 32 { + for i := 0; i+32 <= len(m.store); i += 32 { fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) addr++ } } else { fmt.Println("-- empty --") } - fmt.Println("###########") + fmt.Println("####################") } diff --git a/ethchain/vm.go b/ethchain/vm.go index 126592b25d..9b6807925a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -10,6 +10,17 @@ import ( "math/big" ) +var ( + GasStep = big.NewInt(1) + GasSha = big.NewInt(20) + GasSLoad = big.NewInt(20) + GasSStore = big.NewInt(100) + GasBalance = big.NewInt(20) + GasCreate = big.NewInt(100) + GasCall = big.NewInt(20) + GasMemory = big.NewInt(1) +) + type Vm struct { txPool *TxPool // Stack for processing contracts @@ -70,10 +81,41 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } // TODO Get each instruction cost properly - fee := new(big.Int) - fee.Add(fee, big.NewInt(1000)) + gas := new(big.Int) + useGas := func(amount *big.Int) { + gas.Add(gas, amount) + } - if closure.Gas.Cmp(fee) < 0 { + switch op { + case oSHA3: + useGas(GasSha) + case oSLOAD: + useGas(GasSLoad) + case oSSTORE: + var mult *big.Int + y, x := stack.Peekn() + val := closure.GetMem(x) + if val.IsEmpty() && len(y.Bytes()) > 0 { + mult = ethutil.Big2 + } else if !val.IsEmpty() && len(y.Bytes()) == 0 { + mult = ethutil.Big0 + } else { + mult = ethutil.Big1 + } + useGas(base.Mul(mult, GasSStore)) + case oBALANCE: + useGas(GasBalance) + case oCREATE: + useGas(GasCreate) + case oCALL: + useGas(GasCall) + case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: + useGas(GasMemory) + default: + useGas(GasStep) + } + + if closure.Gas.Cmp(gas) < 0 { return closure.Return(nil) } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 047531e09f..308a654325 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -2,113 +2,15 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/mutan" "math/big" + "strings" "testing" ) -/* - -func TestRun(t *testing.T) { - InitFees() - - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "TXSENDER", - "SUICIDE", - }) - - tx := NewTransaction(ContractAddr, big.NewInt(1e17), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} - -func TestRun1(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "0", - "PUSH", "0", - "TXSENDER", - "PUSH", "10000000", - "MKTX", - }) - fmt.Println(ethutil.NewValue(script)) - - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} - -func TestRun2(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "0", - "PUSH", "0", - "TXSENDER", - "PUSH", "10000000", - "MKTX", - }) - fmt.Println(ethutil.NewValue(script)) - - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) - fmt.Printf("contract addr %x\n", tx.Hash()[12:]) - contract := MakeContract(tx, state) - vm := &Vm{} - - vm.Process(contract, state, RuntimeVars{ - address: tx.Hash()[12:], - blockNumber: 1, - sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - txValue: tx.Value, - txData: tx.Data, - }) -} -*/ - -// XXX Full stack test func TestRun3(t *testing.T) { ethutil.ReadConfig("") @@ -132,7 +34,7 @@ func TestRun3(t *testing.T) { contract := MakeContract(tx, state) state.UpdateContract(contract) - callerScript := ethutil.Compile( + callerScript := ethutil.Assemble( "PUSH", 1337, // Argument "PUSH", 65, // argument mem offset "MSTORE", @@ -172,3 +74,44 @@ func TestRun3(t *testing.T) { t.Errorf("expected return value to be %v, got %v", exp, ret) } } + +func TestRun4(t *testing.T) { + ethutil.ReadConfig("") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + mutan.NewCompiler().Compile(strings.NewReader(` +a = 1337 +c = 1 +[0] = 50 +d = [0] +`)) + + asm := mutan.NewCompiler().Compile(strings.NewReader(` + a = 3 + 3 + [1000] = a + [1000] +`)) + asm = append(asm, "LOG") + fmt.Println(asm) + + callerScript := ethutil.Assemble(asm...) + callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + + // Contract addr as test address + account := NewAccount(ContractAddr, big.NewInt(10000000)) + callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + + vm := NewVm(state, RuntimeVars{ + origin: account.Address(), + blockNumber: 1, + prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + time: 1, + diff: big.NewInt(256), + // XXX Tx data? Could be just an argument to the closure instead + txData: nil, + }) + callerClosure.Call(vm, nil) +} diff --git a/ethutil/common.go b/ethutil/common.go index f15b10e6da..c63af29a69 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -36,6 +36,7 @@ func CurrencyToString(num *big.Int) string { var ( Big1 = big.NewInt(1) + Big2 = big.NewInt(1) Big0 = big.NewInt(0) Big256 = big.NewInt(0xff) ) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 8929f08294..16ed2d06db 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -131,7 +131,7 @@ func Instr(instr string) (int, []string, error) { // Script compilation functions // Compiles strings to machine code -func Compile(instructions ...interface{}) (script []string) { +func Assemble(instructions ...interface{}) (script []string) { script = make([]string, len(instructions)) for i, val := range instructions { diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2a58bfc0fa..dc10db6327 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -119,6 +120,11 @@ func TestEncodeDecodeBytes(t *testing.T) { } } +func TestEncodeZero(t *testing.T) { + b := NewValue(0).Encode() + fmt.Println(b) +} + func BenchmarkEncodeDecode(b *testing.B) { for i := 0; i < b.N; i++ { bytes := Encode([]interface{}{"dog", "god", "cat"}) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 79e5de9211..0be512d9fc 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - "fmt" + _ "fmt" "reflect" "testing" ) From 6253d109389d49e47772597de24cd11874b91338 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 24 Mar 2014 15:04:29 +0100 Subject: [PATCH 0186/1237] initial testcode for canonical chain --- ethchain/block_chain.go | 35 +++++++++----- ethchain/block_chain_test.go | 92 ++++++++++++++++++++++++++++++++++++ ethchain/state_manager.go | 3 ++ ethminer/miner.go | 1 + peer.go | 2 +- 5 files changed, 119 insertions(+), 14 deletions(-) create mode 100644 ethchain/block_chain_test.go diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index f25f0ca5ae..0e3601a4b4 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -24,7 +24,7 @@ type BlockChain struct { func NewBlockChain(ethereum EthManager) *BlockChain { bc := &BlockChain{} - bc.genesisBlock = NewBlockFromData(ethutil.Encode(Genesis)) + bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) bc.Ethereum = ethereum bc.setLastBlock() @@ -101,10 +101,18 @@ func (bc *BlockChain) CalculateBlockTD(block *Block) *big.Int { return blockDiff } +func (bc *BlockChain) FindCanonicalChainFromMsg(msg *ethwire.Msg, commonBlockHash []byte) bool { + var blocks []*Block + for i := 0; i < (msg.Data.Len() - 1); i++ { + block := NewBlockFromRlpValue(msg.Data.Get(i)) + blocks = append(blocks, block) + } + return bc.FindCanonicalChain(blocks, commonBlockHash) +} // Is tasked by finding the CanonicalChain and resetting the chain if we are not the Conical one // Return true if we are the using the canonical chain false if not -func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byte) bool { +func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte) bool { // 1. Calculate TD of the current chain // 2. Calculate TD of the new chain // Reset state to the correct one @@ -113,35 +121,35 @@ func (bc *BlockChain) FindCanonicalChain(msg *ethwire.Msg, commonBlockHash []byt // Calculate the entire chain until the block we both have // Start with the newest block we got, all the way back to the common block we both know - for i := 0; i < (msg.Data.Len() - 1); i++ { - block := NewBlockFromRlpValue(msg.Data.Get(i)) + for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[BCHAIN] We have found the common parent block, breaking") + log.Println("[CHAIN] We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[BCHAIN] Incoming chain difficulty:", chainDifficulty) + log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty) curChainDifficulty := new(big.Int) block := bc.CurrentBlock - - for ; block != nil; block = bc.GetBlock(block.PrevHash) { + for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { + i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[BCHAIN] We have found the common parent block, breaking") + log.Println("[CHAIN] We have found the common parent block, breaking") break } + log.Println("CHECKING BLOGK:", i) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[BCHAIN] Current chain difficulty:", curChainDifficulty) + log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Println("[BCHAIN] The incoming Chain beat our asses, resetting") + log.Println("[CHAIN] The incoming Chain beat our asses, resetting") bc.ResetTillBlockHash(commonBlockHash) return false } else { - log.Println("[BCHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.") return true } } @@ -286,6 +294,7 @@ func (bc *BlockChain) Add(block *Block) { bc.LastBlockHash = block.Hash() encodedBlock := block.RlpEncode() + log.Println(encodedBlock) ethutil.Config.Db.Put(block.Hash(), encodedBlock) ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } @@ -296,7 +305,7 @@ func (bc *BlockChain) GetBlock(hash []byte) *Block { return nil } - return NewBlockFromData(data) + return NewBlockFromBytes(data) } func (bc *BlockChain) BlockInfoByHash(hash []byte) BlockInfo { diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go new file mode 100644 index 0000000000..736247e831 --- /dev/null +++ b/ethchain/block_chain_test.go @@ -0,0 +1,92 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethwire" + "testing" +) + +// Implement our EthTest Manager +type TestManager struct { + stateManager *StateManager + reactor *ethutil.ReactorEngine + + txPool *TxPool + blockChain *BlockChain + Blocks []*Block +} + +func (s *TestManager) BlockChain() *BlockChain { + return s.blockChain +} + +func (tm *TestManager) TxPool() *TxPool { + return tm.txPool +} + +func (tm *TestManager) StateManager() *StateManager { + return tm.stateManager +} + +func (tm *TestManager) Reactor() *ethutil.ReactorEngine { + return tm.reactor +} +func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { + fmt.Println("Broadcast not implemented") +} + +func NewTestManager() *TestManager { + ethutil.ReadConfig(".ethtest") + + db, err := ethdb.NewMemDatabase() + if err != nil { + fmt.Println("Could not create mem-db, failing") + return nil + } + ethutil.Config.Db = db + + testManager := &TestManager{} + testManager.reactor = ethutil.NewReactorEngine() + + testManager.txPool = NewTxPool(testManager) + testManager.blockChain = NewBlockChain(testManager) + testManager.stateManager = NewStateManager(testManager) + + // Start the tx pool + testManager.txPool.Start() + + return testManager +} +func (tm *TestManager) AddFakeBlock(blk []byte) error { + block := NewBlockFromBytes(blk) + tm.Blocks = append(tm.Blocks, block) + tm.StateManager().PrepareDefault(block) + err := tm.StateManager().ProcessBlock(block, false) + return err +} +func (tm *TestManager) CreateChain1() error { + err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 68, 52, 33, 210, 160, 189, 217, 255, 78, 37, 196, 217, 94, 247, 166, 169, 224, 199, 102, 110, 85, 213, 45, 13, 173, 106, 4, 103, 151, 195, 38, 86, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 208, 12, 132, 83, 48, 38, 206, 128, 160, 65, 147, 32, 128, 177, 198, 131, 57, 57, 68, 135, 65, 198, 178, 138, 43, 25, 135, 92, 174, 208, 119, 103, 225, 26, 207, 243, 31, 225, 29, 173, 119, 192, 192}) + return err +} +func (tm *TestManager) CreateChain2() error { + err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 40, 35, 128, 160, 162, 214, 119, 207, 212, 186, 64, 47, 14, 186, 98, 118, 203, 79, 172, 205, 33, 206, 225, 177, 225, 194, 98, 188, 63, 219, 13, 151, 47, 32, 204, 27, 192, 192}) + err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 0, 210, 76, 6, 13, 18, 219, 190, 18, 250, 23, 178, 198, 117, 254, 85, 14, 74, 104, 116, 56, 144, 116, 172, 14, 3, 236, 99, 248, 228, 142, 91, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 72, 201, 77, 81, 160, 103, 70, 18, 102, 204, 82, 192, 86, 157, 40, 30, 117, 218, 224, 202, 1, 36, 249, 88, 82, 210, 19, 156, 112, 31, 13, 117, 227, 0, 125, 221, 190, 165, 16, 193, 163, 161, 175, 33, 37, 184, 235, 62, 201, 93, 102, 185, 143, 54, 146, 114, 30, 253, 178, 245, 87, 38, 191, 214, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 255, 252, 132, 83, 48, 40, 74, 128, 160, 185, 20, 138, 2, 210, 15, 71, 144, 89, 167, 94, 155, 148, 118, 170, 157, 122, 70, 70, 114, 50, 221, 231, 8, 132, 167, 115, 239, 44, 245, 41, 226, 192, 192}) + return err +} + +func TestBlockChainReorg(t *testing.T) { + testManager := NewTestManager() + testManager.CreateChain1() + testManager2 := NewTestManager() + testManager2.CreateChain2() + + // This fails because we keep resetting the DB + block := testManager.BlockChain().GetBlock(testManager.BlockChain().CurrentBlock.PrevHash) + fmt.Println(block) + //testManager.BlockChain().FindCanonicalChain(testManager2.Blocks, testManager.BlockChain().GenesisBlock().Hash()) + +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d907141a47..140b0efd0e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -144,6 +144,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { hash := block.Hash() if sm.bc.HasBlock(hash) { + fmt.Println("[SM] We already have this block, ignoring") return nil } @@ -158,12 +159,14 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Block validation if err := sm.ValidateBlock(block); err != nil { + fmt.Println("[SM] Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. if err := sm.AccumelateRewards(block); err != nil { + fmt.Println("[SM] Error accumulating reward", err) return err } diff --git a/ethminer/miner.go b/ethminer/miner.go index cb752e3dec..125eb6fb1d 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -138,6 +138,7 @@ func (miner *Miner) listener() { } miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) + log.Println(miner.block) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) diff --git a/peer.go b/peer.go index 63059bcfb6..21d55ce6de 100644 --- a/peer.go +++ b/peer.go @@ -342,7 +342,7 @@ func (p *Peer) HandleInbound() { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { fmt.Printf("[PEER] Local and foreign chain have diverted after %x, we are going to get freaky with it!\n", block.PrevHash) - if p.ethereum.StateManager().BlockChain().FindCanonicalChain(msg, block.PrevHash) { + if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { return } } else { From 308c59320c25845f9668e76559b581e2161fec15 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 15:38:55 +0100 Subject: [PATCH 0187/1237] Fixed typo --- ethutil/rlp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 33ec0d3598..e6c75696ee 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -57,7 +57,7 @@ func DecodeWithReader(reader *bytes.Buffer) interface{} { switch { case char == 0: return nil - case char <= 0x7c: + case char <= 0x7f: return char case char <= 0xb7: From 43cad6901620ca077e43f195cc5ae4d1c8edb2d0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 15:42:39 +0100 Subject: [PATCH 0188/1237] Reworked transaction constructors --- ethchain/keypair.go | 3 ++ ethchain/transaction.go | 62 +++++++++++++++++++++++++++++++++-------- ethchain/vm.go | 3 +- peer.go | 3 +- 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/ethchain/keypair.go b/ethchain/keypair.go index 9fdc95972b..9daaedbee2 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -34,6 +34,7 @@ func (k *KeyPair) Account() *Account { // Create transaction, creates a new and signed transaction, ready for processing func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { + /* TODO tx := NewTransaction(receiver, value, data) tx.Nonce = k.account.Nonce @@ -41,6 +42,8 @@ func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Tran tx.Sign(k.PrivateKey) return tx + */ + return nil } func (k *KeyPair) RlpEncode() []byte { diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 3b07c81d45..695071251b 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -18,16 +18,21 @@ type Transaction struct { Data []string v byte r, s []byte + + // Indicates whether this tx is a contract creation transaction + contractCreation bool } +/* func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} return &tx } +*/ func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: data} + return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { @@ -38,10 +43,12 @@ func NewTx(to []byte, value *big.Int, data []string) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} } +/* // XXX Deprecated func NewTransactionFromData(data []byte) *Transaction { return NewTransactionFromBytes(data) } +*/ func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} @@ -148,19 +155,52 @@ func (tx *Transaction) RlpDecode(data []byte) { tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) } +// [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Recipient = decoder.Get(1).Bytes() - tx.Value = decoder.Get(2).BigInt() + tx.Value = decoder.Get(1).BigInt() + tx.Gasprice = decoder.Get(2).BigInt() - d := decoder.Get(3) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() + // If the 4th item is a list(slice) this tx + // is a contract creation tx + if decoder.Get(3).IsSlice() { + d := decoder.Get(3) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() + tx.contractCreation = true + } else { + tx.Recipient = decoder.Get(3).Bytes() + tx.Gas = decoder.Get(4).BigInt() + + d := decoder.Get(5) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() } + /* + tx.Nonce = decoder.Get(0).Uint() + tx.Recipient = decoder.Get(1).Bytes() + tx.Value = decoder.Get(2).BigInt() - // TODO something going wrong here - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() + d := decoder.Get(3) + tx.Data = make([]string, d.Len()) + for i := 0; i < d.Len(); i++ { + tx.Data[i] = d.Get(i).Str() + } + + tx.v = byte(decoder.Get(4).Uint()) + tx.r = decoder.Get(5).Bytes() + tx.s = decoder.Get(6).Bytes() + */ } diff --git a/ethchain/vm.go b/ethchain/vm.go index 9b6807925a..aefc8ff0c8 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,7 +5,6 @@ import ( _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" - "log" _ "math" "math/big" ) @@ -359,6 +358,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } } +/* func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) j := int64(0) @@ -395,3 +395,4 @@ func contractMemory(state *State, contractAddr []byte, memAddr *big.Int) *big.In return decoder.BigInt() } +*/ diff --git a/peer.go b/peer.go index 24a5e97c95..82c9839273 100644 --- a/peer.go +++ b/peer.go @@ -334,7 +334,8 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) + //p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) + p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromValue(msg.Data.Get(i))) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to From 7660e1ed907e213a53408fe60a63619a68fd817b Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 19:42:01 +0100 Subject: [PATCH 0189/1237] Added a IsList method for type checking []interface{} --- ethutil/value.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethutil/value.go b/ethutil/value.go index 46681ec2a5..04131aba90 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -149,6 +149,15 @@ func (val *Value) IsStr() bool { return val.Type() == reflect.String } +// Special list checking function. Something is considered +// a list if it's of type []interface{}. The list is usually +// used in conjunction with rlp decoded streams. +func (val *Value) IsList() bool { + _, ok := val.Val.([]interface{}) + + return ok +} + func (val *Value) IsEmpty() bool { return val.Val == nil || ((val.IsSlice() || val.IsStr()) && val.Len() == 0) } From 00c5f9b9a67a6ab6f2850b756804dfa6efd8a824 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 19:49:47 +0100 Subject: [PATCH 0190/1237] Updated transaction model Changed the behaviour of decoding rlp data. Something is considered to be creating a contract if the 4th item is a list. Changed constructors. --- ethchain/transaction.go | 42 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 695071251b..d71f9c7f73 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -23,33 +24,14 @@ type Transaction struct { contractCreation bool } -/* -func NewTransaction(to []byte, value *big.Int, data []string) *Transaction { - tx := Transaction{Recipient: to, Value: value, Nonce: 0, Data: data} - - return &tx -} -*/ - func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } -func NewContractMessageTx(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { +func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} } -func NewTx(to []byte, value *big.Int, data []string) *Transaction { - return &Transaction{Recipient: to, Value: value, Gasprice: big.NewInt(0), Gas: big.NewInt(0), Nonce: 0, Data: data} -} - -/* -// XXX Deprecated -func NewTransactionFromData(data []byte) *Transaction { - return NewTransactionFromBytes(data) -} -*/ - func NewTransactionFromBytes(data []byte) *Transaction { tx := &Transaction{} tx.RlpDecode(data) @@ -131,16 +113,13 @@ func (tx *Transaction) Sign(privk []byte) error { } func (tx *Transaction) RlpData() interface{} { - // Prepare the transaction for serialization - return []interface{}{ - tx.Nonce, - tx.Recipient, - tx.Value, - ethutil.NewSliceValue(tx.Data).Slice(), - tx.v, - tx.r, - tx.s, + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice} + + if !tx.contractCreation { + data = append(data, tx.Recipient, tx.Gas) } + + return append(data, ethutil.NewSliceValue(tx.Data).Slice(), tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { @@ -156,14 +135,16 @@ func (tx *Transaction) RlpDecode(data []byte) { } // [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] +//["" "\x03\xe8" "" "\xaa" "\x03\xe8" [] '\x1c' "\x10C\x15\xfc\xe5\xd0\t\xe4\r\xe7\xefa\xf5aE\xd6\x14\xaed\xb5.\xf5\x18\xa1S_j\xe0A\xdc5U" "dQ\nqy\xf8\x17+\xbf\xd7Jx\xda-\xcb\xd7\xcfQ\x1bI\xb8_9\b\x80\xea듎i|\x1f"] func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + fmt.Println(decoder) tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() // If the 4th item is a list(slice) this tx // is a contract creation tx - if decoder.Get(3).IsSlice() { + if decoder.Get(3).IsList() { d := decoder.Get(3) tx.Data = make([]string, d.Len()) for i := 0; i < d.Len(); i++ { @@ -173,6 +154,7 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(4).Uint()) tx.r = decoder.Get(5).Bytes() tx.s = decoder.Get(6).Bytes() + tx.contractCreation = true } else { tx.Recipient = decoder.Get(3).Bytes() From 56a58ad70db22b0714a8f81fe31eaedc2a1e8e0d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 22:02:39 +0100 Subject: [PATCH 0191/1237] Removed debug and comments --- ethchain/transaction.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index d71f9c7f73..af27fe6395 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -2,7 +2,6 @@ package ethchain import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -134,10 +133,7 @@ func (tx *Transaction) RlpDecode(data []byte) { tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) } -// [ NONCE, VALUE, GASPRICE, TO, GAS, DATA, V, R, S ] -//["" "\x03\xe8" "" "\xaa" "\x03\xe8" [] '\x1c' "\x10C\x15\xfc\xe5\xd0\t\xe4\r\xe7\xefa\xf5aE\xd6\x14\xaed\xb5.\xf5\x18\xa1S_j\xe0A\xdc5U" "dQ\nqy\xf8\x17+\xbf\xd7Jx\xda-\xcb\xd7\xcfQ\x1bI\xb8_9\b\x80\xea듎i|\x1f"] func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - fmt.Println(decoder) tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() @@ -170,19 +166,4 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() } - /* - tx.Nonce = decoder.Get(0).Uint() - tx.Recipient = decoder.Get(1).Bytes() - tx.Value = decoder.Get(2).BigInt() - - d := decoder.Get(3) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() - } - - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() - */ } From 3c3431d111ae8ba7f03349f93c9b191fcdf92254 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 23:17:14 +0100 Subject: [PATCH 0192/1237] Fixed IsContract method to use the contractCreation flag --- ethchain/transaction.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index af27fe6395..9fdf55b4db 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,7 +1,6 @@ package ethchain import ( - "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -62,7 +61,7 @@ func (tx *Transaction) Hash() []byte { } func (tx *Transaction) IsContract() bool { - return bytes.Compare(tx.Recipient, ContractAddr) == 0 + return tx.contractCreation } func (tx *Transaction) Signature(key []byte) []byte { From 75e6406c1f1034dbf96aca28193d7e1e0653db50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 27 Mar 2014 23:17:23 +0100 Subject: [PATCH 0193/1237] Fixed tests --- ethchain/vm_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 308a654325..5acc476597 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -29,7 +29,7 @@ func TestRun3(t *testing.T) { "PUSH", "0", "RETURN", }) - tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateContract(contract) @@ -51,7 +51,7 @@ func TestRun3(t *testing.T) { "PUSH", 0, "RETURN", ) - callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) @@ -84,20 +84,20 @@ func TestRun4(t *testing.T) { mutan.NewCompiler().Compile(strings.NewReader(` a = 1337 c = 1 -[0] = 50 -d = [0] +store[0] = 50 +d = store[0] `)) - asm := mutan.NewCompiler().Compile(strings.NewReader(` + asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` a = 3 + 3 - [1000] = a - [1000] + stotre[1000] = a + store[1000] `)) asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) From 60fd2f3521471b300107847271f4df2919f1b0d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Thu, 27 Mar 2014 23:25:03 +0100 Subject: [PATCH 0194/1237] Update vm_test.go store ... --- ethchain/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5acc476597..c802420cb4 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -90,7 +90,7 @@ d = store[0] asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` a = 3 + 3 - stotre[1000] = a + store[1000] = a store[1000] `)) asm = append(asm, "LOG") From b888652201277ab86e9e8c280e75e23ced5e3d38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 28 Mar 2014 11:20:07 +0100 Subject: [PATCH 0195/1237] Added missing GetTx (0x16) wire message --- ethchain/transaction_pool.go | 8 +++++++- ethwire/messaging.go | 2 ++ peer.go | 18 ++++++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index fdc3863036..4a4f2e809a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -207,7 +207,7 @@ func (pool *TxPool) QueueTransaction(tx *Transaction) { pool.queueChan <- tx } -func (pool *TxPool) Flush() []*Transaction { +func (pool *TxPool) CurrentTransactions() []*Transaction { pool.mutex.Lock() defer pool.mutex.Unlock() @@ -221,6 +221,12 @@ func (pool *TxPool) Flush() []*Transaction { i++ } + return txList +} + +func (pool *TxPool) Flush() []*Transaction { + txList := pool.CurrentTransactions() + // Recreate a new list all together // XXX Is this the fastest way? pool.pool = list.New() diff --git a/ethwire/messaging.go b/ethwire/messaging.go index 185faa341a..b622376f36 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -32,6 +32,7 @@ const ( MsgBlockTy = 0x13 MsgGetChainTy = 0x14 MsgNotInChainTy = 0x15 + MsgGetTxsTy = 0x16 MsgTalkTy = 0xff ) @@ -46,6 +47,7 @@ var msgTypeToString = map[MsgType]string{ MsgTxTy: "Transactions", MsgBlockTy: "Blocks", MsgGetChainTy: "Get chain", + MsgGetTxsTy: "Get Txs", MsgNotInChainTy: "Not in chain", } diff --git a/peer.go b/peer.go index 82c9839273..279b0bc7f1 100644 --- a/peer.go +++ b/peer.go @@ -334,8 +334,8 @@ func (p *Peer) HandleInbound() { // in the TxPool where it will undergo validation and // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { - //p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromData(msg.Data.Get(i).Encode())) - p.ethereum.TxPool().QueueTransaction(ethchain.NewTransactionFromValue(msg.Data.Get(i))) + tx := ethchain.NewTransactionFromValue(msg.Data.Get(i)) + p.ethereum.TxPool().QueueTransaction(tx) } case ethwire.MsgGetPeersTy: // Flag this peer as a 'requested of new peers' this to @@ -398,6 +398,16 @@ func (p *Peer) HandleInbound() { case ethwire.MsgNotInChainTy: ethutil.Config.Log.Infof("Not in chain %x\n", msg.Data) // TODO + case ethwire.MsgGetTxsTy: + // Get the current transactions of the pool + txs := p.ethereum.TxPool().CurrentTransactions() + // Get the RlpData values from the txs + txsInterface := make([]interface{}, len(txs)) + for i, tx := range txs { + txsInterface[i] = tx.RlpData() + } + // Broadcast it back to the peer + p.QueueMessage(ethwire.NewMessage(ethwire.MsgTxTy, txsInterface)) // Unofficial but fun nonetheless case ethwire.MsgTalkTy: @@ -562,6 +572,10 @@ func (p *Peer) CatchupWithPeer() { p.QueueMessage(msg) ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) + + msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) + p.QueueMessage(msg) + ethutil.Config.Log.Debugln("Requested transactions") } } From 6625b6ffbdb93a47de2187198d6e826fb32c1ba6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 12:58:37 +0200 Subject: [PATCH 0196/1237] Changed to new mutan API --- ethchain/state_manager.go | 26 +++++++++++++------------- ethchain/vm_test.go | 25 ++++++++++++++----------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3b55077405..5c693442b9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -100,16 +100,21 @@ func (sm *StateManager) MakeContract(tx *Transaction) { } } +// Apply transactions uses the transaction passed to it and applies them onto +// the current processing state. func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. if tx.IsContract() { sm.MakeContract(tx) - //XXX block.MakeContract(tx) } else { + // Figure out if the address this transaction was sent to is a + // contract or an actual account. In case of a contract, we process that + // contract instead of moving funds between accounts. if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - //XXX if contract := block.state.GetContract(tx.Recipient); contract != nil { sm.ProcessContract(contract, tx, block) } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) @@ -172,14 +177,12 @@ func (sm *StateManager) ProcessBlock(block *Block) error { // if !sm.compState.Cmp(sm.procState) if !sm.compState.Cmp(sm.procState) { - //XXX return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, sm.bc.CurrentBlock.State().trie.Root) return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - //XXX sm.bc.CurrentBlock.Sync() sm.procState.Sync() // Broadcast the valid block back to the wire @@ -273,12 +276,10 @@ func CalculateUncleReward(block *Block) *big.Int { func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - //XXX addr := processor.state.GetAccount(block.Coinbase) addr := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - //XXX processor.state.UpdateAccount(block.Coinbase, addr) sm.procState.UpdateAccount(block.Coinbase, addr) for _, uncle := range block.Uncles { @@ -298,13 +299,12 @@ func (sm *StateManager) Stop() { func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors - /* - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from VM execution with err =", r) - } - }() - */ + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + } + }() + caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index c802420cb4..589f0bf4aa 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -81,18 +81,21 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - mutan.NewCompiler().Compile(strings.NewReader(` -a = 1337 -c = 1 -store[0] = 50 -d = store[0] -`)) + mutan.Compile(strings.NewReader(` + a = 1337 + c = 1 + store[0] = 50 + d = store[0] + `), false) - asm, _ := mutan.NewCompiler().Compile(strings.NewReader(` - a = 3 + 3 - store[1000] = a - store[1000] -`)) + asm, err := mutan.Compile(strings.NewReader(` + a = 3 + 3 + store[1000] = a + store[1000] + `), false) + if err != nil { + fmt.Println(err) + } asm = append(asm, "LOG") fmt.Println(asm) From 205e33bc831bb44f41dc899ae41bbfe0e44ddc5d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 18:55:51 +0200 Subject: [PATCH 0197/1237] Fixed bug in stack to expand beyond expectations. Fixed EQ and NOT opcode --- ethchain/stack.go | 14 +++++++++----- ethchain/vm.go | 20 ++++++++++++++------ ethchain/vm_test.go | 21 +++++++++------------ 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 57165c4326..e3fc4b6844 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -173,21 +173,25 @@ func NewStack() *Stack { } func (st *Stack) Pop() *big.Int { - str := st.data[0] - st.data = st.data[1:] + str := st.data[len(st.data)-1] + + copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1]) + st.data = st.data[:len(st.data)-1] return str } func (st *Stack) Popn() (*big.Int, *big.Int) { - ints := st.data[:2] - st.data = st.data[2:] + ints := st.data[len(st.data)-2:] + + copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2]) + st.data = st.data[:len(st.data)-2] return ints[0], ints[1] } func (st *Stack) Peek() *big.Int { - str := st.data[0] + str := st.data[len(st.data)-1] return str } diff --git a/ethchain/vm.go b/ethchain/vm.go index aefc8ff0c8..18b7fe607b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - _ "fmt" + "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -213,10 +213,17 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } else { stack.Push(ethutil.BigFalse) } - case oNOT: + case oEQ: x, y := stack.Popn() - // x != y - if x.Cmp(y) != 0 { + // x == y + if x.Cmp(y) == 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oNOT: + x := stack.Pop() + if x.Cmp(ethutil.BigFalse) == 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -300,8 +307,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { case oJUMP: pc = stack.Pop() case oJUMPI: - pos, cond := stack.Popn() - if cond.Cmp(big.NewInt(0)) > 0 { + cond, pos := stack.Popn() + if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos } case oPC: @@ -314,6 +321,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { retSize, retOffset := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() + fmt.Println(inSize, inOffset) // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) // Pop gas and value of the stack. diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 589f0bf4aa..e3880d26ec 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,7 +1,7 @@ package ethchain import ( - "bytes" + _ "bytes" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -11,6 +11,7 @@ import ( "testing" ) +/* func TestRun3(t *testing.T) { ethutil.ReadConfig("") @@ -73,7 +74,7 @@ func TestRun3(t *testing.T) { if bytes.Compare(ret, exp) != 0 { t.Errorf("expected return value to be %v, got %v", exp, ret) } -} +}*/ func TestRun4(t *testing.T) { ethutil.ReadConfig("") @@ -81,17 +82,13 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - mutan.Compile(strings.NewReader(` - a = 1337 - c = 1 - store[0] = 50 - d = store[0] - `), false) - asm, err := mutan.Compile(strings.NewReader(` - a = 3 + 3 - store[1000] = a - store[1000] + a = 10 + b = 10 + if a == b { + b = 1000 + c = 10 + } `), false) if err != nil { fmt.Println(err) From 7cc28c8b469ba8df8bad1e3bbbba7fbd99b88535 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Mar 2014 22:03:08 +0200 Subject: [PATCH 0198/1237] Added storage test --- ethchain/vm_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index e3880d26ec..2a02bcf4cd 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,14 +86,22 @@ func TestRun4(t *testing.T) { a = 10 b = 10 if a == b { - b = 1000 c = 10 + if c == 10 { + d = 1000 + e = 10 + } } + + store[0] = 20 + test = store[0] + store[a] = 20 + f = store[400] `), false) if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") + //asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) From 7277c420479239fbea78417e42c43ee0162c2728 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 31 Mar 2014 01:03:28 +0200 Subject: [PATCH 0199/1237] Fixed some state issues --- ethchain/state_manager.go | 6 +++--- ethchain/transaction.go | 3 ++- ethchain/vm.go | 2 ++ ethchain/vm_test.go | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5c693442b9..d9831d49fb 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -82,7 +82,7 @@ func (sm *StateManager) WatchAddr(addr []byte) *AccountState { func (sm *StateManager) GetAddrState(addr []byte) *AccountState { account := sm.addrStateStore.Get(addr) if account == nil { - a := sm.bc.CurrentBlock.state.GetAccount(addr) + a := sm.procState.GetAccount(addr) account = &AccountState{Nonce: a.Nonce, Account: a} } @@ -128,9 +128,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // The prepare function, prepares the state manager for the next // "ProcessBlock" action. -func (sm *StateManager) Prepare(processer *State, comparative *State) { +func (sm *StateManager) Prepare(processor *State, comparative *State) { sm.compState = comparative - sm.procState = processer + sm.procState = processor } // Default prepare function diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 9fdf55b4db..506e3c159a 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -116,8 +116,9 @@ func (tx *Transaction) RlpData() interface{} { if !tx.contractCreation { data = append(data, tx.Recipient, tx.Gas) } + d := ethutil.NewSliceValue(tx.Data).Slice() - return append(data, ethutil.NewSliceValue(tx.Data).Slice(), tx.v, tx.r, tx.s) + return append(data, d, tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { diff --git a/ethchain/vm.go b/ethchain/vm.go index 18b7fe607b..98aaa603ad 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -115,6 +115,8 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } if closure.Gas.Cmp(gas) < 0 { + ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) + return closure.Return(nil) } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 2a02bcf4cd..838f12f562 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -94,9 +94,7 @@ func TestRun4(t *testing.T) { } store[0] = 20 - test = store[0] store[a] = 20 - f = store[400] `), false) if err != nil { fmt.Println(err) From 5f49a659c36dbfb8c330ddc3d4565c19a9a936b5 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 31 Mar 2014 12:54:37 +0200 Subject: [PATCH 0200/1237] More blockchain testing --- ethchain/block_chain.go | 13 +++++++++++-- ethchain/block_chain_test.go | 37 +++++++++++++++++++++++++++++------- ethutil/rlp_test.go | 10 ++++++++++ ethutil/trie_test.go | 2 +- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 0e3601a4b4..8c03eec38f 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -126,6 +126,7 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } + log.Println("Checking incoming blocks:") chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } @@ -139,13 +140,20 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } - log.Println("CHECKING BLOGK:", i) + anOtherBlock := bc.GetBlock(block.PrevHash) + if anOtherBlock == nil { + // We do not want to count the genesis block for difficulty since that's not being sent + log.Println("[CHAIN] At genesis block, breaking") + break + } + log.Printf("CHECKING OUR OWN BLOCKS: %x", block.Hash()) + log.Printf("%x", bc.GenesisBlock().Hash()) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Println("[CHAIN] The incoming Chain beat our asses, resetting") + log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) bc.ResetTillBlockHash(commonBlockHash) return false } else { @@ -165,6 +173,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { // END TODO bc.Ethereum.StateManager().PrepareDefault(returnTo) + err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { return err diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 736247e831..30eb622660 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -78,15 +78,38 @@ func (tm *TestManager) CreateChain2() error { return err } -func TestBlockChainReorg(t *testing.T) { - testManager := NewTestManager() - testManager.CreateChain1() +func TestNegativeBlockChainReorg(t *testing.T) { + // We are resetting the database between creation so we need to cache our information testManager2 := NewTestManager() testManager2.CreateChain2() + tm2Blocks := testManager2.Blocks - // This fails because we keep resetting the DB - block := testManager.BlockChain().GetBlock(testManager.BlockChain().CurrentBlock.PrevHash) - fmt.Println(block) - //testManager.BlockChain().FindCanonicalChain(testManager2.Blocks, testManager.BlockChain().GenesisBlock().Hash()) + testManager := NewTestManager() + testManager.CreateChain1() + oldState := testManager.BlockChain().CurrentBlock.State() + + if testManager.BlockChain().FindCanonicalChain(tm2Blocks, testManager.BlockChain().GenesisBlock().Hash()) != true { + t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") + } + if testManager.BlockChain().CurrentBlock.State() != oldState { + t.Error("I expected the top state to be the same as it was as before the reorg") + } } + +func TestPositiveBlockChainReorg(t *testing.T) { + testManager := NewTestManager() + testManager.CreateChain1() + tm1Blocks := testManager.Blocks + + testManager2 := NewTestManager() + testManager2.CreateChain2() + oldState := testManager2.BlockChain().CurrentBlock.State() + + if testManager2.BlockChain().FindCanonicalChain(tm1Blocks, testManager.BlockChain().GenesisBlock().Hash()) == true { + t.Error("I expected TestManager to have the longest chain, but it was TestManager2 instead.") + } + if testManager2.BlockChain().CurrentBlock.State() == oldState { + t.Error("I expected the top state to have been modified but it was not") + } +} diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 2a58bfc0fa..ce25356634 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,6 +2,7 @@ package ethutil import ( "bytes" + "fmt" "math/big" "reflect" "testing" @@ -55,6 +56,15 @@ func TestValue(t *testing.T) { } } +func TestEncodeDecodeMaran(t *testing.T) { + b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"}) + a := b.Encode() + fmt.Println("voor maran", a) + f, i := Decode(a, 0) + fmt.Println("voor maran 2", f) + fmt.Println(i) +} + func TestEncode(t *testing.T) { strRes := "\x83dog" bytes := Encode("dog") diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 79e5de9211..0be512d9fc 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - "fmt" + _ "fmt" "reflect" "testing" ) From 7d0348e4baf45197ca506070e06e756a4ba6ccf6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Apr 2014 10:41:30 +0200 Subject: [PATCH 0201/1237] Handle contract messages --- ethchain/state_manager.go | 18 +++++++++++++----- ethchain/transaction_pool.go | 12 +++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index d9831d49fb..95e46e41d5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,13 +114,18 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Figure out if the address this transaction was sent to is a // contract or an actual account. In case of a contract, we process that // contract instead of moving funds between accounts. + var err error if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - sm.ProcessContract(contract, tx, block) - } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block) - if err != nil { - ethutil.Config.Log.Infoln("[STATE]", err) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, true) + if err == nil { + sm.ProcessContract(contract, tx, block) } + } else { + err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, false) + } + + if err != nil { + ethutil.Config.Log.Infoln("[STATE]", err) } } } @@ -318,4 +323,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo txData: nil, }) closure.Call(vm, nil) + + // Update the account (refunds) + sm.procState.UpdateAccount(tx.Sender(), caller) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 4a4f2e809a..66828adfbf 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { defer func() { if r := recover(); r != nil { log.Println(r) @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -116,13 +116,15 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error } // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + } else if toContract { + sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) } else { // Subtract the amount from the senders account sender.Amount.Sub(sender.Amount, totAmount) @@ -130,10 +132,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - block.state.UpdateAccount(tx.Recipient, receiver) + state.UpdateAccount(tx.Recipient, receiver) } - block.state.UpdateAccount(tx.Sender(), sender) + state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) From 3558dd5ed4e14f124f04e2bf72fc3b989dff9e77 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Apr 2014 14:42:48 +0200 Subject: [PATCH 0202/1237] Finalize blockchain reverting test --- ethchain/block_chain.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 8c03eec38f..a8d9793d68 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -163,14 +163,20 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte } func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { lastBlock := bc.CurrentBlock - returnTo := bc.GetBlock(hash) - - // TODO: REFACTOR TO FUNCTION, Used multiple times - bc.CurrentBlock = returnTo - bc.LastBlockHash = returnTo.Hash() - info := bc.BlockInfo(returnTo) - bc.LastBlockNumber = info.Number - // END TODO + var returnTo *Block + // Reset to Genesis if that's all the origin there is. + if bytes.Compare(hash, bc.genesisBlock.Hash()) == 0 { + returnTo = bc.genesisBlock + bc.CurrentBlock = bc.genesisBlock + bc.LastBlockHash = bc.genesisBlock.Hash() + bc.LastBlockNumber = 1 + } else { + returnTo = bc.GetBlock(hash) + bc.CurrentBlock = returnTo + bc.LastBlockHash = returnTo.Hash() + info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = info.Number + } bc.Ethereum.StateManager().PrepareDefault(returnTo) From 782910eaa76bb31be4c2bcd0f4505b8085acb57c Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Apr 2014 15:54:29 +0200 Subject: [PATCH 0203/1237] Small tweaks --- ethchain/block_chain.go | 3 --- ethminer/miner.go | 2 -- peer.go | 9 +++------ 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index a8d9793d68..f621965ae0 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -146,8 +146,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] At genesis block, breaking") break } - log.Printf("CHECKING OUR OWN BLOCKS: %x", block.Hash()) - log.Printf("%x", bc.GenesisBlock().Hash()) curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } @@ -309,7 +307,6 @@ func (bc *BlockChain) Add(block *Block) { bc.LastBlockHash = block.Hash() encodedBlock := block.RlpEncode() - log.Println(encodedBlock) ethutil.Config.Db.Put(block.Hash(), encodedBlock) ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) } diff --git a/ethminer/miner.go b/ethminer/miner.go index 125eb6fb1d..60af3ab319 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -130,7 +130,6 @@ func (miner *Miner) listener() { err := miner.ethereum.StateManager().ProcessBlock(miner.block, true) if err != nil { log.Println("Error result from process block:", err) - log.Println(miner.block) } else { if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { @@ -138,7 +137,6 @@ func (miner *Miner) listener() { } miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) - log.Println(miner.block) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) diff --git a/peer.go b/peer.go index f2267c29b6..0ecd13e604 100644 --- a/peer.go +++ b/peer.go @@ -337,16 +337,16 @@ func (p *Peer) HandleInbound() { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) // Do we have this block on our chain? If so we can continue if p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { - fmt.Println("[PEER] Block found, checking next one.") + ethutil.Config.Log.Debugf("[PEER] Block found, checking next one.\n") } else { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { - fmt.Printf("[PEER] Local and foreign chain have diverted after %x, we are going to get freaky with it!\n", block.PrevHash) + ethutil.Config.Log.Infof("[PEER] Local and foreign chain have diverted after %x, finding best chain!\n", block.PrevHash) if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { return } } else { - fmt.Println("[PEER] Both local and foreign chain have same parent. Continue normally") + ethutil.Config.Log.Debugf("[PEER] Both local and foreign chain have same parent. Continue normally\n") } } } @@ -362,7 +362,6 @@ func (p *Peer) HandleInbound() { if ethutil.Config.Debug { ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash()) ethutil.Config.Log.Infof("[PEER] %v\n", err) - ethutil.Config.Log.Infoln(block) } break } else { @@ -637,8 +636,6 @@ func (p *Peer) SyncWithBlocks() { if p.blocksRequested == 0 { p.blocksRequested = 10 } - fmt.Printf("Currenb lock %x\n", p.ethereum.BlockChain().CurrentBlock.Hash()) - fmt.Println("Amount:", p.blocksRequested) blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested) var hashes []interface{} From 90bb512f420f204f50ba451a4a25682ca8443746 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 5 Apr 2014 10:49:07 +0200 Subject: [PATCH 0204/1237] Update --- ethchain/vm_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 838f12f562..85ec4c6935 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -83,18 +83,23 @@ func TestRun4(t *testing.T) { state := NewState(ethutil.NewTrie(db, "")) asm, err := mutan.Compile(strings.NewReader(` - a = 10 - b = 10 + int32 a = 10 + int32 b = 10 if a == b { - c = 10 + int32 c = 10 if c == 10 { - d = 1000 - e = 10 + int32 d = 1000 + int32 e = 10 } } store[0] = 20 store[a] = 20 + store[b] = this.caller() + + int8[10] ret + int8[10] arg + call(1234, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) From 35a82f8f4a69019d72ff3379e0f61bf2be475e42 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 7 Apr 2014 14:00:02 +0200 Subject: [PATCH 0205/1237] Added support for mneomnic privkeys --- ethutil/mnemonic.go | 1686 ++++++++++++++++++++++++++++++++++++++ ethutil/mnemonic_test.go | 74 ++ 2 files changed, 1760 insertions(+) create mode 100644 ethutil/mnemonic.go create mode 100644 ethutil/mnemonic_test.go diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go new file mode 100644 index 0000000000..d21c20f003 --- /dev/null +++ b/ethutil/mnemonic.go @@ -0,0 +1,1686 @@ +package ethutil + +import ( + "fmt" + "strconv" +) + +var words []string = []string{ + "like", + "just", + "love", + "know", + "never", + "want", + "time", + "out", + "there", + "make", + "look", + "eye", + "down", + "only", + "think", + "heart", + "back", + "then", + "into", + "about", + "more", + "away", + "still", + "them", + "take", + "thing", + "even", + "through", + "long", + "always", + "world", + "too", + "friend", + "tell", + "try", + "hand", + "thought", + "over", + "here", + "other", + "need", + "smile", + "again", + "much", + "cry", + "been", + "night", + "ever", + "little", + "said", + "end", + "some", + "those", + "around", + "mind", + "people", + "girl", + "leave", + "dream", + "left", + "turn", + "myself", + "give", + "nothing", + "really", + "off", + "before", + "something", + "find", + "walk", + "wish", + "good", + "once", + "place", + "ask", + "stop", + "keep", + "watch", + "seem", + "everything", + "wait", + "got", + "yet", + "made", + "remember", + "start", + "alone", + "run", + "hope", + "maybe", + "believe", + "body", + "hate", + "after", + "close", + "talk", + "stand", + "own", + "each", + "hurt", + "help", + "home", + "god", + "soul", + "new", + "many", + "two", + "inside", + "should", + "true", + "first", + "fear", + "mean", + "better", + "play", + "another", + "gone", + "change", + "use", + "wonder", + "someone", + "hair", + "cold", + "open", + "best", + "any", + "behind", + "happen", + "water", + "dark", + "laugh", + "stay", + "forever", + "name", + "work", + "show", + "sky", + "break", + "came", + "deep", + "door", + "put", + "black", + "together", + "upon", + "happy", + "such", + "great", + "white", + "matter", + "fill", + "past", + "please", + "burn", + "cause", + "enough", + "touch", + "moment", + "soon", + "voice", + "scream", + "anything", + "stare", + "sound", + "red", + "everyone", + "hide", + "kiss", + "truth", + "death", + "beautiful", + "mine", + "blood", + "broken", + "very", + "pass", + "next", + "forget", + "tree", + "wrong", + "air", + "mother", + "understand", + "lip", + "hit", + "wall", + "memory", + "sleep", + "free", + "high", + "realize", + "school", + "might", + "skin", + "sweet", + "perfect", + "blue", + "kill", + "breath", + "dance", + "against", + "fly", + "between", + "grow", + "strong", + "under", + "listen", + "bring", + "sometimes", + "speak", + "pull", + "person", + "become", + "family", + "begin", + "ground", + "real", + "small", + "father", + "sure", + "feet", + "rest", + "young", + "finally", + "land", + "across", + "today", + "different", + "guy", + "line", + "fire", + "reason", + "reach", + "second", + "slowly", + "write", + "eat", + "smell", + "mouth", + "step", + "learn", + "three", + "floor", + "promise", + "breathe", + "darkness", + "push", + "earth", + "guess", + "save", + "song", + "above", + "along", + "both", + "color", + "house", + "almost", + "sorry", + "anymore", + "brother", + "okay", + "dear", + "game", + "fade", + "already", + "apart", + "warm", + "beauty", + "heard", + "notice", + "question", + "shine", + "began", + "piece", + "whole", + "shadow", + "secret", + "street", + "within", + "finger", + "point", + "morning", + "whisper", + "child", + "moon", + "green", + "story", + "glass", + "kid", + "silence", + "since", + "soft", + "yourself", + "empty", + "shall", + "angel", + "answer", + "baby", + "bright", + "dad", + "path", + "worry", + "hour", + "drop", + "follow", + "power", + "war", + "half", + "flow", + "heaven", + "act", + "chance", + "fact", + "least", + "tired", + "children", + "near", + "quite", + "afraid", + "rise", + "sea", + "taste", + "window", + "cover", + "nice", + "trust", + "lot", + "sad", + "cool", + "force", + "peace", + "return", + "blind", + "easy", + "ready", + "roll", + "rose", + "drive", + "held", + "music", + "beneath", + "hang", + "mom", + "paint", + "emotion", + "quiet", + "clear", + "cloud", + "few", + "pretty", + "bird", + "outside", + "paper", + "picture", + "front", + "rock", + "simple", + "anyone", + "meant", + "reality", + "road", + "sense", + "waste", + "bit", + "leaf", + "thank", + "happiness", + "meet", + "men", + "smoke", + "truly", + "decide", + "self", + "age", + "book", + "form", + "alive", + "carry", + "escape", + "damn", + "instead", + "able", + "ice", + "minute", + "throw", + "catch", + "leg", + "ring", + "course", + "goodbye", + "lead", + "poem", + "sick", + "corner", + "desire", + "known", + "problem", + "remind", + "shoulder", + "suppose", + "toward", + "wave", + "drink", + "jump", + "woman", + "pretend", + "sister", + "week", + "human", + "joy", + "crack", + "grey", + "pray", + "surprise", + "dry", + "knee", + "less", + "search", + "bleed", + "caught", + "clean", + "embrace", + "future", + "king", + "son", + "sorrow", + "chest", + "hug", + "remain", + "sat", + "worth", + "blow", + "daddy", + "final", + "parent", + "tight", + "also", + "create", + "lonely", + "safe", + "cross", + "dress", + "evil", + "silent", + "bone", + "fate", + "perhaps", + "anger", + "class", + "scar", + "snow", + "tiny", + "tonight", + "continue", + "control", + "dog", + "edge", + "mirror", + "month", + "suddenly", + "comfort", + "given", + "loud", + "quickly", + "gaze", + "plan", + "rush", + "stone", + "town", + "battle", + "ignore", + "spirit", + "stood", + "stupid", + "yours", + "brown", + "build", + "dust", + "hey", + "kept", + "pay", + "phone", + "twist", + "although", + "ball", + "beyond", + "hidden", + "nose", + "taken", + "fail", + "float", + "pure", + "somehow", + "wash", + "wrap", + "angry", + "cheek", + "creature", + "forgotten", + "heat", + "rip", + "single", + "space", + "special", + "weak", + "whatever", + "yell", + "anyway", + "blame", + "job", + "choose", + "country", + "curse", + "drift", + "echo", + "figure", + "grew", + "laughter", + "neck", + "suffer", + "worse", + "yeah", + "disappear", + "foot", + "forward", + "knife", + "mess", + "somewhere", + "stomach", + "storm", + "beg", + "idea", + "lift", + "offer", + "breeze", + "field", + "five", + "often", + "simply", + "stuck", + "win", + "allow", + "confuse", + "enjoy", + "except", + "flower", + "seek", + "strength", + "calm", + "grin", + "gun", + "heavy", + "hill", + "large", + "ocean", + "shoe", + "sigh", + "straight", + "summer", + "tongue", + "accept", + "crazy", + "everyday", + "exist", + "grass", + "mistake", + "sent", + "shut", + "surround", + "table", + "ache", + "brain", + "destroy", + "heal", + "nature", + "shout", + "sign", + "stain", + "choice", + "doubt", + "glance", + "glow", + "mountain", + "queen", + "stranger", + "throat", + "tomorrow", + "city", + "either", + "fish", + "flame", + "rather", + "shape", + "spin", + "spread", + "ash", + "distance", + "finish", + "image", + "imagine", + "important", + "nobody", + "shatter", + "warmth", + "became", + "feed", + "flesh", + "funny", + "lust", + "shirt", + "trouble", + "yellow", + "attention", + "bare", + "bite", + "money", + "protect", + "amaze", + "appear", + "born", + "choke", + "completely", + "daughter", + "fresh", + "friendship", + "gentle", + "probably", + "six", + "deserve", + "expect", + "grab", + "middle", + "nightmare", + "river", + "thousand", + "weight", + "worst", + "wound", + "barely", + "bottle", + "cream", + "regret", + "relationship", + "stick", + "test", + "crush", + "endless", + "fault", + "itself", + "rule", + "spill", + "art", + "circle", + "join", + "kick", + "mask", + "master", + "passion", + "quick", + "raise", + "smooth", + "unless", + "wander", + "actually", + "broke", + "chair", + "deal", + "favorite", + "gift", + "note", + "number", + "sweat", + "box", + "chill", + "clothes", + "lady", + "mark", + "park", + "poor", + "sadness", + "tie", + "animal", + "belong", + "brush", + "consume", + "dawn", + "forest", + "innocent", + "pen", + "pride", + "stream", + "thick", + "clay", + "complete", + "count", + "draw", + "faith", + "press", + "silver", + "struggle", + "surface", + "taught", + "teach", + "wet", + "bless", + "chase", + "climb", + "enter", + "letter", + "melt", + "metal", + "movie", + "stretch", + "swing", + "vision", + "wife", + "beside", + "crash", + "forgot", + "guide", + "haunt", + "joke", + "knock", + "plant", + "pour", + "prove", + "reveal", + "steal", + "stuff", + "trip", + "wood", + "wrist", + "bother", + "bottom", + "crawl", + "crowd", + "fix", + "forgive", + "frown", + "grace", + "loose", + "lucky", + "party", + "release", + "surely", + "survive", + "teacher", + "gently", + "grip", + "speed", + "suicide", + "travel", + "treat", + "vein", + "written", + "cage", + "chain", + "conversation", + "date", + "enemy", + "however", + "interest", + "million", + "page", + "pink", + "proud", + "sway", + "themselves", + "winter", + "church", + "cruel", + "cup", + "demon", + "experience", + "freedom", + "pair", + "pop", + "purpose", + "respect", + "shoot", + "softly", + "state", + "strange", + "bar", + "birth", + "curl", + "dirt", + "excuse", + "lord", + "lovely", + "monster", + "order", + "pack", + "pants", + "pool", + "scene", + "seven", + "shame", + "slide", + "ugly", + "among", + "blade", + "blonde", + "closet", + "creek", + "deny", + "drug", + "eternity", + "gain", + "grade", + "handle", + "key", + "linger", + "pale", + "prepare", + "swallow", + "swim", + "tremble", + "wheel", + "won", + "cast", + "cigarette", + "claim", + "college", + "direction", + "dirty", + "gather", + "ghost", + "hundred", + "loss", + "lung", + "orange", + "present", + "swear", + "swirl", + "twice", + "wild", + "bitter", + "blanket", + "doctor", + "everywhere", + "flash", + "grown", + "knowledge", + "numb", + "pressure", + "radio", + "repeat", + "ruin", + "spend", + "unknown", + "buy", + "clock", + "devil", + "early", + "false", + "fantasy", + "pound", + "precious", + "refuse", + "sheet", + "teeth", + "welcome", + "add", + "ahead", + "block", + "bury", + "caress", + "content", + "depth", + "despite", + "distant", + "marry", + "purple", + "threw", + "whenever", + "bomb", + "dull", + "easily", + "grasp", + "hospital", + "innocence", + "normal", + "receive", + "reply", + "rhyme", + "shade", + "someday", + "sword", + "toe", + "visit", + "asleep", + "bought", + "center", + "consider", + "flat", + "hero", + "history", + "ink", + "insane", + "muscle", + "mystery", + "pocket", + "reflection", + "shove", + "silently", + "smart", + "soldier", + "spot", + "stress", + "train", + "type", + "view", + "whether", + "bus", + "energy", + "explain", + "holy", + "hunger", + "inch", + "magic", + "mix", + "noise", + "nowhere", + "prayer", + "presence", + "shock", + "snap", + "spider", + "study", + "thunder", + "trail", + "admit", + "agree", + "bag", + "bang", + "bound", + "butterfly", + "cute", + "exactly", + "explode", + "familiar", + "fold", + "further", + "pierce", + "reflect", + "scent", + "selfish", + "sharp", + "sink", + "spring", + "stumble", + "universe", + "weep", + "women", + "wonderful", + "action", + "ancient", + "attempt", + "avoid", + "birthday", + "branch", + "chocolate", + "core", + "depress", + "drunk", + "especially", + "focus", + "fruit", + "honest", + "match", + "palm", + "perfectly", + "pillow", + "pity", + "poison", + "roar", + "shift", + "slightly", + "thump", + "truck", + "tune", + "twenty", + "unable", + "wipe", + "wrote", + "coat", + "constant", + "dinner", + "drove", + "egg", + "eternal", + "flight", + "flood", + "frame", + "freak", + "gasp", + "glad", + "hollow", + "motion", + "peer", + "plastic", + "root", + "screen", + "season", + "sting", + "strike", + "team", + "unlike", + "victim", + "volume", + "warn", + "weird", + "attack", + "await", + "awake", + "built", + "charm", + "crave", + "despair", + "fought", + "grant", + "grief", + "horse", + "limit", + "message", + "ripple", + "sanity", + "scatter", + "serve", + "split", + "string", + "trick", + "annoy", + "blur", + "boat", + "brave", + "clearly", + "cling", + "connect", + "fist", + "forth", + "imagination", + "iron", + "jock", + "judge", + "lesson", + "milk", + "misery", + "nail", + "naked", + "ourselves", + "poet", + "possible", + "princess", + "sail", + "size", + "snake", + "society", + "stroke", + "torture", + "toss", + "trace", + "wise", + "bloom", + "bullet", + "cell", + "check", + "cost", + "darling", + "during", + "footstep", + "fragile", + "hallway", + "hardly", + "horizon", + "invisible", + "journey", + "midnight", + "mud", + "nod", + "pause", + "relax", + "shiver", + "sudden", + "value", + "youth", + "abuse", + "admire", + "blink", + "breast", + "bruise", + "constantly", + "couple", + "creep", + "curve", + "difference", + "dumb", + "emptiness", + "gotta", + "honor", + "plain", + "planet", + "recall", + "rub", + "ship", + "slam", + "soar", + "somebody", + "tightly", + "weather", + "adore", + "approach", + "bond", + "bread", + "burst", + "candle", + "coffee", + "cousin", + "crime", + "desert", + "flutter", + "frozen", + "grand", + "heel", + "hello", + "language", + "level", + "movement", + "pleasure", + "powerful", + "random", + "rhythm", + "settle", + "silly", + "slap", + "sort", + "spoken", + "steel", + "threaten", + "tumble", + "upset", + "aside", + "awkward", + "bee", + "blank", + "board", + "button", + "card", + "carefully", + "complain", + "crap", + "deeply", + "discover", + "drag", + "dread", + "effort", + "entire", + "fairy", + "giant", + "gotten", + "greet", + "illusion", + "jeans", + "leap", + "liquid", + "march", + "mend", + "nervous", + "nine", + "replace", + "rope", + "spine", + "stole", + "terror", + "accident", + "apple", + "balance", + "boom", + "childhood", + "collect", + "demand", + "depression", + "eventually", + "faint", + "glare", + "goal", + "group", + "honey", + "kitchen", + "laid", + "limb", + "machine", + "mere", + "mold", + "murder", + "nerve", + "painful", + "poetry", + "prince", + "rabbit", + "shelter", + "shore", + "shower", + "soothe", + "stair", + "steady", + "sunlight", + "tangle", + "tease", + "treasure", + "uncle", + "begun", + "bliss", + "canvas", + "cheer", + "claw", + "clutch", + "commit", + "crimson", + "crystal", + "delight", + "doll", + "existence", + "express", + "fog", + "football", + "gay", + "goose", + "guard", + "hatred", + "illuminate", + "mass", + "math", + "mourn", + "rich", + "rough", + "skip", + "stir", + "student", + "style", + "support", + "thorn", + "tough", + "yard", + "yearn", + "yesterday", + "advice", + "appreciate", + "autumn", + "bank", + "beam", + "bowl", + "capture", + "carve", + "collapse", + "confusion", + "creation", + "dove", + "feather", + "girlfriend", + "glory", + "government", + "harsh", + "hop", + "inner", + "loser", + "moonlight", + "neighbor", + "neither", + "peach", + "pig", + "praise", + "screw", + "shield", + "shimmer", + "sneak", + "stab", + "subject", + "throughout", + "thrown", + "tower", + "twirl", + "wow", + "army", + "arrive", + "bathroom", + "bump", + "cease", + "cookie", + "couch", + "courage", + "dim", + "guilt", + "howl", + "hum", + "husband", + "insult", + "led", + "lunch", + "mock", + "mostly", + "natural", + "nearly", + "needle", + "nerd", + "peaceful", + "perfection", + "pile", + "price", + "remove", + "roam", + "sanctuary", + "serious", + "shiny", + "shook", + "sob", + "stolen", + "tap", + "vain", + "void", + "warrior", + "wrinkle", + "affection", + "apologize", + "blossom", + "bounce", + "bridge", + "cheap", + "crumble", + "decision", + "descend", + "desperately", + "dig", + "dot", + "flip", + "frighten", + "heartbeat", + "huge", + "lazy", + "lick", + "odd", + "opinion", + "process", + "puzzle", + "quietly", + "retreat", + "score", + "sentence", + "separate", + "situation", + "skill", + "soak", + "square", + "stray", + "taint", + "task", + "tide", + "underneath", + "veil", + "whistle", + "anywhere", + "bedroom", + "bid", + "bloody", + "burden", + "careful", + "compare", + "concern", + "curtain", + "decay", + "defeat", + "describe", + "double", + "dreamer", + "driver", + "dwell", + "evening", + "flare", + "flicker", + "grandma", + "guitar", + "harm", + "horrible", + "hungry", + "indeed", + "lace", + "melody", + "monkey", + "nation", + "object", + "obviously", + "rainbow", + "salt", + "scratch", + "shown", + "shy", + "stage", + "stun", + "third", + "tickle", + "useless", + "weakness", + "worship", + "worthless", + "afternoon", + "beard", + "boyfriend", + "bubble", + "busy", + "certain", + "chin", + "concrete", + "desk", + "diamond", + "doom", + "drawn", + "due", + "felicity", + "freeze", + "frost", + "garden", + "glide", + "harmony", + "hopefully", + "hunt", + "jealous", + "lightning", + "mama", + "mercy", + "peel", + "physical", + "position", + "pulse", + "punch", + "quit", + "rant", + "respond", + "salty", + "sane", + "satisfy", + "savior", + "sheep", + "slept", + "social", + "sport", + "tuck", + "utter", + "valley", + "wolf", + "aim", + "alas", + "alter", + "arrow", + "awaken", + "beaten", + "belief", + "brand", + "ceiling", + "cheese", + "clue", + "confidence", + "connection", + "daily", + "disguise", + "eager", + "erase", + "essence", + "everytime", + "expression", + "fan", + "flag", + "flirt", + "foul", + "fur", + "giggle", + "glorious", + "ignorance", + "law", + "lifeless", + "measure", + "mighty", + "muse", + "north", + "opposite", + "paradise", + "patience", + "patient", + "pencil", + "petal", + "plate", + "ponder", + "possibly", + "practice", + "slice", + "spell", + "stock", + "strife", + "strip", + "suffocate", + "suit", + "tender", + "tool", + "trade", + "velvet", + "verse", + "waist", + "witch", + "aunt", + "bench", + "bold", + "cap", + "certainly", + "click", + "companion", + "creator", + "dart", + "delicate", + "determine", + "dish", + "dragon", + "drama", + "drum", + "dude", + "everybody", + "feast", + "forehead", + "former", + "fright", + "fully", + "gas", + "hook", + "hurl", + "invite", + "juice", + "manage", + "moral", + "possess", + "raw", + "rebel", + "royal", + "scale", + "scary", + "several", + "slight", + "stubborn", + "swell", + "talent", + "tea", + "terrible", + "thread", + "torment", + "trickle", + "usually", + "vast", + "violence", + "weave", + "acid", + "agony", + "ashamed", + "awe", + "belly", + "blend", + "blush", + "character", + "cheat", + "common", + "company", + "coward", + "creak", + "danger", + "deadly", + "defense", + "define", + "depend", + "desperate", + "destination", + "dew", + "duck", + "dusty", + "embarrass", + "engine", + "example", + "explore", + "foe", + "freely", + "frustrate", + "generation", + "glove", + "guilty", + "health", + "hurry", + "idiot", + "impossible", + "inhale", + "jaw", + "kingdom", + "mention", + "mist", + "moan", + "mumble", + "mutter", + "observe", + "ode", + "pathetic", + "pattern", + "pie", + "prefer", + "puff", + "rape", + "rare", + "revenge", + "rude", + "scrape", + "spiral", + "squeeze", + "strain", + "sunset", + "suspend", + "sympathy", + "thigh", + "throne", + "total", + "unseen", + "weapon", + "weary", +} + +var n int64 = 1626 + +func IndexOf(slice []string, value string) int64 { + for p, v := range slice { + if v == value { + return int64(p) + } + } + return -1 +} + +func MnemonicEncode(message string) []string { + var out []string + + for i := 0; i < len(message); i += (len(message) / 8) { + x := message[i : i+8] + bit, _ := strconv.ParseInt(x, 16, 64) + w1 := (bit % n) + w2 := ((bit / n) + w1) % n + w3 := ((bit / n / n) + w2) % n + out = append(out, words[w1], words[w2], words[w3]) + } + return out +} + +func MnemonicDecode(wordsar []string) string { + var out string + for i := 0; i < len(wordsar); i += 3 { + word1 := wordsar[i] + word2 := wordsar[i+1] + word3 := wordsar[i+2] + w1 := IndexOf(words, word1) + w2 := IndexOf(words, word2) + w3 := IndexOf(words, word3) + + y := (w2 - w1) % n + z := (w3 - w2) % n + + // Golang handles modulo with negative numbers different then most languages + if z < 0 { + z += n + } + if y < 0 { + y += n + } + x := w1 + n*(y) + n*n*(z) + out += fmt.Sprintf("%08x", x) + } + return out +} diff --git a/ethutil/mnemonic_test.go b/ethutil/mnemonic_test.go new file mode 100644 index 0000000000..ccf3f98831 --- /dev/null +++ b/ethutil/mnemonic_test.go @@ -0,0 +1,74 @@ +package ethutil + +import ( + "testing" +) + +func TestMnDecode(t *testing.T) { + words := []string{ + "ink", + "balance", + "gain", + "fear", + "happen", + "melt", + "mom", + "surface", + "stir", + "bottle", + "unseen", + "expression", + "important", + "curl", + "grant", + "fairy", + "across", + "back", + "figure", + "breast", + "nobody", + "scratch", + "worry", + "yesterday", + } + encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" + result := MnemonicDecode(words) + if encode != result { + t.Error("We expected", encode, "got", result, "instead") + } +} +func TestMnEncode(t *testing.T) { + encode := "c61d43dc5bb7a4e754d111dae8105b6f25356492df5e50ecb33b858d94f8c338" + result := []string{ + "ink", + "balance", + "gain", + "fear", + "happen", + "melt", + "mom", + "surface", + "stir", + "bottle", + "unseen", + "expression", + "important", + "curl", + "grant", + "fairy", + "across", + "back", + "figure", + "breast", + "nobody", + "scratch", + "worry", + "yesterday", + } + words := MnemonicEncode(encode) + for i, word := range words { + if word != result[i] { + t.Error("Mnenonic does not match:", words, result) + } + } +} From c0a030ef0a3ce8342fda2a53cdafd50a271b4837 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 14:08:18 +0200 Subject: [PATCH 0206/1237] Added new insruction methods --- ethchain/closure.go | 5 +++++ ethchain/contract.go | 9 +++++++++ ethchain/vm.go | 26 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 2e809aa9dc..e9cb2c8bc1 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -17,6 +17,7 @@ type ClosureBody interface { ethutil.RlpEncodable GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) + GetInstr(*big.Int) *ethutil.Value } // Basic inline closure object which implement the 'closure' interface @@ -46,6 +47,10 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value { return m } +func (c *Closure) GetInstr(x *big.Int) *ethutil.Value { + return c.object.GetInstr(x) +} + func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { c.object.SetMem(x, val) } diff --git a/ethchain/contract.go b/ethchain/contract.go index f7ae017534..f68dcf3677 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -11,6 +11,7 @@ type Contract struct { //state *ethutil.Trie state *State address []byte + script []byte } func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { @@ -45,6 +46,14 @@ func (c *Contract) GetMem(num *big.Int) *ethutil.Value { return c.Addr(nb) } +func (c *Contract) GetInstr(pc *big.Int) *ethutil.Value { + if int64(len(c.script)-1) < pc.Int64() { + return ethutil.NewValue(0) + } + + return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) +} + func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.state.trie.Update(string(addr), string(val.Encode())) diff --git a/ethchain/vm.go b/ethchain/vm.go index 98aaa603ad..b4b2177bfb 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -72,7 +72,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { for { step++ // Get the memory location of pc - val := closure.GetMem(pc) + val := closure.GetInstr(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) if ethutil.Config.Debug { @@ -233,13 +233,37 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x10 range case oAND: + x, y := stack.Popn() + if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case oOR: + x, y := stack.Popn() + if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } case oXOR: + x, y := stack.Popn() + stack.Push(base.Xor(x, y)) case oBYTE: + val, th := stack.Popn() + if th.Cmp(big.NewInt(32)) < 0 { + stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) + } else { + stack.Push(ethutil.BigFalse) + } // 0x20 range case oSHA3: + size, offset := stack.Popn() + data := mem.Get(offset.Int64(), size.Int64()) + stack.Push(ethutil.BigD(data)) // 0x30 range case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) From 527a3bbc2aa9cfd26bd8419d33b50adef536067d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 14:53:20 +0200 Subject: [PATCH 0207/1237] Typo fix --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index a6265afd68..849909677a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -108,7 +108,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce) + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) } // Get the receiver From b66a99e32dd51ddd66a81141a9a37f93144935bd Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 08:55:39 -0400 Subject: [PATCH 0208/1237] Added todo --- ethchain/block_chain.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index f621965ae0..2a50ef6873 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -169,6 +169,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockHash = bc.genesisBlock.Hash() bc.LastBlockNumber = 1 } else { + // TODO: Somehow this doesn't really give the right numbers, double check. + // TODO: Change logs into debug lines returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() From 035f0ffb8ac95faa1742c0575cc9b5409ec54379 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 15:08:10 +0200 Subject: [PATCH 0209/1237] Reverted changes --- ethchain/state_manager.go | 4 ++-- ethchain/transaction_pool.go | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4b0ea25158..c33ba92725 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,12 +114,12 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // contract instead of moving funds between accounts. var err error if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, true) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) if err == nil { sm.ProcessContract(contract, tx, block) } } else { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, sm.procState, false) + err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) } if err != nil { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 849909677a..0bcfe69234 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -90,7 +90,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { defer func() { if r := recover(); r != nil { log.Println(r) @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } }() // Get the sender - sender := state.GetAccount(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. @@ -112,7 +112,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract } // Get the receiver - receiver := state.GetAccount(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -128,10 +128,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract // Add the amount to receivers account which should conclude this transaction receiver.Amount.Add(receiver.Amount, tx.Value) - state.UpdateAccount(tx.Recipient, receiver) + block.state.UpdateAccount(tx.Recipient, receiver) } - state.UpdateAccount(tx.Sender(), sender) + block.state.UpdateAccount(tx.Sender(), sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) From a83db489dfddb16786b1de3d28aee4a4af9e12d5 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 09:48:17 -0400 Subject: [PATCH 0210/1237] Fix transaction on new blocks --- ethminer/miner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethminer/miner.go b/ethminer/miner.go index 60af3ab319..d849773420 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -105,6 +105,7 @@ func (miner *Miner) listener() { if found == false { log.Println("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block.SetTransactions(miner.txs) } else { log.Println("[MINER] We already had this transaction, ignoring") From 6d28bf534f0fabb5740ef035b829e5edc4dc3131 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 16:00:28 +0200 Subject: [PATCH 0211/1237] Added a length for copy --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c33ba92725..4c001a387b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -288,7 +288,7 @@ func (sm *StateManager) AccumelateRewards(block *Block) error { // Reward amount of ether to the coinbase address addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) - var acc []byte + acc := make([]byte, len(block.Coinbase)) copy(acc, block.Coinbase) sm.procState.UpdateAccount(acc, addr) From 03e139d23b4350172b69d81c2c5690d0da282fb7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 16:04:36 +0200 Subject: [PATCH 0212/1237] Switched variable names --- ethchain/state_manager.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4c001a387b..0f8ef19a74 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -284,13 +284,13 @@ func CalculateUncleReward(block *Block) *big.Int { func (sm *StateManager) AccumelateRewards(block *Block) error { // Get the coinbase rlp data - addr := sm.procState.GetAccount(block.Coinbase) + acc := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address - addr.AddFee(CalculateBlockReward(block, len(block.Uncles))) + acc.AddFee(CalculateBlockReward(block, len(block.Uncles))) - acc := make([]byte, len(block.Coinbase)) - copy(acc, block.Coinbase) - sm.procState.UpdateAccount(acc, addr) + addr := make([]byte, len(block.Coinbase)) + copy(addr, block.Coinbase) + sm.procState.UpdateAccount(addr, acc) for _, uncle := range block.Uncles { uncleAddr := sm.procState.GetAccount(uncle.Coinbase) From 272b135b74931fd159d4e50a2328ea32a73f787c Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 10:40:55 -0400 Subject: [PATCH 0213/1237] One more line of comment --- ethutil/mnemonic.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go index d21c20f003..cc58de84a0 100644 --- a/ethutil/mnemonic.go +++ b/ethutil/mnemonic.go @@ -5,6 +5,7 @@ import ( "strconv" ) +// Electrum word list var words []string = []string{ "like", "just", @@ -1673,6 +1674,7 @@ func MnemonicDecode(wordsar []string) string { z := (w3 - w2) % n // Golang handles modulo with negative numbers different then most languages + // The modulo can be negative, we don't want that. if z < 0 { z += n } From 5714a82778c688a332f4b42bee28e99fb2b30e0b Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 9 Apr 2014 11:06:30 -0400 Subject: [PATCH 0214/1237] Small tweaks to mnemonic --- ethutil/mnemonic.go | 106 ++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go index cc58de84a0..00f089e3bf 100644 --- a/ethutil/mnemonic.go +++ b/ethutil/mnemonic.go @@ -5,6 +5,60 @@ import ( "strconv" ) +// 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 { + for p, v := range slice { + if v == value { + return int64(p) + } + } + return -1 +} + +func MnemonicEncode(message string) []string { + var out []string + n := int64(len(words)) + + for i := 0; i < len(message); i += (len(message) / 8) { + x := message[i : i+8] + bit, _ := strconv.ParseInt(x, 16, 64) + w1 := (bit % n) + w2 := ((bit / n) + w1) % n + w3 := ((bit / n / n) + w2) % n + out = append(out, words[w1], words[w2], words[w3]) + } + return out +} + +func MnemonicDecode(wordsar []string) string { + var out string + n := int64(len(words)) + + for i := 0; i < len(wordsar); i += 3 { + word1 := wordsar[i] + word2 := wordsar[i+1] + word3 := wordsar[i+2] + w1 := IndexOf(words, word1) + w2 := IndexOf(words, word2) + w3 := IndexOf(words, word3) + + y := (w2 - w1) % n + z := (w3 - w2) % n + + // Golang handles modulo with negative numbers different then most languages + // The modulo can be negative, we don't want that. + if z < 0 { + z += n + } + if y < 0 { + y += n + } + x := w1 + n*(y) + n*n*(z) + out += fmt.Sprintf("%08x", x) + } + return out +} + // Electrum word list var words []string = []string{ "like", @@ -1634,55 +1688,3 @@ var words []string = []string{ "weapon", "weary", } - -var n int64 = 1626 - -func IndexOf(slice []string, value string) int64 { - for p, v := range slice { - if v == value { - return int64(p) - } - } - return -1 -} - -func MnemonicEncode(message string) []string { - var out []string - - for i := 0; i < len(message); i += (len(message) / 8) { - x := message[i : i+8] - bit, _ := strconv.ParseInt(x, 16, 64) - w1 := (bit % n) - w2 := ((bit / n) + w1) % n - w3 := ((bit / n / n) + w2) % n - out = append(out, words[w1], words[w2], words[w3]) - } - return out -} - -func MnemonicDecode(wordsar []string) string { - var out string - for i := 0; i < len(wordsar); i += 3 { - word1 := wordsar[i] - word2 := wordsar[i+1] - word3 := wordsar[i+2] - w1 := IndexOf(words, word1) - w2 := IndexOf(words, word2) - w3 := IndexOf(words, word3) - - y := (w2 - w1) % n - z := (w3 - w2) % n - - // Golang handles modulo with negative numbers different then most languages - // The modulo can be negative, we don't want that. - if z < 0 { - z += n - } - if y < 0 { - y += n - } - x := w1 + n*(y) + n*n*(z) - out += fmt.Sprintf("%08x", x) - } - return out -} From 4f2e9c2640eaa962d085db329221bfd6f1a1799e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:27:25 -0400 Subject: [PATCH 0215/1237] Check for nil --- ethutil/rlp.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index e6c75696ee..d95ace4251 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -186,7 +186,12 @@ func Encode(object interface{}) []byte { case byte: buff.Write(Encode(big.NewInt(int64(t)))) case *big.Int: - buff.Write(Encode(t.Bytes())) + // Not sure how this is possible while we check for + if t == nil { + buff.WriteByte(0xc0) + } else { + buff.Write(Encode(t.Bytes())) + } case []byte: if len(t) == 1 && t[0] <= 0x7f { buff.Write(t) From e09f0a5f2c1e1b46226656dbac9a4ae10e0dcd14 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:27:54 -0400 Subject: [PATCH 0216/1237] Split code for contracts --- ethchain/closure.go | 22 ++++++++++++++-------- ethchain/contract.go | 22 ++++++++++++++-------- ethchain/state_manager.go | 2 +- ethchain/vm.go | 4 ++-- ethchain/vm_test.go | 3 ++- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index e9cb2c8bc1..d1fac0f43b 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -12,18 +12,18 @@ type Callee interface { Address() []byte } -type ClosureBody interface { +type Reference interface { Callee ethutil.RlpEncodable GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) - GetInstr(*big.Int) *ethutil.Value } // Basic inline closure object which implement the 'closure' interface type Closure struct { callee Callee - object ClosureBody + object Reference + Script []byte State *State Gas *big.Int @@ -33,8 +33,8 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, state, gas, val, nil} +func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { + return &Closure{callee, object, script, state, gas, val, nil} } // Retuns the x element in data slice @@ -47,8 +47,14 @@ func (c *Closure) GetMem(x *big.Int) *ethutil.Value { return m } -func (c *Closure) GetInstr(x *big.Int) *ethutil.Value { - return c.object.GetInstr(x) +func (c *Closure) Get(x *big.Int) *ethutil.Value { + return c.Gets(x, big.NewInt(1)) +} + +func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { + partial := c.Script[x.Int64() : x.Int64()+y.Int64()] + + return ethutil.NewValue(partial) } func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { @@ -86,7 +92,7 @@ func (c *Closure) ReturnGas(gas *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() ClosureBody { +func (c *Closure) Object() Reference { return c.object } diff --git a/ethchain/contract.go b/ethchain/contract.go index f68dcf3677..113d067a43 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -9,9 +9,10 @@ type Contract struct { Amount *big.Int Nonce uint64 //state *ethutil.Trie - state *State - address []byte - script []byte + state *State + address []byte + script []byte + initScript []byte } func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { @@ -88,12 +89,17 @@ func MakeContract(tx *Transaction, state *State) *Contract { value := tx.Value contract := NewContract(addr, value, []byte("")) state.trie.Update(string(addr), string(contract.RlpEncode())) - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) + contract.script = tx.Data + contract.initScript = tx.Init + + /* + for i, val := range tx.Data { + if len(val) > 0 { + bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) + contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) + } } - } + */ state.trie.Update(string(addr), string(contract.RlpEncode())) return contract diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 95e46e41d5..7a2a762b29 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -311,7 +311,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ origin: caller.Address(), blockNumber: block.BlockInfo().Number, diff --git a/ethchain/vm.go b/ethchain/vm.go index b4b2177bfb..a6a02dc9f6 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -72,7 +72,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { for { step++ // Get the memory location of pc - val := closure.GetInstr(pc) + val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) if ethutil.Config.Debug { @@ -357,7 +357,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure - closure := NewClosure(closure, contract, vm.state, gas, value) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) ret := closure.Call(vm, args) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 85ec4c6935..745005b099 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -112,7 +112,8 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) - callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) + c := MakeContract(callerTx, state) + callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ origin: account.Address(), From 720521ed4a28c8a1b74bedd03e82bf4f887c9cb5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:28:16 -0400 Subject: [PATCH 0217/1237] Changed how txs define their data & added init field --- ethchain/transaction.go | 66 ++++++++++++++---------------------- ethchain/transaction_test.go | 53 ----------------------------- 2 files changed, 25 insertions(+), 94 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 506e3c159a..b359c9151c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -14,7 +14,8 @@ type Transaction struct { Value *big.Int Gas *big.Int Gasprice *big.Int - Data []string + Data []byte + Init []byte v byte r, s []byte @@ -22,11 +23,11 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, data []string) *Transaction { +func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction { return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} } -func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []string) *Transaction { +func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} } @@ -45,19 +46,12 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := make([]interface{}, len(tx.Data)) - for i, val := range tx.Data { - data[i] = val + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, string(tx.Data)} + if tx.contractCreation { + data = append(data, string(tx.Init)) } - preEnc := []interface{}{ - tx.Nonce, - tx.Recipient, - tx.Value, - data, - } - - return ethutil.Sha3Bin(ethutil.Encode(preEnc)) + return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } func (tx *Transaction) IsContract() bool { @@ -110,15 +104,17 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } +// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] +// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice} + data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, tx.Data} - if !tx.contractCreation { - data = append(data, tx.Recipient, tx.Gas) + if tx.contractCreation { + data = append(data, tx.Init) } - d := ethutil.NewSliceValue(tx.Data).Slice() + //d := ethutil.NewSliceValue(tx.Data).Slice() - return append(data, d, tx.v, tx.r, tx.s) + return append(data, tx.v, tx.r, tx.s) } func (tx *Transaction) RlpValue() *ethutil.Value { @@ -137,31 +133,19 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() tx.Gasprice = decoder.Get(2).BigInt() + tx.Gas = decoder.Get(3).BigInt() + tx.Recipient = decoder.Get(4).Bytes() + tx.Data = decoder.Get(5).Bytes() - // If the 4th item is a list(slice) this tx - // is a contract creation tx - if decoder.Get(3).IsList() { - d := decoder.Get(3) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() - } - - tx.v = byte(decoder.Get(4).Uint()) - tx.r = decoder.Get(5).Bytes() - tx.s = decoder.Get(6).Bytes() - + // If the list is of length 10 it's a contract creation tx + if decoder.Len() == 10 { tx.contractCreation = true + tx.Init = decoder.Get(6).Bytes() + + tx.v = byte(decoder.Get(7).Uint()) + tx.r = decoder.Get(8).Bytes() + tx.s = decoder.Get(9).Bytes() } else { - tx.Recipient = decoder.Get(3).Bytes() - tx.Gas = decoder.Get(4).BigInt() - - d := decoder.Get(5) - tx.Data = make([]string, d.Len()) - for i := 0; i < d.Len(); i++ { - tx.Data[i] = d.Get(i).Str() - } - tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() diff --git a/ethchain/transaction_test.go b/ethchain/transaction_test.go index a49768aea2..3603fd8a78 100644 --- a/ethchain/transaction_test.go +++ b/ethchain/transaction_test.go @@ -1,54 +1 @@ package ethchain - -import ( - "encoding/hex" - "math/big" - "testing" -) - -func TestAddressRetrieval(t *testing.T) { - // TODO - // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f - key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") - - tx := &Transaction{ - Nonce: 0, - Recipient: ZeroHash160, - Value: big.NewInt(0), - Data: nil, - } - //fmt.Printf("rlp %x\n", tx.RlpEncode()) - //fmt.Printf("sha rlp %x\n", tx.Hash()) - - tx.Sign(key) - - //fmt.Printf("hex tx key %x\n", tx.PublicKey()) - //fmt.Printf("seder %x\n", tx.Sender()) -} - -func TestAddressRetrieval2(t *testing.T) { - // TODO - // 88f9b82462f6c4bf4a0fb15e5c3971559a316e7f - key, _ := hex.DecodeString("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4") - addr, _ := hex.DecodeString("944400f4b88ac9589a0f17ed4671da26bddb668b") - tx := &Transaction{ - Nonce: 0, - Recipient: addr, - Value: big.NewInt(1000), - Data: nil, - } - tx.Sign(key) - //data, _ := hex.DecodeString("f85d8094944400f4b88ac9589a0f17ed4671da26bddb668b8203e8c01ca0363b2a410de00bc89be40f468d16e70e543b72191fbd8a684a7c5bef51dc451fa02d8ecf40b68f9c64ed623f6ee24c9c878943b812e1e76bd73ccb2bfef65579e7") - //tx := NewTransactionFromData(data) - /* - fmt.Println(tx.RlpValue()) - - fmt.Printf("rlp %x\n", tx.RlpEncode()) - fmt.Printf("sha rlp %x\n", tx.Hash()) - - //tx.Sign(key) - - fmt.Printf("hex tx key %x\n", tx.PublicKey()) - fmt.Printf("seder %x\n", tx.Sender()) - */ -} From 0fccbeabcc3b8c110ce3712e5488ad99245f92ee Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 9 Apr 2014 12:28:34 -0400 Subject: [PATCH 0218/1237] No longer return a list, but raw bytes --- ethutil/parsing.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 16ed2d06db..a9d50e4252 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -131,13 +131,14 @@ func Instr(instr string) (int, []string, error) { // Script compilation functions // Compiles strings to machine code -func Assemble(instructions ...interface{}) (script []string) { - script = make([]string, len(instructions)) +func Assemble(instructions ...interface{}) (script []byte) { + //script = make([]string, len(instructions)) - for i, val := range instructions { + for _, val := range instructions { instr, _ := CompileInstr(val) - script[i] = string(instr) + //script[i] = string(instr) + script = append(script, instr...) } return From 6a530ea3717e592407737c6cd2ebeba0200c9cd8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 14:40:12 -0400 Subject: [PATCH 0219/1237] Call fixed --- ethchain/closure.go | 4 ++++ ethchain/contract.go | 4 +++- ethchain/vm.go | 30 ++++++++++++++++++------------ ethchain/vm_test.go | 23 ++++++++++++++++++++--- ethutil/parsing.go | 28 +++++++--------------------- 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index d1fac0f43b..8e57a0d03f 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -52,6 +52,10 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value { } func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { + if x.Int64() > int64(len(c.Script)) || y.Int64() > int64(len(c.Script)) { + return ethutil.NewValue(0) + } + partial := c.Script[x.Int64() : x.Int64()+y.Int64()] return ethutil.NewValue(partial) diff --git a/ethchain/contract.go b/ethchain/contract.go index 113d067a43..e99e413f7a 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -70,7 +70,7 @@ func (c *Contract) Address() []byte { } func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root}) + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) } func (c *Contract) RlpDecode(data []byte) { @@ -79,6 +79,8 @@ func (c *Contract) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.script = decoder.Get(3).Bytes() + c.initScript = decoder.Get(4).Bytes() } func MakeContract(tx *Transaction, state *State) *Contract { diff --git a/ethchain/vm.go b/ethchain/vm.go index a6a02dc9f6..f94425d2d1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - "fmt" + _ "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -301,9 +301,14 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) + //val := closure.GetMem(pc).BigInt() + data := closure.Gets(pc, big.NewInt(32)) + val := ethutil.BigD(data.Bytes()) - val := closure.GetMem(pc).BigInt() + // Push value to stack stack.Push(val) + + pc.Add(pc, big.NewInt(31)) case oPOP: stack.Pop() case oDUP: @@ -343,17 +348,16 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCALL: - // Pop return size and offset - retSize, retOffset := stack.Popn() - // Pop input size and offset - inSize, inOffset := stack.Popn() - fmt.Println(inSize, inOffset) - // Get the arguments from the memory - args := mem.Get(inOffset.Int64(), inSize.Int64()) - // Pop gas and value of the stack. - gas, value := stack.Popn() // Closure addr addr := stack.Pop() + // Pop gas and value of the stack. + gas, value := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // Pop return size and offset + retSize, retOffset := stack.Popn() + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure @@ -385,7 +389,9 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { break out */ default: - ethutil.Config.Log.Debugln("Invalid opcode", op) + ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) + + return closure.Return(nil) } pc.Add(pc, ethutil.Big1) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 745005b099..65113ff573 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -83,6 +83,21 @@ func TestRun4(t *testing.T) { state := NewState(ethutil.NewTrie(db, "")) asm, err := mutan.Compile(strings.NewReader(` + int32 a = 10 + int32 b = 20 + if a > b { + int32 c = this.caller() + } + exit() + `), false) + script := ethutil.Assemble(asm...) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) + addr := tx.Hash()[12:] + contract := MakeContract(tx, state) + state.UpdateContract(contract) + fmt.Printf("%x\n", addr) + + asm, err = mutan.Compile(strings.NewReader(` int32 a = 10 int32 b = 10 if a == b { @@ -97,9 +112,9 @@ func TestRun4(t *testing.T) { store[a] = 20 store[b] = this.caller() - int8[10] ret - int8[10] arg - call(1234, 0, 100000000, arg, ret) + int8 ret = 0 + int8 arg = 10 + call(938726394128221156290138488023434115948430767407, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) @@ -113,6 +128,8 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) c := MakeContract(callerTx, state) + //fmt.Println(c.script[230:240]) + //fmt.Println(c.script) callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ diff --git a/ethutil/parsing.go b/ethutil/parsing.go index a9d50e4252..0de3966548 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -1,8 +1,8 @@ package ethutil import ( + _ "fmt" "math/big" - "strconv" ) // Op codes @@ -98,11 +98,16 @@ func CompileInstr(s interface{}) ([]byte, error) { // Assume regular bytes during compilation if !success { num.SetBytes([]byte(str)) + } else { + // tmp fix for 32 bytes + n := BigToBytes(num, 256) + return n, nil } return num.Bytes(), nil case int: - return big.NewInt(int64(s.(int))).Bytes(), nil + num := BigToBytes(big.NewInt(int64(s.(int))), 256) + return num, nil case []byte: return BigD(s.([]byte)).Bytes(), nil } @@ -110,25 +115,6 @@ func CompileInstr(s interface{}) ([]byte, error) { return nil, nil } -func Instr(instr string) (int, []string, error) { - - base := new(big.Int) - base.SetString(instr, 0) - - args := make([]string, 7) - for i := 0; i < 7; i++ { - // int(int(val) / int(math.Pow(256,float64(i)))) % 256 - exp := BigPow(256, i) - num := new(big.Int) - num.Div(base, exp) - - args[i] = num.Mod(num, big.NewInt(256)).String() - } - op, _ := strconv.Atoi(args[0]) - - return op, args[1:7], nil -} - // Script compilation functions // Compiles strings to machine code func Assemble(instructions ...interface{}) (script []byte) { From 969e748dce5562fc543990b6911d53ab699e393e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 15:30:14 -0400 Subject: [PATCH 0220/1237] Call fixed --- ethchain/vm_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 65113ff573..dc74422cc6 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -119,7 +119,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - //asm = append(asm, "LOG") + asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) @@ -128,8 +128,6 @@ func TestRun4(t *testing.T) { // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) c := MakeContract(callerTx, state) - //fmt.Println(c.script[230:240]) - //fmt.Println(c.script) callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ From 891f7259091cba0fe5e8c9370e7b0b1055b56683 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 18:14:19 -0400 Subject: [PATCH 0221/1237] Added better address format --- ethchain/stack.go | 1 + ethchain/vm.go | 11 ++++++++++- ethchain/vm_test.go | 5 +++-- ethutil/parsing.go | 5 ++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index e3fc4b6844..0dadd15e51 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -55,6 +55,7 @@ const ( // 0x50 range - 'storage' and execution oPUSH = 0x50 + oPUSH20 = 0x80 oPOP = 0x51 oDUP = 0x52 oSWAP = 0x53 diff --git a/ethchain/vm.go b/ethchain/vm.go index f94425d2d1..dd99ee7905 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -301,7 +301,6 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x50 range case oPUSH: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) - //val := closure.GetMem(pc).BigInt() data := closure.Gets(pc, big.NewInt(32)) val := ethutil.BigD(data.Bytes()) @@ -309,6 +308,16 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { stack.Push(val) pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := closure.Gets(pc, big.NewInt(20)) + val := ethutil.BigD(data.Bytes()) + + // Push value to stack + stack.Push(val) + + pc.Add(pc, big.NewInt(19)) + case oPOP: stack.Pop() case oDUP: diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index dc74422cc6..923d3526cd 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -114,12 +114,13 @@ func TestRun4(t *testing.T) { int8 ret = 0 int8 arg = 10 - call(938726394128221156290138488023434115948430767407, 0, 100000000, arg, ret) + addr address = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" + call(address, 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") + //asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 0de3966548..278414982f 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -51,7 +51,10 @@ var OpCodes = map[string]byte{ "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution - "PUSH": 0x50, + "PUSH": 0x50, + + "PUSH20": 0x80, + "POP": 0x51, "DUP": 0x52, "SWAP": 0x53, From afc92fb7d799a4085d2256a7106ee9f7b9ea2f9e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 18:32:54 -0400 Subject: [PATCH 0222/1237] Added better address format --- ethchain/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 923d3526cd..55fb71dbe9 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -120,7 +120,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - //asm = append(asm, "LOG") + asm = append(asm, "LOG") fmt.Println(asm) callerScript := ethutil.Assemble(asm...) From 25dd46061fc3b732056ea87fe4a9696e160179cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 10 Apr 2014 21:03:14 -0400 Subject: [PATCH 0223/1237] Added push20 --- ethchain/stack.go | 2 +- ethchain/vm_test.go | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 0dadd15e51..d475f2f8e0 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -251,7 +251,7 @@ func (m *Memory) Print() { if len(m.store) > 0 { addr := 0 for i := 0; i+32 <= len(m.store); i += 32 { - fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) + fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) addr++ } } else { diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 55fb71dbe9..4075dfbc6b 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -98,24 +98,22 @@ func TestRun4(t *testing.T) { fmt.Printf("%x\n", addr) asm, err = mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 10 - if a == b { - int32 c = 10 - if c == 10 { - int32 d = 1000 - int32 e = 10 - } + // Check if there's any cash in the initial store + if store[1000] == 0 { + store[1000] = 10^20 } - store[0] = 20 - store[a] = 20 - store[b] = this.caller() + store[1001] = this.value() * 20 + store[this.origin()] = store[this.origin()] + 1000 + + if store[1001] > 20 { + store[1001] = 10^50 + } int8 ret = 0 int8 arg = 10 - addr address = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" - call(address, 0, 100000000, arg, ret) + store[1002] = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" + call(store[1002], 0, 100000000, arg, ret) `), false) if err != nil { fmt.Println(err) From ca747f268800590ee855b1ce593b61e95d073311 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Apr 2014 08:28:30 -0400 Subject: [PATCH 0224/1237] Added the possibility for debug hooks during closure call --- ethchain/closure.go | 6 +++-- ethchain/state_manager.go | 2 +- ethchain/vm.go | 47 +++++---------------------------------- ethchain/vm_test.go | 2 +- 4 files changed, 12 insertions(+), 45 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 8e57a0d03f..3d15f2a990 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -69,10 +69,12 @@ func (c *Closure) Address() []byte { return c.object.Address() } -func (c *Closure) Call(vm *Vm, args []byte) []byte { +type DebugHook func(op OpCode) + +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args - return vm.RunClosure(c) + return vm.RunClosure(c, hook) } func (c *Closure) Return(ret []byte) []byte { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3043c3d15c..111d2c019e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -327,7 +327,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - closure.Call(vm, nil) + closure.Call(vm, nil, nil) // Update the account (refunds) sm.procState.UpdateAccount(tx.Sender(), caller) diff --git a/ethchain/vm.go b/ethchain/vm.go index dd99ee7905..dce972cc73 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,7 @@ func NewVm(state *State, vars RuntimeVars) *Vm { var Pow256 = ethutil.BigPow(2, 256) -func (vm *Vm) RunClosure(closure *Closure) []byte { +func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // If the amount of gas supplied is less equal to 0 if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -372,7 +372,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // Create a new callable closure closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, args) + ret := closure.Call(vm, args, hook) mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: @@ -404,44 +404,9 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { } pc.Add(pc, ethutil.Big1) + + if hook != nil { + hook(op) + } } } - -/* -func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { - ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) - j := int64(0) - dataItems := make([]string, int(length.Uint64())) - for i := from.Int64(); i < length.Int64(); i++ { - dataItems[j] = contract.GetMem(big.NewInt(j)).Str() - j++ - } - - tx := NewTransaction(addr, value, dataItems) - if tx.IsContract() { - contract := MakeContract(tx, state) - state.UpdateContract(contract) - } else { - account := state.GetAccount(tx.Recipient) - account.Amount.Add(account.Amount, tx.Value) - state.UpdateAccount(tx.Recipient, account) - } -} - -// Returns an address from the specified contract's address -func contractMemory(state *State, contractAddr []byte, memAddr *big.Int) *big.Int { - contract := state.GetContract(contractAddr) - if contract == nil { - log.Panicf("invalid contract addr %x", contractAddr) - } - val := state.trie.Get(memAddr.String()) - - // decode the object as a big integer - decoder := ethutil.NewValueFromBytes([]byte(val)) - if decoder.IsNil() { - return ethutil.BigFalse - } - - return decoder.BigInt() -} -*/ diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 4075dfbc6b..5a1419c0f9 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -139,5 +139,5 @@ func TestRun4(t *testing.T) { // XXX Tx data? Could be just an argument to the closure instead txData: nil, }) - callerClosure.Call(vm, nil) + callerClosure.Call(vm, nil, nil) } From 116516158da637cde50d27d600db6661732fc402 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 11 Apr 2014 13:29:57 -0400 Subject: [PATCH 0225/1237] Renamed --- ethchain/closure.go | 4 +- ethchain/contract.go | 8 ++++ ethchain/stack.go | 8 ++++ ethchain/state_manager.go | 14 +++--- ethchain/vm.go | 98 ++++++++++++++++++++++++++++++--------- ethchain/vm_test.go | 29 +++++++++--- 6 files changed, 124 insertions(+), 37 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 3d15f2a990..de21964996 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -52,7 +52,7 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value { } func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { - if x.Int64() > int64(len(c.Script)) || y.Int64() > int64(len(c.Script)) { + if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) { return ethutil.NewValue(0) } @@ -69,7 +69,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(op OpCode) +type DebugHook func(op OpCode, mem *Memory, stack *Stack) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args diff --git a/ethchain/contract.go b/ethchain/contract.go index e99e413f7a..af348667c3 100644 --- a/ethchain/contract.go +++ b/ethchain/contract.go @@ -69,6 +69,14 @@ func (c *Contract) Address() []byte { return c.address } +func (c *Contract) Script() []byte { + return c.script +} + +func (c *Contract) Init() []byte { + return c.initScript +} + func (c *Contract) RlpEncode() []byte { return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) } diff --git a/ethchain/stack.go b/ethchain/stack.go index d475f2f8e0..2aca0a3500 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -173,6 +173,10 @@ func NewStack() *Stack { return &Stack{} } +func (st *Stack) Data() []*big.Int { + return st.data +} + func (st *Stack) Pop() *big.Int { str := st.data[len(st.data)-1] @@ -246,6 +250,10 @@ func (m *Memory) Len() int { return len(m.store) } +func (m *Memory) Data() []byte { + return m.store +} + func (m *Memory) Print() { fmt.Printf("### mem %d bytes ###\n", len(m.store)) if len(m.store) > 0 { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 111d2c019e..549d599594 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -318,14 +318,14 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ - origin: caller.Address(), - blockNumber: block.BlockInfo().Number, - prevHash: block.PrevHash, - coinbase: block.Coinbase, - time: block.Time, - diff: block.Difficulty, + Origin: caller.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, // XXX Tx data? Could be just an argument to the closure instead - txData: nil, + TxData: nil, }) closure.Call(vm, nil, nil) diff --git a/ethchain/vm.go b/ethchain/vm.go index dce972cc73..fbe0d0439b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,7 +2,7 @@ package ethchain import ( _ "bytes" - _ "fmt" + "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" _ "math" @@ -33,13 +33,13 @@ type Vm struct { } type RuntimeVars struct { - origin []byte - blockNumber uint64 - prevHash []byte - coinbase []byte - time int64 - diff *big.Int - txData []string + Origin []byte + BlockNumber uint64 + PrevHash []byte + Coinbase []byte + Time int64 + Diff *big.Int + TxData []string } func NewVm(state *State, vars RuntimeVars) *Vm { @@ -65,9 +65,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // The base for all big integer arithmetic base := new(big.Int) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } + */ for { step++ @@ -75,9 +77,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + */ // TODO Get each instruction cost properly gas := new(big.Int) @@ -270,7 +274,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oBALANCE: stack.Push(closure.Value) case oORIGIN: - stack.Push(ethutil.BigD(vm.vars.origin)) + stack.Push(ethutil.BigD(vm.vars.Origin)) case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: @@ -286,15 +290,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // 0x40 range case oPREVHASH: - stack.Push(ethutil.BigD(vm.vars.prevHash)) + stack.Push(ethutil.BigD(vm.vars.PrevHash)) case oCOINBASE: - stack.Push(ethutil.BigD(vm.vars.coinbase)) + stack.Push(ethutil.BigD(vm.vars.Coinbase)) case oTIMESTAMP: - stack.Push(big.NewInt(vm.vars.time)) + stack.Push(big.NewInt(vm.vars.Time)) case oNUMBER: - stack.Push(big.NewInt(int64(vm.vars.blockNumber))) + stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) case oDIFFICULTY: - stack.Push(vm.vars.diff) + stack.Push(vm.vars.Diff) case oGASLIMIT: // TODO @@ -406,7 +410,59 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, ethutil.Big1) if hook != nil { - hook(op) + hook(op, mem, stack) } } } + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%v", op)) + + switch op { + case oPUSH: // Push PC+1 on to the stack + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+32] + val := ethutil.BigD(data) + + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+20] + val := ethutil.BigD(data) + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(19)) + } + + pc.Add(pc, ethutil.Big1) + } + + return +} diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5a1419c0f9..a0add95328 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -130,14 +130,29 @@ func TestRun4(t *testing.T) { callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - origin: account.Address(), - blockNumber: 1, - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), + Origin: account.Address(), + BlockNumber: 1, + PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), + Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), + Time: 1, + Diff: big.NewInt(256), // XXX Tx data? Could be just an argument to the closure instead - txData: nil, + TxData: nil, }) callerClosure.Call(vm, nil, nil) } + +func TestRun5(t *testing.T) { + ethutil.ReadConfig("") + + asm, _ := mutan.Compile(strings.NewReader(` + int32 a = 10 + int32 b = 20 + if a > b { + int32 c = this.caller() + } + exit() + `), false) + script := ethutil.Assemble(asm...) + fmt.Println(Disassemble(script)) +} From 086acd122b59071255b0c1cfae569748b1d7427a Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 12 Apr 2014 00:13:42 -0400 Subject: [PATCH 0226/1237] Added pre processing of script data --- ethchain/closure.go | 2 +- ethchain/vm.go | 5 +++-- ethutil/parsing.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index de21964996..0fbe48f921 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -69,7 +69,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(op OpCode, mem *Memory, stack *Stack) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { c.Args = args diff --git a/ethchain/vm.go b/ethchain/vm.go index fbe0d0439b..b88cd28613 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -312,6 +312,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(val) pc.Add(pc, big.NewInt(31)) + step++ case oPUSH20: pc.Add(pc, ethutil.Big1) data := closure.Gets(pc, big.NewInt(20)) @@ -321,7 +322,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(val) pc.Add(pc, big.NewInt(19)) - + step++ case oPOP: stack.Pop() case oDUP: @@ -410,7 +411,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, ethutil.Big1) if hook != nil { - hook(op, mem, stack) + hook(step-1, op, mem, stack) } } } diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 278414982f..328704caea 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -3,6 +3,7 @@ package ethutil import ( _ "fmt" "math/big" + "regexp" ) // Op codes @@ -132,3 +133,33 @@ func Assemble(instructions ...interface{}) (script []byte) { return } + +/* +Prepocessing function that takes init and main apart: +init() { + // something +} + +main() { + // main something +} +*/ +func PreProcess(data string) (mainInput, initInput string) { + reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" + mainReg := regexp.MustCompile("main" + reg) + initReg := regexp.MustCompile("init" + reg) + + main := mainReg.FindStringSubmatch(data) + if len(main) > 0 { + mainInput = main[1] + } else { + mainInput = data + } + + init := initReg.FindStringSubmatch(data) + if len(init) > 0 { + initInput = init[1] + } + + return +} From ca13e3b1058f0d680b79dc1d9319d427a09493f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 15 Apr 2014 16:16:38 -0400 Subject: [PATCH 0227/1237] Moved assembler stage processing to it's own file --- ethchain/asm.go | 126 ++++++++++++++++++++++++ ethchain/closure.go | 2 +- ethchain/stack.go | 151 +---------------------------- ethchain/types.go | 230 ++++++++++++++++++++++++++++++++++++++++++++ ethchain/vm.go | 134 +++++++++++++------------- 5 files changed, 430 insertions(+), 213 deletions(-) create mode 100644 ethchain/asm.go create mode 100644 ethchain/types.go diff --git a/ethchain/asm.go b/ethchain/asm.go new file mode 100644 index 0000000000..5f901f8a23 --- /dev/null +++ b/ethchain/asm.go @@ -0,0 +1,126 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" + "regexp" +) + +func CompileInstr(s interface{}) ([]byte, error) { + switch s.(type) { + case string: + str := s.(string) + isOp := IsOpCode(str) + if isOp { + return []byte{OpCodes[str]}, nil + } + + num := new(big.Int) + _, success := num.SetString(str, 0) + // Assume regular bytes during compilation + if !success { + num.SetBytes([]byte(str)) + } else { + // tmp fix for 32 bytes + n := ethutil.BigToBytes(num, 256) + return n, nil + } + + return num.Bytes(), nil + case int: + num := ethutil.BigToBytes(big.NewInt(int64(s.(int))), 256) + return num, nil + case []byte: + return ethutil.BigD(s.([]byte)).Bytes(), nil + } + + return nil, nil +} + +// Script compilation functions +// Compiles strings to machine code +func Assemble(instructions ...interface{}) (script []byte) { + //script = make([]string, len(instructions)) + + for _, val := range instructions { + instr, _ := CompileInstr(val) + + //script[i] = string(instr) + script = append(script, instr...) + } + + return +} + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%v", op)) + + switch op { + case oPUSH: // Push PC+1 on to the stack + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+32] + val := ethutil.BigD(data) + + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(31)) + case oPUSH20: + pc.Add(pc, ethutil.Big1) + data := script[pc.Int64() : pc.Int64()+20] + val := ethutil.BigD(data) + var b []byte + if val.Int64() == 0 { + b = []byte{0} + } else { + b = val.Bytes() + } + + asm = append(asm, fmt.Sprintf("0x%x", b)) + + pc.Add(pc, big.NewInt(19)) + } + + pc.Add(pc, ethutil.Big1) + } + + return +} + +func PreProcess(data string) (mainInput, initInput string) { + reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" + mainReg := regexp.MustCompile("main" + reg) + initReg := regexp.MustCompile("init" + reg) + + main := mainReg.FindStringSubmatch(data) + if len(main) > 0 { + mainInput = main[1] + } else { + mainInput = data + } + + init := initReg.FindStringSubmatch(data) + if len(init) > 0 { + initInput = init[1] + } + + return +} diff --git a/ethchain/closure.go b/ethchain/closure.go index 0fbe48f921..0762e8f49f 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -71,7 +71,7 @@ func (c *Closure) Address() []byte { type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) -func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) []byte { +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args return vm.RunClosure(c, hook) diff --git a/ethchain/stack.go b/ethchain/stack.go index 2aca0a3500..2883600627 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -6,153 +6,6 @@ import ( "math/big" ) -type OpCode int - -// Op codes -const ( - // 0x0 range - arithmetic ops - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oGT = 0x0b - oEQ = 0x0c - oNOT = 0x0d - - // 0x10 range - bit ops - oAND = 0x10 - oOR = 0x11 - oXOR = 0x12 - oBYTE = 0x13 - - // 0x20 range - crypto - oSHA3 = 0x20 - - // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATA = 0x35 - oCALLDATASIZE = 0x36 - oGASPRICE = 0x37 - - // 0x40 range - block operations - oPREVHASH = 0x40 - oCOINBASE = 0x41 - oTIMESTAMP = 0x42 - oNUMBER = 0x43 - oDIFFICULTY = 0x44 - oGASLIMIT = 0x45 - - // 0x50 range - 'storage' and execution - oPUSH = 0x50 - oPUSH20 = 0x80 - oPOP = 0x51 - oDUP = 0x52 - oSWAP = 0x53 - oMLOAD = 0x54 - oMSTORE = 0x55 - oMSTORE8 = 0x56 - oSLOAD = 0x57 - oSSTORE = 0x58 - oJUMP = 0x59 - oJUMPI = 0x5a - oPC = 0x5b - oMSIZE = 0x5c - - // 0x60 range - closures - oCREATE = 0x60 - oCALL = 0x61 - oRETURN = 0x62 - - // 0x70 range - other - oLOG = 0x70 // XXX Unofficial - oSUICIDE = 0x7f -) - -// Since the opcodes aren't all in order we can't use a regular slice -var opCodeToString = map[OpCode]string{ - // 0x0 range - arithmetic ops - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oGT: "GT", - oEQ: "EQ", - oNOT: "NOT", - - // 0x10 range - bit ops - oAND: "AND", - oOR: "OR", - oXOR: "XOR", - oBYTE: "BYTE", - - // 0x20 range - crypto - oSHA3: "SHA3", - - // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", - oCALLDATASIZE: "CALLDATASIZE", - oGASPRICE: "TXGASPRICE", - - // 0x40 range - block operations - oPREVHASH: "PREVHASH", - oCOINBASE: "COINBASE", - oTIMESTAMP: "TIMESTAMP", - oNUMBER: "NUMBER", - oDIFFICULTY: "DIFFICULTY", - oGASLIMIT: "GASLIMIT", - - // 0x50 range - 'storage' and execution - oPUSH: "PUSH", - oPOP: "POP", - oDUP: "DUP", - oSWAP: "SWAP", - oMLOAD: "MLOAD", - oMSTORE: "MSTORE", - oMSTORE8: "MSTORE8", - oSLOAD: "SLOAD", - oSSTORE: "SSTORE", - oJUMP: "JUMP", - oJUMPI: "JUMPI", - oPC: "PC", - oMSIZE: "MSIZE", - - // 0x60 range - closures - oCREATE: "CREATE", - oCALL: "CALL", - oRETURN: "RETURN", - - // 0x70 range - other - oLOG: "LOG", - oSUICIDE: "SUICIDE", -} - -func (o OpCode) String() string { - return opCodeToString[o] -} - type OpType int const ( @@ -177,6 +30,10 @@ func (st *Stack) Data() []*big.Int { return st.data } +func (st *Stack) Len() int { + return len(st.data) +} + func (st *Stack) Pop() *big.Int { str := st.data[len(st.data)-1] diff --git a/ethchain/types.go b/ethchain/types.go new file mode 100644 index 0000000000..24aad82c37 --- /dev/null +++ b/ethchain/types.go @@ -0,0 +1,230 @@ +package ethchain + +type OpCode int + +// Op codes +const ( + // 0x0 range - arithmetic ops + oSTOP = 0x00 + oADD = 0x01 + oMUL = 0x02 + oSUB = 0x03 + oDIV = 0x04 + oSDIV = 0x05 + oMOD = 0x06 + oSMOD = 0x07 + oEXP = 0x08 + oNEG = 0x09 + oLT = 0x0a + oGT = 0x0b + oEQ = 0x0c + oNOT = 0x0d + + // 0x10 range - bit ops + oAND = 0x10 + oOR = 0x11 + oXOR = 0x12 + oBYTE = 0x13 + + // 0x20 range - crypto + oSHA3 = 0x20 + + // 0x30 range - closure state + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oGASPRICE = 0x37 + + // 0x40 range - block operations + oPREVHASH = 0x40 + oCOINBASE = 0x41 + oTIMESTAMP = 0x42 + oNUMBER = 0x43 + oDIFFICULTY = 0x44 + oGASLIMIT = 0x45 + + // 0x50 range - 'storage' and execution + oPUSH = 0x50 + oPUSH20 = 0x80 + oPOP = 0x51 + oDUP = 0x52 + oSWAP = 0x53 + oMLOAD = 0x54 + oMSTORE = 0x55 + oMSTORE8 = 0x56 + oSLOAD = 0x57 + oSSTORE = 0x58 + oJUMP = 0x59 + oJUMPI = 0x5a + oPC = 0x5b + oMSIZE = 0x5c + + // 0x60 range - closures + oCREATE = 0x60 + oCALL = 0x61 + oRETURN = 0x62 + + // 0x70 range - other + oLOG = 0x70 // XXX Unofficial + oSUICIDE = 0x7f +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + // 0x0 range - arithmetic ops + oSTOP: "STOP", + oADD: "ADD", + oMUL: "MUL", + oSUB: "SUB", + oDIV: "DIV", + oSDIV: "SDIV", + oMOD: "MOD", + oSMOD: "SMOD", + oEXP: "EXP", + oNEG: "NEG", + oLT: "LT", + oGT: "GT", + oEQ: "EQ", + oNOT: "NOT", + + // 0x10 range - bit ops + oAND: "AND", + oOR: "OR", + oXOR: "XOR", + oBYTE: "BYTE", + + // 0x20 range - crypto + oSHA3: "SHA3", + + // 0x30 range - closure state + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oGASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + oPREVHASH: "PREVHASH", + oCOINBASE: "COINBASE", + oTIMESTAMP: "TIMESTAMP", + oNUMBER: "NUMBER", + oDIFFICULTY: "DIFFICULTY", + oGASLIMIT: "GASLIMIT", + + // 0x50 range - 'storage' and execution + oPUSH: "PUSH", + oPOP: "POP", + oDUP: "DUP", + oSWAP: "SWAP", + oMLOAD: "MLOAD", + oMSTORE: "MSTORE", + oMSTORE8: "MSTORE8", + oSLOAD: "SLOAD", + oSSTORE: "SSTORE", + oJUMP: "JUMP", + oJUMPI: "JUMPI", + oPC: "PC", + oMSIZE: "MSIZE", + + // 0x60 range - closures + oCREATE: "CREATE", + oCALL: "CALL", + oRETURN: "RETURN", + + // 0x70 range - other + oLOG: "LOG", + oSUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + return opCodeToString[o] +} + +// Op codes for assembling +var OpCodes = map[string]byte{ + // 0x0 range - arithmetic ops + "STOP": 0x00, + "ADD": 0x01, + "MUL": 0x02, + "SUB": 0x03, + "DIV": 0x04, + "SDIV": 0x05, + "MOD": 0x06, + "SMOD": 0x07, + "EXP": 0x08, + "NEG": 0x09, + "LT": 0x0a, + "GT": 0x0b, + "EQ": 0x0c, + "NOT": 0x0d, + + // 0x10 range - bit ops + "AND": 0x10, + "OR": 0x11, + "XOR": 0x12, + "BYTE": 0x13, + + // 0x20 range - crypto + "SHA3": 0x20, + + // 0x30 range - closure state + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, + + // 0x40 range - block operations + "PREVHASH": 0x40, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, + + // 0x50 range - 'storage' and execution + "PUSH": 0x50, + + "PUSH20": 0x80, + + "POP": 0x51, + "DUP": 0x52, + "SWAP": 0x53, + "MLOAD": 0x54, + "MSTORE": 0x55, + "MSTORE8": 0x56, + "SLOAD": 0x57, + "SSTORE": 0x58, + "JUMP": 0x59, + "JUMPI": 0x5a, + "PC": 0x5b, + "MSIZE": 0x5c, + + // 0x60 range - closures + "CREATE": 0x60, + "CALL": 0x61, + "RETURN": 0x62, + + // 0x70 range - other + "LOG": 0x70, + "SUICIDE": 0x7f, +} + +func IsOpCode(s string) bool { + for key, _ := range OpCodes { + if key == s { + return true + } + } + return false +} diff --git a/ethchain/vm.go b/ethchain/vm.go index b88cd28613..33d667457e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -48,7 +48,19 @@ func NewVm(state *State, vars RuntimeVars) *Vm { var Pow256 = ethutil.BigPow(2, 256) -func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { +var isRequireError = false + +func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { + // Recover from any require exception + defer func() { + if r := recover(); r != nil && isRequireError { + fmt.Println(r) + + ret = closure.Return(nil) + err = fmt.Errorf("%v", r) + } + }() + // If the amount of gas supplied is less equal to 0 if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something @@ -58,6 +70,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { mem := &Memory{} // New stack (should this be shared?) stack := NewStack() + require := func(m int) { + if stack.Len()-1 > m { + isRequireError = true + panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) + } + } + // Instruction pointer pc := big.NewInt(0) // Current step count @@ -121,7 +140,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { if closure.Gas.Cmp(gas) < 0 { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) - return closure.Return(nil) + return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } switch op { @@ -129,10 +148,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Print() mem.Print() case oSTOP: // Stop the closure - return closure.Return(nil) + return closure.Return(nil), nil - // 0x20 range + // 0x20 range case oADD: + require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) @@ -140,6 +160,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oSUB: + require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) @@ -147,6 +168,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oMUL: + require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) @@ -154,12 +176,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Pop result back on the stack stack.Push(base) case oDIV: + require(2) x, y := stack.Popn() // floor(x / y) base.Div(x, y) // Pop result back on the stack stack.Push(base) case oSDIV: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -176,10 +200,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oMOD: + require(2) x, y := stack.Popn() base.Mod(x, y) stack.Push(base) case oSMOD: + require(2) x, y := stack.Popn() // n > 2**255 if x.Cmp(Pow256) > 0 { @@ -196,14 +222,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Push result on to the stack stack.Push(z) case oEXP: + require(2) x, y := stack.Popn() base.Exp(x, y, Pow256) stack.Push(base) case oNEG: + require(1) base.Sub(Pow256, stack.Pop()) stack.Push(base) case oLT: + require(2) x, y := stack.Popn() // x < y if x.Cmp(y) < 0 { @@ -212,6 +241,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oGT: + require(2) x, y := stack.Popn() // x > y if x.Cmp(y) > 0 { @@ -220,6 +250,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oEQ: + require(2) x, y := stack.Popn() // x == y if x.Cmp(y) == 0 { @@ -228,6 +259,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oNOT: + require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) == 0 { stack.Push(ethutil.BigTrue) @@ -235,8 +267,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } - // 0x10 range + // 0x10 range case oAND: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { stack.Push(ethutil.BigTrue) @@ -245,6 +278,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { } case oOR: + require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { stack.Push(ethutil.BigTrue) @@ -252,9 +286,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } case oXOR: + require(2) x, y := stack.Popn() stack.Push(base.Xor(x, y)) case oBYTE: + require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) @@ -262,13 +298,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(ethutil.BigFalse) } - // 0x20 range + // 0x20 range case oSHA3: + require(2) size, offset := stack.Popn() data := mem.Get(offset.Int64(), size.Int64()) stack.Push(ethutil.BigD(data)) - // 0x30 range + // 0x30 range case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: @@ -281,6 +318,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // FIXME: Original value of the call, not the current value stack.Push(closure.Value) case oCALLDATA: + require(1) offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: @@ -288,7 +326,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oGASPRICE: // TODO - // 0x40 range + // 0x40 range case oPREVHASH: stack.Push(ethutil.BigD(vm.vars.PrevHash)) case oCOINBASE: @@ -300,7 +338,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { case oDIFFICULTY: stack.Push(vm.vars.Diff) case oGASLIMIT: - // TODO + // TODO // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -324,34 +362,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { pc.Add(pc, big.NewInt(19)) step++ case oPOP: + require(1) stack.Pop() case oDUP: + require(1) stack.Push(stack.Peek()) case oSWAP: + require(2) x, y := stack.Popn() stack.Push(y) stack.Push(x) case oMLOAD: + require(1) offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) case oMSTORE: // Store the value at stack top-1 in to memory at location stack top + require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + require(1) loc := stack.Pop() val := closure.GetMem(loc) stack.Push(val.BigInt()) case oSSTORE: + require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) case oJUMP: + require(1) pc = stack.Pop() case oJUMPI: + require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos @@ -360,8 +408,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { stack.Push(pc) case oMSIZE: stack.Push(big.NewInt(int64(mem.Len()))) - // 0x60 range + // 0x60 range + case oCREATE: case oCALL: + require(8) // Closure addr addr := stack.Pop() // Pop gas and value of the stack. @@ -377,14 +427,20 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { // Create a new callable closure closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) // Executer the closure and get the return value (if any) - ret := closure.Call(vm, args, hook) + ret, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } mem.Set(retOffset.Int64(), retSize.Int64(), ret) case oRETURN: + require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - return closure.Return(ret) + return closure.Return(ret), nil case oSUICIDE: /* recAddr := stack.Pop().Bytes() @@ -405,7 +461,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) - return closure.Return(nil) + return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } pc.Add(pc, ethutil.Big1) @@ -415,55 +471,3 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) []byte { } } } - -func Disassemble(script []byte) (asm []string) { - pc := new(big.Int) - for { - if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { - return - } - - // Get the memory location of pc - val := script[pc.Int64()] - // Get the opcode (it must be an opcode!) - op := OpCode(val) - - asm = append(asm, fmt.Sprintf("%v", op)) - - switch op { - case oPUSH: // Push PC+1 on to the stack - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+32] - val := ethutil.BigD(data) - - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(31)) - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+20] - val := ethutil.BigD(data) - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(19)) - } - - pc.Add(pc, ethutil.Big1) - } - - return -} From 9c6aca78933c14ca107da30c4690808950718368 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Apr 2014 04:06:51 +0200 Subject: [PATCH 0228/1237] Merged accounts and contracts in to StateObject * Account removed * Contract removed * Address state changed to CachedStateObject * Added StateObject --- ethchain/address.go | 76 ---------------- ethchain/address_test.go | 8 -- ethchain/block.go | 7 +- ethchain/block_chain.go | 6 +- ethchain/contract.go | 119 ------------------------- ethchain/keypair.go | 4 +- ethchain/state.go | 65 ++++---------- ethchain/state_manager.go | 54 +++++------- ethchain/state_object.go | 162 +++++++++++++++++++++++++++++++++++ ethchain/transaction.go | 4 +- ethchain/transaction_pool.go | 14 +-- 11 files changed, 219 insertions(+), 300 deletions(-) delete mode 100644 ethchain/address.go delete mode 100644 ethchain/address_test.go delete mode 100644 ethchain/contract.go create mode 100644 ethchain/state_object.go diff --git a/ethchain/address.go b/ethchain/address.go deleted file mode 100644 index 0b3ef7c057..0000000000 --- a/ethchain/address.go +++ /dev/null @@ -1,76 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -type Account struct { - address []byte - Amount *big.Int - Nonce uint64 -} - -func NewAccount(address []byte, amount *big.Int) *Account { - return &Account{address, amount, 0} -} - -func NewAccountFromData(address, data []byte) *Account { - account := &Account{address: address} - account.RlpDecode(data) - - return account -} - -func (a *Account) AddFee(fee *big.Int) { - a.AddFunds(fee) -} - -func (a *Account) AddFunds(funds *big.Int) { - a.Amount.Add(a.Amount, funds) -} - -func (a *Account) Address() []byte { - return a.address -} - -// Implements Callee -func (a *Account) ReturnGas(value *big.Int, state *State) { - // Return the value back to the sender - a.AddFunds(value) - state.UpdateAccount(a.address, a) -} - -func (a *Account) RlpEncode() []byte { - return ethutil.Encode([]interface{}{a.Amount, a.Nonce}) -} - -func (a *Account) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - a.Amount = decoder.Get(0).BigInt() - a.Nonce = decoder.Get(1).Uint() -} - -type AddrStateStore struct { - states map[string]*AccountState -} - -func NewAddrStateStore() *AddrStateStore { - return &AddrStateStore{states: make(map[string]*AccountState)} -} - -func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState { - state := &AccountState{Nonce: account.Nonce, Account: account} - s.states[string(addr)] = state - return state -} - -func (s *AddrStateStore) Get(addr []byte) *AccountState { - return s.states[string(addr)] -} - -type AccountState struct { - Nonce uint64 - Account *Account -} diff --git a/ethchain/address_test.go b/ethchain/address_test.go deleted file mode 100644 index 161e1b251e..0000000000 --- a/ethchain/address_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package ethchain - -import ( - "testing" -) - -func TestAddressState(t *testing.T) { -} diff --git a/ethchain/block.go b/ethchain/block.go index 732739c1ba..8c93947fb6 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -142,12 +142,13 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { data := block.state.trie.Get(string(block.Coinbase)) // Get the ether (Coinbase) and add the fee (gief fee to miner) - ether := NewAccountFromData(block.Coinbase, []byte(data)) + account := NewStateObjectFromBytes(block.Coinbase, []byte(data)) base = new(big.Int) - ether.Amount = base.Add(ether.Amount, fee) + account.Amount = base.Add(account.Amount, fee) - block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) + //block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) + block.state.UpdateStateObject(account) return true } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2a50ef6873..d65c38fe46 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -262,9 +262,9 @@ func AddTestNetFunds(block *Block) { } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) - addr := block.state.GetAccount(codedAddr) - addr.Amount = ethutil.BigPow(2, 200) - block.state.UpdateAccount(codedAddr, addr) + account := block.state.GetAccount(codedAddr) + account.Amount = ethutil.BigPow(2, 200) + block.state.UpdateStateObject(account) } } diff --git a/ethchain/contract.go b/ethchain/contract.go deleted file mode 100644 index af348667c3..0000000000 --- a/ethchain/contract.go +++ /dev/null @@ -1,119 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -type Contract struct { - Amount *big.Int - Nonce uint64 - //state *ethutil.Trie - state *State - address []byte - script []byte - initScript []byte -} - -func NewContract(address []byte, Amount *big.Int, root []byte) *Contract { - contract := &Contract{address: address, Amount: Amount, Nonce: 0} - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) - - return contract -} - -func NewContractFromBytes(address, data []byte) *Contract { - contract := &Contract{address: address} - contract.RlpDecode(data) - - return contract -} - -func (c *Contract) Addr(addr []byte) *ethutil.Value { - return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) -} - -func (c *Contract) SetAddr(addr []byte, value interface{}) { - c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) -} - -func (c *Contract) State() *State { - return c.state -} - -func (c *Contract) GetMem(num *big.Int) *ethutil.Value { - nb := ethutil.BigToBytes(num, 256) - - return c.Addr(nb) -} - -func (c *Contract) GetInstr(pc *big.Int) *ethutil.Value { - if int64(len(c.script)-1) < pc.Int64() { - return ethutil.NewValue(0) - } - - return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) -} - -func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) - c.state.trie.Update(string(addr), string(val.Encode())) -} - -// Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *Contract) ReturnGas(val *big.Int, state *State) { - c.Amount.Add(c.Amount, val) -} - -func (c *Contract) Address() []byte { - return c.address -} - -func (c *Contract) Script() []byte { - return c.script -} - -func (c *Contract) Init() []byte { - return c.initScript -} - -func (c *Contract) RlpEncode() []byte { - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript}) -} - -func (c *Contract) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.script = decoder.Get(3).Bytes() - c.initScript = decoder.Get(4).Bytes() -} - -func MakeContract(tx *Transaction, state *State) *Contract { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.Hash()[12:] - - value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.trie.Update(string(addr), string(contract.RlpEncode())) - contract.script = tx.Data - contract.initScript = tx.Init - - /* - for i, val := range tx.Data { - if len(val) > 0 { - bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256) - contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val))) - } - } - */ - state.trie.Update(string(addr), string(contract.RlpEncode())) - - return contract - } - - return nil -} diff --git a/ethchain/keypair.go b/ethchain/keypair.go index 9daaedbee2..a5af791d0d 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -10,7 +10,7 @@ type KeyPair struct { PublicKey []byte // The associated account - account *Account + account *StateObject state *State } @@ -24,7 +24,7 @@ func (k *KeyPair) Address() []byte { return ethutil.Sha3Bin(k.PublicKey[1:])[12:] } -func (k *KeyPair) Account() *Account { +func (k *KeyPair) Account() *StateObject { if k.account == nil { k.account = k.state.GetAccount(k.Address()) } diff --git a/ethchain/state.go b/ethchain/state.go index 1860647f2a..6558489325 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -47,23 +47,14 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -func (s *State) GetContract(addr []byte) *Contract { +func (s *State) GetContract(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { return nil } - // Whet get contract is called the retrieved value might - // be an account. The StateManager uses this to check - // to see if the address a tx was sent to is a contract - // or an account - value := ethutil.NewValueFromBytes([]byte(data)) - if value.Len() == 2 { - return nil - } - // build contract - contract := NewContractFromBytes(addr, []byte(data)) + contract := NewStateObjectFromBytes(addr, []byte(data)) // Check if there's a cached state for this contract cachedState := s.states[string(addr)] @@ -77,28 +68,17 @@ func (s *State) GetContract(addr []byte) *Contract { return contract } -func (s *State) UpdateContract(contract *Contract) { - addr := contract.Address() - - s.states[string(addr)] = contract.state - s.trie.Update(string(addr), string(contract.RlpEncode())) -} - -func (s *State) GetAccount(addr []byte) (account *Account) { +func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { account = NewAccount(addr, big.NewInt(0)) } else { - account = NewAccountFromData(addr, []byte(data)) + account = NewStateObjectFromBytes(addr, []byte(data)) } return } -func (s *State) UpdateAccount(addr []byte, account *Account) { - s.trie.Update(string(addr), string(account.RlpEncode())) -} - func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } @@ -119,7 +99,7 @@ const ( // Returns the object stored at key and the type stored at key // Returns nil if nothing is stored -func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { +func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { // Fetch data from the trie data := s.trie.Get(string(key)) // Returns the nil type, indicating nothing could be retrieved. @@ -145,6 +125,17 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) { return val, typ } +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil { + s.states[string(addr)] = object.state + } + + s.trie.Update(string(addr), string(object.RlpEncode())) +} + func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } @@ -152,27 +143,3 @@ func (s *State) Put(key, object []byte) { func (s *State) Root() interface{} { return s.trie.Root } - -// Script compilation functions -// Compiles strings to machine code -func Compile(code []string) (script []string) { - script = make([]string, len(code)) - for i, val := range code { - instr, _ := ethutil.CompileInstr(val) - - script[i] = string(instr) - } - - return -} - -func CompileToValues(code []string) (script []*ethutil.Value) { - script = make([]*ethutil.Value, len(code)) - for i, val := range code { - instr, _ := ethutil.CompileInstr(val) - - script[i] = ethutil.NewValue(instr) - } - - return -} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 549d599594..5e30d7280f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -30,7 +30,7 @@ type StateManager struct { bc *BlockChain // States for addresses. You can watch any address // at any given time - addrStateStore *AddrStateStore + stateObjectCache *StateObjectCache // Stack for processing contracts stack *Stack @@ -54,12 +54,12 @@ type StateManager struct { func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - addrStateStore: NewAddrStateStore(), - bc: ethereum.BlockChain(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + stateObjectCache: NewStateObjectCache(), + bc: ethereum.BlockChain(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -70,18 +70,18 @@ func (sm *StateManager) ProcState() *State { } // Watches any given address and puts it in the address state store -func (sm *StateManager) WatchAddr(addr []byte) *AccountState { +func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) account := sm.procState.GetAccount(addr) - return sm.addrStateStore.Add(addr, account) + return sm.stateObjectCache.Add(addr, account) } -func (sm *StateManager) GetAddrState(addr []byte) *AccountState { - account := sm.addrStateStore.Get(addr) +func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject { + account := sm.stateObjectCache.Get(addr) if account == nil { a := sm.procState.GetAccount(addr) - account = &AccountState{Nonce: a.Nonce, Account: a} + account = &CachedStateObject{Nonce: a.Nonce, Object: a} } return account @@ -116,7 +116,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { if contract := sm.procState.GetContract(tx.Recipient); contract != nil { err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) if err == nil { - sm.ProcessContract(contract, tx, block) + sm.EvalScript(contract.Script(), contract, tx, block) } } else { err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) @@ -180,7 +180,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { return err } - // if !sm.compState.Cmp(sm.procState) if !sm.compState.Cmp(sm.procState) { return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) } @@ -190,9 +189,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Sync the current block's state to the database and cancelling out the deferred Undo sm.procState.Sync() - // Broadcast the valid block back to the wire - //sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - // Add the block to the chain sm.bc.Add(block) @@ -282,22 +278,20 @@ func CalculateUncleReward(block *Block) *big.Int { } func (sm *StateManager) AccumelateRewards(block *Block) error { - - // Get the coinbase rlp data - acc := sm.procState.GetAccount(block.Coinbase) + // Get the account associated with the coinbase + account := sm.procState.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address - acc.AddFee(CalculateBlockReward(block, len(block.Uncles))) + account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) addr := make([]byte, len(block.Coinbase)) copy(addr, block.Coinbase) - sm.procState.UpdateAccount(addr, acc) + sm.procState.UpdateStateObject(account) for _, uncle := range block.Uncles { - uncleAddr := sm.procState.GetAccount(uncle.Coinbase) - uncleAddr.AddFee(CalculateUncleReward(uncle)) + uncleAccount := sm.procState.GetAccount(uncle.Coinbase) + uncleAccount.AddAmount(CalculateUncleReward(uncle)) - //processor.state.UpdateAccount(uncle.Coinbase, uncleAddr) - sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr) + sm.procState.UpdateStateObject(uncleAccount) } return nil @@ -307,7 +301,7 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) { +func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors defer func() { if r := recover(); r != nil { @@ -316,7 +310,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, @@ -324,11 +318,9 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, - // XXX Tx data? Could be just an argument to the closure instead - TxData: nil, }) closure.Call(vm, nil, nil) // Update the account (refunds) - sm.procState.UpdateAccount(tx.Sender(), caller) + sm.procState.UpdateStateObject(caller) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go new file mode 100644 index 0000000000..8b4de0c4f3 --- /dev/null +++ b/ethchain/state_object.go @@ -0,0 +1,162 @@ +package ethchain + +import ( + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type StateObject struct { + // Address of the object + address []byte + // Shared attributes + Amount *big.Int + Nonce uint64 + // Contract related attributes + state *State + script []byte + initScript []byte +} + +func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { + contract := &StateObject{address: address, Amount: Amount, Nonce: 0} + contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) + + 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) + + return object +} + +func (c *StateObject) Addr(addr []byte) *ethutil.Value { + return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) +} + +func (c *StateObject) SetAddr(addr []byte, value interface{}) { + c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) +} + +func (c *StateObject) State() *State { + return c.state +} + +func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { + nb := ethutil.BigToBytes(num, 256) + + return c.Addr(nb) +} + +func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { + if int64(len(c.script)-1) < pc.Int64() { + return ethutil.NewValue(0) + } + + return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) +} + +func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.state.trie.Update(string(addr), string(val.Encode())) +} + +// Return the gas back to the origin. Used by the Virtual machine or Closures +func (c *StateObject) ReturnGas(val *big.Int, state *State) { + c.AddAmount(val) +} + +func (c *StateObject) AddAmount(amount *big.Int) { + c.Amount.Add(c.Amount, amount) +} + +func (c *StateObject) SubAmount(amount *big.Int) { + c.Amount.Sub(c.Amount, amount) +} + +func (c *StateObject) Address() []byte { + return c.address +} + +func (c *StateObject) Script() []byte { + return c.script +} + +func (c *StateObject) Init() []byte { + return c.initScript +} + +func (c *StateObject) RlpEncode() []byte { + var root interface{} + if c.state != nil { + root = c.state.trie.Root + } else { + root = nil + } + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script}) +} + +func (c *StateObject) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + c.Amount = decoder.Get(0).BigInt() + c.Nonce = decoder.Get(1).Uint() + c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.script = decoder.Get(3).Bytes() +} + +func MakeContract(tx *Transaction, state *State) *StateObject { + // Create contract if there's no recipient + if tx.IsContract() { + // FIXME + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(addr, value, []byte("")) + state.UpdateStateObject(contract) + + contract.script = tx.Data + contract.initScript = tx.Init + + state.UpdateStateObject(contract) + + return contract + } + + return nil +} + +// The cached state and state object cache are helpers which will give you somewhat +// control over the nonce. When creating new transactions you're interested in the 'next' +// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. +type StateObjectCache struct { + cachedObjects map[string]*CachedStateObject +} + +func NewStateObjectCache() *StateObjectCache { + return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)} +} + +func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject { + state := &CachedStateObject{Nonce: object.Nonce, Object: object} + s.cachedObjects[string(addr)] = state + + return state +} + +func (s *StateObjectCache) Get(addr []byte) *CachedStateObject { + return s.cachedObjects[string(addr)] +} + +type CachedStateObject struct { + Nonce uint64 + Object *StateObject +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index b359c9151c..78044e8408 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -23,8 +23,8 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true} +func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { + return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true} } func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 0bcfe69234..5cdda17e25 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -118,20 +118,20 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee - sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else if toContract { - sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else { // Subtract the amount from the senders account - sender.Amount.Sub(sender.Amount, totAmount) + sender.SubAmount(totAmount) // Add the amount to receivers account which should conclude this transaction - receiver.Amount.Add(receiver.Amount, tx.Value) + receiver.AddAmount(tx.Value) - block.state.UpdateAccount(tx.Recipient, receiver) + block.state.UpdateStateObject(receiver) } - block.state.UpdateAccount(tx.Sender(), sender) + block.state.UpdateStateObject(sender) log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) @@ -151,7 +151,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the sender accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) - sender := accountState.Account + sender := accountState.Object totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient From d811920d8b5643b944a7df58d5d75095539242c4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Apr 2014 04:07:21 +0200 Subject: [PATCH 0229/1237] Hack for miner problem added w/ note @maranh please check --- ethminer/miner.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethminer/miner.go b/ethminer/miner.go index d849773420..5bbf6b977f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -119,6 +119,9 @@ func (miner *Miner) listener() { miner.block.SetUncles(miner.uncles) } + // FIXME @ maranh, first block doesn't need this. Everything after the first block does. + // Please check and fix + miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) // Apply all transactions to the block miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions()) miner.ethereum.StateManager().AccumelateRewards(miner.block) From c5729d7ecc564f8eff6df565173a4f5cc6c43cb0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 16 Apr 2014 04:07:52 +0200 Subject: [PATCH 0230/1237] comments --- ethchain/asm.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethchain/asm.go b/ethchain/asm.go index 5f901f8a23..a6c85cb602 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -106,6 +106,7 @@ func Disassemble(script []byte) (asm []string) { } func PreProcess(data string) (mainInput, initInput string) { + // Regexp for parsing anything between brackets reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" mainReg := regexp.MustCompile("main" + reg) initReg := regexp.MustCompile("init" + reg) From a96c8c8af969665cc0c357eef81d43b5b7285dfe Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 18 Apr 2014 13:41:07 +0200 Subject: [PATCH 0231/1237] Added proper gas handling --- ethchain/closure.go | 5 +++-- ethchain/state_manager.go | 3 ++- ethchain/transaction.go | 12 ++++++------ ethchain/vm.go | 9 +++++---- ethchain/vm_test.go | 17 ++++++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 0762e8f49f..5c508179e5 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -27,14 +27,15 @@ type Closure struct { State *State Gas *big.Int + Price *big.Int Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, val *big.Int) *Closure { - return &Closure{callee, object, script, state, gas, val, nil} +func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { + return &Closure{callee, object, script, state, gas, price, val, nil} } // Retuns the x element in data slice diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 5e30d7280f..75a78e9f3b 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -310,7 +310,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans }() caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value) + closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, @@ -318,6 +318,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + //Price: tx.GasPrice, }) closure.Call(vm, nil, nil) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 78044e8408..1e43a2bae4 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -13,7 +13,7 @@ type Transaction struct { Recipient []byte Value *big.Int Gas *big.Int - Gasprice *big.Int + GasPrice *big.Int Data []byte Init []byte v byte @@ -24,11 +24,11 @@ type Transaction struct { } func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true} + return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} } func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, Gasprice: gasprice, Gas: gas, Data: data} + return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,7 +46,7 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, string(tx.Data)} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, string(tx.Data)} if tx.contractCreation { data = append(data, string(tx.Init)) } @@ -107,7 +107,7 @@ func (tx *Transaction) Sign(privk []byte) error { // [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] // [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.Gasprice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -132,7 +132,7 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() tx.Value = decoder.Get(1).BigInt() - tx.Gasprice = decoder.Get(2).BigInt() + tx.GasPrice = decoder.Get(2).BigInt() tx.Gas = decoder.Get(3).BigInt() tx.Recipient = decoder.Get(4).Bytes() tx.Data = decoder.Get(5).Bytes() diff --git a/ethchain/vm.go b/ethchain/vm.go index 33d667457e..85aefa685d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -71,7 +71,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // New stack (should this be shared?) stack := NewStack() require := func(m int) { - if stack.Len()-1 > m { + if stack.Len() < m { isRequireError = true panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) } @@ -105,7 +105,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO Get each instruction cost properly gas := new(big.Int) useGas := func(amount *big.Int) { - gas.Add(gas, amount) + gas.Add(gas, new(big.Int).Mul(amount, closure.Price)) } switch op { @@ -142,6 +142,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + closure.Gas.Sub(closure.Gas, gas) switch op { case oLOG: @@ -411,7 +412,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // 0x60 range case oCREATE: case oCALL: - require(8) + require(7) // Closure addr addr := stack.Pop() // Pop gas and value of the stack. @@ -425,7 +426,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, value) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index a0add95328..f66f2a8966 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -91,10 +91,10 @@ func TestRun4(t *testing.T) { exit() `), false) script := ethutil.Assemble(asm...) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) - state.UpdateContract(contract) + state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) asm, err = mutan.Compile(strings.NewReader(` @@ -122,12 +122,13 @@ func TestRun4(t *testing.T) { fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) // Contract addr as test address account := NewAccount(ContractAddr, big.NewInt(10000000)) + fmt.Println(account) c := MakeContract(callerTx, state) - callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), new(big.Int)) + callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0)) vm := NewVm(state, RuntimeVars{ Origin: account.Address(), @@ -136,10 +137,12 @@ func TestRun4(t *testing.T) { Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Time: 1, Diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - TxData: nil, }) - callerClosure.Call(vm, nil, nil) + _, e := callerClosure.Call(vm, nil, nil) + if e != nil { + fmt.Println("error", e) + } + fmt.Println(account) } func TestRun5(t *testing.T) { From 6930260962f4c6d1fe11d07a10300da96886ecd6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 20 Apr 2014 01:31:01 +0200 Subject: [PATCH 0232/1237] Updated VM --- ethchain/closure.go | 10 +++----- ethchain/state_object.go | 22 ++++++++++++++-- ethchain/vm.go | 54 +++++++++++++++++++++++++++------------- ethchain/vm_test.go | 41 +++++++++++++++++++++--------- 4 files changed, 90 insertions(+), 37 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 5c508179e5..defd8b5c84 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -8,7 +8,7 @@ import ( ) type Callee interface { - ReturnGas(*big.Int, *State) + ReturnGas(*big.Int, *big.Int, *State) Address() []byte } @@ -83,18 +83,16 @@ func (c *Closure) Return(ret []byte) []byte { // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.Gas, c.State) + c.callee.ReturnGas(c.Gas, c.Price, c.State) } else { - c.object.ReturnGas(c.Gas, c.State) - // TODO incase it's a POST contract we gotta serialise the contract again. - // But it's not yet defined + c.object.ReturnGas(c.Gas, c.Price, c.State) } return ret } // Implement the Callee interface -func (c *Closure) ReturnGas(gas *big.Int, state *State) { +func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8b4de0c4f3..f562e5b04d 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -70,8 +71,9 @@ func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { } // Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(val *big.Int, state *State) { - c.AddAmount(val) +func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { + remainder := new(big.Int).Mul(gas, price) + c.AddAmount(remainder) } func (c *StateObject) AddAmount(amount *big.Int) { @@ -82,18 +84,33 @@ func (c *StateObject) SubAmount(amount *big.Int) { c.Amount.Sub(c.Amount, amount) } +func (c *StateObject) ConvertGas(gas, price *big.Int) error { + total := new(big.Int).Mul(gas, price) + if total.Cmp(c.Amount) > 0 { + return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total) + } + + c.SubAmount(total) + + return nil +} + +// Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address } +// Returns the main script body func (c *StateObject) Script() []byte { return c.script } +// Returns the initialization script func (c *StateObject) Init() []byte { return c.initScript } +// State object encoding methods func (c *StateObject) RlpEncode() []byte { var root interface{} if c.state != nil { @@ -113,6 +130,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } +// Converts an transaction in to a state object func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient if tx.IsContract() { diff --git a/ethchain/vm.go b/ethchain/vm.go index 85aefa685d..c249adfebc 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -102,10 +102,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } */ - // TODO Get each instruction cost properly gas := new(big.Int) useGas := func(amount *big.Int) { - gas.Add(gas, new(big.Int).Mul(amount, closure.Price)) + gas.Add(gas, amount) } switch op { @@ -142,6 +141,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + + // Sub the amount of gas from the remaining closure.Gas.Sub(closure.Gas, gas) switch op { @@ -157,7 +158,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oSUB: @@ -165,7 +165,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oMUL: @@ -173,7 +172,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) - base.Mod(base, Pow256) // Pop result back on the stack stack.Push(base) case oDIV: @@ -325,7 +323,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case oGASPRICE: - // TODO + stack.Push(closure.Price) // 0x40 range case oPREVHASH: @@ -339,7 +337,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oDIFFICULTY: stack.Push(vm.vars.Diff) case oGASLIMIT: - // TODO + // TODO + stack.Push(big.NewInt(0)) // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -399,11 +398,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oJUMP: require(1) pc = stack.Pop() + // Reduce pc by one because of the increment that's at the end of this for loop + pc.Sub(pc, ethutil.Big1) case oJUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos + pc.Sub(pc, ethutil.Big1) } case oPC: stack.Push(pc) @@ -421,21 +423,39 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro inSize, inOffset := stack.Popn() // Pop return size and offset retSize, retOffset := stack.Popn() + // Make sure there's enough gas + if closure.Gas.Cmp(gas) < 0 { + stack.Push(ethutil.BigFalse) + + break + } // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) - // Executer the closure and get the return value (if any) - ret, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - } else { - stack.Push(ethutil.BigTrue) - } - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + if contract != nil { + // Prepay for the gas + // If gas is set to 0 use all remaining gas for the next call + if gas.Cmp(big.NewInt(0)) == 0 { + gas = closure.Gas + } + closure.Gas.Sub(closure.Gas, gas) + // Create a new callable closure + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) + // Executer the closure and get the return value (if any) + ret, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } else { + ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stack.Push(ethutil.BigFalse) + } case oRETURN: require(2) size, offset := stack.Popn() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index f66f2a8966..cca9b876a7 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,9 +86,9 @@ func TestRun4(t *testing.T) { int32 a = 10 int32 b = 20 if a > b { - int32 c = this.caller() + int32 c = this.Caller() } - exit() + Exit() `), false) script := ethutil.Assemble(asm...) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) @@ -103,8 +103,9 @@ func TestRun4(t *testing.T) { store[1000] = 10^20 } - store[1001] = this.value() * 20 - store[this.origin()] = store[this.origin()] + 1000 + + store[1001] = this.Value() * 20 + store[this.Origin()] = store[this.Origin()] + 1000 if store[1001] > 20 { store[1001] = 10^50 @@ -112,8 +113,18 @@ func TestRun4(t *testing.T) { int8 ret = 0 int8 arg = 10 - store[1002] = "a46df28529eb8aa8b8c025b0b413c5f4b688352f" - call(store[1002], 0, 100000000, arg, ret) + Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) + + big t + for int8 i = 0; i < 10; i++ { + t = i + } + + if 10 > 20 { + int8 shouldnt = 2 + } else { + int8 should = 1 + } `), false) if err != nil { fmt.Println(err) @@ -125,10 +136,17 @@ func TestRun4(t *testing.T) { callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) // Contract addr as test address + gas := big.NewInt(1000) + gasPrice := big.NewInt(10) account := NewAccount(ContractAddr, big.NewInt(10000000)) - fmt.Println(account) + fmt.Println("account.Amount =", account.Amount) c := MakeContract(callerTx, state) - callerClosure := NewClosure(account, c, c.script, state, big.NewInt(1000000000), big.NewInt(10), big.NewInt(0)) + e := account.ConvertGas(gas, gasPrice) + if e != nil { + fmt.Println(err) + } + fmt.Println("account.Amount =", account.Amount) + callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) vm := NewVm(state, RuntimeVars{ Origin: account.Address(), @@ -138,11 +156,11 @@ func TestRun4(t *testing.T) { Time: 1, Diff: big.NewInt(256), }) - _, e := callerClosure.Call(vm, nil, nil) + _, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } - fmt.Println(account) + fmt.Println("account.Amount =", account.Amount) } func TestRun5(t *testing.T) { @@ -156,6 +174,5 @@ func TestRun5(t *testing.T) { } exit() `), false) - script := ethutil.Assemble(asm...) - fmt.Println(Disassemble(script)) + ethutil.Assemble(asm...) } From 11c26e32114dabc6524ad9fb1f868440f5d3fff3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:50:17 +0200 Subject: [PATCH 0233/1237] Implemented ethereum package reader --- ethutil/package.go | 123 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 ethutil/package.go diff --git a/ethutil/package.go b/ethutil/package.go new file mode 100644 index 0000000000..e5df989d23 --- /dev/null +++ b/ethutil/package.go @@ -0,0 +1,123 @@ +package ethutil + +import ( + "archive/zip" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "strings" +) + +// Manifest object +// +// The manifest object holds all the relevant information supplied with the +// the manifest specified in the package +type Manifest struct { + Entry string + Height, Width int +} + +// External package +// +// External package contains the main html file and manifest +type ExtPackage struct { + EntryHtml string + Manifest *Manifest +} + +// Read file +// +// Read a given compressed file and returns the read bytes. +// Returns an error otherwise +func ReadFile(f *zip.File) ([]byte, error) { + rc, err := f.Open() + if err != nil { + return nil, err + } + defer rc.Close() + + content, err := ioutil.ReadAll(rc) + if err != nil { + return nil, err + } + + return content, nil +} + +// Reads manifest +// +// Reads and returns a manifest object. Returns error otherwise +func ReadManifest(m []byte) (*Manifest, error) { + var manifest Manifest + + dec := json.NewDecoder(strings.NewReader(string(m))) + if err := dec.Decode(&manifest); err == io.EOF { + } else if err != nil { + return nil, err + } + + return &manifest, nil +} + +// Find file in archive +// +// Returns the index of the given file name if it exists. -1 if file not found +func FindFileInArchive(fn string, files []*zip.File) (index int) { + index = -1 + // Find the manifest first + for i, f := range files { + if f.Name == fn { + index = i + } + } + + return +} + +// Open package +// +// Opens a prepared ethereum package +// Reads the manifest file and determines file contents and returns and +// the external package. +func OpenPackage(fn string) (*ExtPackage, error) { + r, err := zip.OpenReader(fn) + if err != nil { + return nil, err + } + defer r.Close() + + manifestIndex := FindFileInArchive("manifest.json", r.File) + + if manifestIndex < 0 { + return nil, fmt.Errorf("No manifest file found in archive") + } + + f, err := ReadFile(r.File[manifestIndex]) + if err != nil { + return nil, err + } + + manifest, err := ReadManifest(f) + if err != nil { + return nil, err + } + + if manifest.Entry == "" { + return nil, fmt.Errorf("Entry file specified but appears to be empty: %s", manifest.Entry) + } + + entryIndex := FindFileInArchive(manifest.Entry, r.File) + if entryIndex < 0 { + return nil, fmt.Errorf("Entry file not found: '%s'", manifest.Entry) + } + + f, err = ReadFile(r.File[entryIndex]) + if err != nil { + return nil, err + } + + extPackage := &ExtPackage{string(f), manifest} + + return extPackage, nil +} From 61cd1594b52514244efcb47bd93722aaec0fe456 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:50:38 +0200 Subject: [PATCH 0234/1237] Fixed gas, price & value setters on initialization --- ethchain/closure.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index defd8b5c84..f8135c5143 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -35,7 +35,15 @@ type Closure struct { // Create a new closure for the given data items func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { - return &Closure{callee, object, script, state, gas, price, val, nil} + c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} + + // In most cases gas, price and value are pointers to transaction objects + // and we don't want the transaction's values to change. + c.Gas = new(big.Int).Set(gas) + c.Price = new(big.Int).Set(price) + c.Value = new(big.Int).Set(val) + + return c } // Retuns the x element in data slice From 3a9a252f6e44abb0f45f57a46c0fa91e2f73c545 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 11:51:04 +0200 Subject: [PATCH 0235/1237] Fixed minor issue with gas and added state object init --- ethchain/state_manager.go | 53 +++++++++++++++++++++++++++++++----- ethchain/transaction.go | 14 +++++----- ethchain/transaction_pool.go | 4 +-- ethchain/types.go | 6 ++-- ethchain/vm.go | 24 ++++++++-------- ethutil/parsing.go | 49 +++++++++++++++++++++++++++++++-- ethutil/parsing_test.go | 41 ++++++++++++++-------------- 7 files changed, 135 insertions(+), 56 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 75a78e9f3b..23da77fae3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -91,11 +91,15 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(tx *Transaction) { +func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { contract := MakeContract(tx, sm.procState) if contract != nil { sm.procState.states[string(tx.Hash()[12:])] = contract.state + + return contract } + + return nil } // Apply transactions uses the transaction passed to it and applies them onto @@ -103,11 +107,44 @@ func (sm *StateManager) MakeContract(tx *Transaction) { func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { + fmt.Printf("Processing Tx: %x\n", tx.Hash()) // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. if tx.IsContract() { - sm.MakeContract(tx) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + if err == nil { + contract := sm.MakeContract(tx) + if contract != nil { + sm.EvalScript(contract.Init(), contract, tx, block) + } else { + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + } + } else { + ethutil.Config.Log.Infoln("[STATE] contract create:", err) + } + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + contract := sm.procState.GetContract(tx.Recipient) + if err == nil && len(contract.Script()) > 0 { + sm.EvalScript(contract.Script(), contract, tx, block) + } else if err != nil { + ethutil.Config.Log.Infoln("[STATE] process:", err) + } + } + } + // Process each transaction/contract + for _, tx := range txs { + // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. + if tx.IsContract() { + contract := sm.MakeContract(tx) + if contract != nil { + sm.EvalScript(contract.Init(), contract, tx, block) + } else { + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + } } else { // Figure out if the address this transaction was sent to is a // contract or an actual account. In case of a contract, we process that @@ -303,11 +340,13 @@ func (sm *StateManager) Stop() { func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { // Recovering function in case the VM had any errors - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from VM execution with err =", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + } + }() + */ caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 1e43a2bae4..421f26c98c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -23,12 +23,12 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, GasPrice: gasprice, Data: script, Init: init, contractCreation: true} +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction { + return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true} } -func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasprice, Gas: gas, Data: data} +func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -46,9 +46,10 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, string(tx.Data)} + data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + if tx.contractCreation { - data = append(data, string(tx.Init)) + data = append(data, tx.Init) } return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) @@ -112,7 +113,6 @@ func (tx *Transaction) RlpData() interface{} { if tx.contractCreation { data = append(data, tx.Init) } - //d := ethutil.NewSliceValue(tx.Data).Slice() return append(data, tx.v, tx.r, tx.s) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 5cdda17e25..957381ac76 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -104,7 +104,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // funds won't invalidate this transaction but simple ignores it. totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) if sender.Amount.Cmp(totAmount) < 0 { - return errors.New("[TXPL] Insufficient amount in sender's account") + return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } if sender.Nonce != tx.Nonce { @@ -119,8 +119,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) - } else if toContract { - sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) diff --git a/ethchain/types.go b/ethchain/types.go index 24aad82c37..827d4f27f4 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -35,7 +35,7 @@ const ( oORIGIN = 0x32 oCALLER = 0x33 oCALLVALUE = 0x34 - oCALLDATA = 0x35 + oCALLDATALOAD = 0x35 oCALLDATASIZE = 0x36 oGASPRICE = 0x37 @@ -106,7 +106,7 @@ var opCodeToString = map[OpCode]string{ oORIGIN: "ORIGIN", oCALLER: "CALLER", oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", + oCALLDATALOAD: "CALLDATALOAD", oCALLDATASIZE: "CALLDATASIZE", oGASPRICE: "TXGASPRICE", @@ -180,7 +180,7 @@ var OpCodes = map[string]byte{ "ORIGIN": 0x32, "CALLER": 0x33, "CALLVALUE": 0x34, - "CALLDATA": 0x35, + "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, "GASPRICE": 0x38, diff --git a/ethchain/vm.go b/ethchain/vm.go index c249adfebc..33541cb3ba 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -84,11 +84,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // The base for all big integer arithmetic base := new(big.Int) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("# op\n") + } for { step++ @@ -96,11 +94,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } gas := new(big.Int) useGas := func(amount *big.Int) { @@ -316,10 +312,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLVALUE: // FIXME: Original value of the call, not the current value stack.Push(closure.Value) - case oCALLDATA: + case oCALLDATALOAD: require(1) - offset := stack.Pop() - mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) + offset := stack.Pop().Int64() + val := closure.Args[offset : offset+31] + + stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case oGASPRICE: diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 328704caea..9775cf328e 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -3,7 +3,7 @@ package ethutil import ( _ "fmt" "math/big" - "regexp" + _ "regexp" ) // Op codes @@ -143,7 +143,6 @@ init() { main() { // main something } -*/ func PreProcess(data string) (mainInput, initInput string) { reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" mainReg := regexp.MustCompile("main" + reg) @@ -163,3 +162,49 @@ func PreProcess(data string) (mainInput, initInput string) { return } +*/ + +// Very, very dumb parser. Heed no attention :-) +func FindFor(blockMatcher, input string) string { + curCount := -1 + length := len(blockMatcher) + matchfst := rune(blockMatcher[0]) + var currStr string + + for i, run := range input { + // Find init + if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { + curCount = 0 + } else if curCount > -1 { + if run == '{' { + curCount++ + if curCount == 1 { + continue + } + } else if run == '}' { + curCount-- + if curCount == 0 { + // we are done + curCount = -1 + break + } + } + + if curCount > 0 { + currStr += string(run) + } + } + } + + return currStr +} + +func PreProcess(data string) (mainInput, initInput string) { + mainInput = FindFor("main", data) + if mainInput == "" { + mainInput = data + } + initInput = FindFor("init", data) + + return +} diff --git a/ethutil/parsing_test.go b/ethutil/parsing_test.go index 6b59777e69..a9ad347dd2 100644 --- a/ethutil/parsing_test.go +++ b/ethutil/parsing_test.go @@ -1,32 +1,31 @@ package ethutil -/* import ( - "math" + "fmt" "testing" ) -func TestCompile(t *testing.T) { - instr, err := CompileInstr("PUSH") - - if err != nil { - t.Error("Failed compiling instruction") +func TestPreProcess(t *testing.T) { + main, init := PreProcess(` + init { + // init + if a > b { + if { + } + } } - calc := (48 + 0*256 + 0*int64(math.Pow(256, 2))) - if BigD(instr).Int64() != calc { - t.Error("Expected", calc, ", got:", instr) + main { + // main + if a > b { + if c > d { + } + } } -} - -func TestValidInstr(t *testing.T) { - op, args, err := Instr("68163") - if err != nil { - t.Error("Error decoding instruction") - } + `) + fmt.Println("main") + fmt.Println(main) + fmt.Println("init") + fmt.Println(init) } - -func TestInvalidInstr(t *testing.T) { -} -*/ From 6b08efabf837c9c763e116b91dc9b566a2c76d80 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 12:14:28 +0200 Subject: [PATCH 0236/1237] @maranh see comment --- ethminer/miner.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 5bbf6b977f..d1636cceeb 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -61,10 +61,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - log.Println("[MINER] Got new block via Reactor") + //log.Println("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - log.Println("[MINER] New top block found resetting state") + //log.Println("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -86,7 +86,7 @@ func (miner *Miner) listener() { } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { - log.Println("[MINER] Adding uncle block") + //log.Println("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } @@ -94,7 +94,7 @@ func (miner *Miner) listener() { } if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { - log.Println("[MINER] Got new transaction from Reactor", tx) + //log.Println("[MINER] Got new transaction from Reactor", tx) found := false for _, ctx := range miner.txs { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { @@ -103,12 +103,12 @@ func (miner *Miner) listener() { } if found == false { - log.Println("[MINER] We did not know about this transaction, adding") + //log.Println("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block.SetTransactions(miner.txs) } else { - log.Println("[MINER] We already had this transaction, ignoring") + //log.Println("[MINER] We already had this transaction, ignoring") } } default: @@ -127,7 +127,7 @@ func (miner *Miner) listener() { miner.ethereum.StateManager().AccumelateRewards(miner.block) // Search the nonce - log.Println("[MINER] Initialision complete, starting mining") + //log.Println("[MINER] Initialision complete, starting mining") miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) if miner.block.Nonce != nil { miner.ethereum.StateManager().PrepareDefault(miner.block) @@ -136,6 +136,7 @@ func (miner *Miner) listener() { log.Println("Error result from process block:", err) } else { + // XXX @maranh This is already done in the state manager, why a 2nd time? if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) } From f7d4e3cd6b276e4d66abe89b4f1b2dfa2faf90df Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:52:50 +0200 Subject: [PATCH 0237/1237] Copy over bytes from previous root Copy over instead of directly using the previous root. This is order to avoid resetting problems --- ethchain/block.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethchain/block.go b/ethchain/block.go index 8c93947fb6..c9197c69a1 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -80,6 +80,9 @@ func CreateBlock(root interface{}, extra string, txes []*Transaction) *Block { + // Copy over the bytes + copiedRoot := ethutil.NewValue(root).Bytes() + block := &Block{ // Slice of transactions to include in this block transactions: txes, @@ -95,7 +98,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, copiedRoot)) for _, tx := range txes { block.MakeContract(tx) From ef7f3f36e261bc500016dac0a703c5b7931a1721 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:53:34 +0200 Subject: [PATCH 0238/1237] Renamed CALLDATA to CALLDATALOAD --- ethutil/parsing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/parsing.go b/ethutil/parsing.go index 9775cf328e..514fd92cde 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -39,7 +39,7 @@ var OpCodes = map[string]byte{ "ORIGIN": 0x32, "CALLER": 0x33, "CALLVALUE": 0x34, - "CALLDATA": 0x35, + "CALLDATALOAD": 0x35, "CALLDATASIZE": 0x36, "GASPRICE": 0x38, From c81804444f69ae1653d54551d8555ff924651cd9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:53:53 +0200 Subject: [PATCH 0239/1237] Call initial closure with proper tx argument --- ethchain/block_chain.go | 1 + ethchain/state_manager.go | 33 +-------------------------------- ethchain/vm.go | 4 +++- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index d65c38fe46..08886c9cda 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -46,6 +46,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { hash = bc.LastBlockHash lastBlockTime = bc.CurrentBlock.Time } + block := CreateBlock( root, hash, diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 23da77fae3..668a44c3f8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -133,37 +133,6 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } } - // Process each transaction/contract - for _, tx := range txs { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - contract := sm.MakeContract(tx) - if contract != nil { - sm.EvalScript(contract.Init(), contract, tx, block) - } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") - } - } else { - // Figure out if the address this transaction was sent to is a - // contract or an actual account. In case of a contract, we process that - // contract instead of moving funds between accounts. - var err error - if contract := sm.procState.GetContract(tx.Recipient); contract != nil { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true) - if err == nil { - sm.EvalScript(contract.Script(), contract, tx, block) - } - } else { - err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - } - - if err != nil { - ethutil.Config.Log.Infoln("[STATE]", err) - } - } - } } // The prepare function, prepares the state manager for the next @@ -359,7 +328,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Diff: block.Difficulty, //Price: tx.GasPrice, }) - closure.Call(vm, nil, nil) + closure.Call(vm, tx.Data, nil) // Update the account (refunds) sm.procState.UpdateStateObject(caller) diff --git a/ethchain/vm.go b/ethchain/vm.go index 33541cb3ba..90b591f506 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,11 +53,12 @@ var isRequireError = false func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { // Recover from any require exception defer func() { - if r := recover(); r != nil && isRequireError { + if r := recover(); r != nil /*&& isRequireError*/ { fmt.Println(r) ret = closure.Return(nil) err = fmt.Errorf("%v", r) + fmt.Println("vm err", err) } }() @@ -315,6 +316,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() + fmt.Println(closure.Args) val := closure.Args[offset : offset+31] stack.Push(ethutil.BigD(val)) From 0651af9dfd701ba09e6c734f21eff85f61454476 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 23 Apr 2014 15:54:15 +0200 Subject: [PATCH 0240/1237] Removed some log statements and disabled additional validation checks --- ethminer/miner.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index d1636cceeb..08a4626e4f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -134,14 +134,18 @@ func (miner *Miner) listener() { err := miner.ethereum.StateManager().ProcessBlock(miner.block, true) if err != nil { log.Println("Error result from process block:", err) + miner.block.State().Reset() } else { - // XXX @maranh This is already done in the state manager, why a 2nd time? - if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { - log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) - } + /* + // XXX @maranh This is already done in the state manager, why a 2nd time? + if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { + log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) + } + */ miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) + log.Println(miner.block) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) From 1c85d8c66b9db23687b0446b4a7e97e3e61fe188 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 00:00:50 +0200 Subject: [PATCH 0241/1237] Minor improvements and bug fixes * Fixed VM base bug --- ethchain/state.go | 4 ++-- ethchain/state_manager.go | 2 ++ ethchain/transaction_pool.go | 8 ++++---- ethchain/vm.go | 6 ++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 6558489325..fa63accf8f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -34,12 +34,12 @@ func (s *State) Reset() { // Syncs the trie and all siblings func (s *State) Sync() { - s.trie.Sync() - // Sync all nested states for _, state := range s.states { state.Sync() } + + s.trie.Sync() } // Purges the current trie. diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 668a44c3f8..29c3cd16b1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -117,6 +117,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { contract := sm.MakeContract(tx) if contract != nil { sm.EvalScript(contract.Init(), contract, tx, block) + fmt.Printf("state root of contract %x\n", contract.State().Root()) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -332,4 +333,5 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(caller) + sm.procState.UpdateStateObject(object) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 957381ac76..91fad2635b 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -100,6 +100,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Get the sender sender := block.state.GetAccount(tx.Sender()) + if sender.Nonce != tx.Nonce { + return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + } + // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) @@ -107,10 +111,6 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } - if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) - } - // Get the receiver receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 diff --git a/ethchain/vm.go b/ethchain/vm.go index 90b591f506..7df63b181e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -82,14 +82,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc := big.NewInt(0) // Current step count step := 0 - // The base for all big integer arithmetic - base := new(big.Int) if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } for { + // The base for all big integer arithmetic + base := new(big.Int) + step++ // Get the memory location of pc val := closure.Get(pc) @@ -390,6 +391,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + fmt.Printf("load %x = %v\n", loc.Bytes(), val.BigInt()) stack.Push(val.BigInt()) case oSSTORE: require(2) From ee7c16a8d977389c63ef60ea6c5eaff11e150ca4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 13:30:57 +0200 Subject: [PATCH 0242/1237] Fixed Base problem and sload/sstore --- ethchain/vm.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 7df63b181e..bc4c65d03e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -121,7 +121,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - useGas(base.Mul(mult, GasSStore)) + useGas(new(big.Int).Mul(mult, GasSStore)) case oBALANCE: useGas(GasBalance) case oCREATE: @@ -156,6 +156,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) + fmt.Println(x, y, base) // Pop result back on the stack stack.Push(base) case oSUB: @@ -317,8 +318,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() - fmt.Println(closure.Args) - val := closure.Args[offset : offset+31] + val := closure.Args[offset : offset+32] + fmt.Println(ethutil.BigD(val)) stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: From f3818478e2601df1d9cfc9cc36b021366f870856 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 24 Apr 2014 13:48:33 +0200 Subject: [PATCH 0243/1237] Removed debug & unused functions --- ethchain/block.go | 25 ------------------------- ethminer/miner.go | 1 - 2 files changed, 26 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index c9197c69a1..d95ebf4b58 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -116,11 +116,6 @@ func (block *Block) HashNoNonce() []byte { return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) } -func (block *Block) PrintHash() { - fmt.Println(block) - fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce}))) -} - func (block *Block) State() *State { return block.state } @@ -182,26 +177,6 @@ func (block *Block) MakeContract(tx *Transaction) { } /////// Block Encoding -func (block *Block) encodedUncles() interface{} { - uncles := make([]interface{}, len(block.Uncles)) - for i, uncle := range block.Uncles { - uncles[i] = uncle.RlpEncode() - } - - return uncles -} - -func (block *Block) encodedTxs() interface{} { - // Marshal the transactions of this block - encTx := make([]interface{}, len(block.transactions)) - for i, tx := range block.transactions { - // Cast it to a string (safe) - encTx[i] = tx.RlpData() - } - - return encTx -} - func (block *Block) rlpTxs() interface{} { // Marshal the transactions of this block encTx := make([]interface{}, len(block.transactions)) diff --git a/ethminer/miner.go b/ethminer/miner.go index 08a4626e4f..791e8e4024 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -145,7 +145,6 @@ func (miner *Miner) listener() { */ miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) - log.Println(miner.block) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) From 0f93da400ab7fd238eb7286f14c229d780f73636 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 01:47:55 +0200 Subject: [PATCH 0244/1237] Added new state object change echanism --- ethchain/state_manager.go | 33 +++++++++++++------ ethchain/state_object.go | 67 +++++++++++++++++++++------------------ ethchain/vm.go | 6 ++-- ethutil/value.go | 7 +++- 4 files changed, 69 insertions(+), 44 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 29c3cd16b1..1ab58386a2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,6 +50,10 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + + // It's generally know that a map is faster for small lookups than arrays + // we'll eventually have to make a decision if the map grows too large + watchedAddresses map[string]bool } func NewStateManager(ethereum EthManager) *StateManager { @@ -60,6 +64,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Ethereum: ethereum, stateObjectCache: NewStateObjectCache(), bc: ethereum.BlockChain(), + watchedAddresses: make(map[string]bool), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -309,18 +314,9 @@ func (sm *StateManager) Stop() { } func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - // Recovering function in case the VM had any errors - /* - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from VM execution with err =", r) - } - }() - */ - caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) - vm := NewVm(sm.procState, RuntimeVars{ + vm := NewVm(sm.procState, sm, RuntimeVars{ Origin: caller.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, @@ -333,5 +329,22 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(caller) + sm.Changed(caller) sm.procState.UpdateStateObject(object) + sm.Changed(object) +} + +// Watch a specific address +func (sm *StateManager) Watch(addr []byte) { + if !sm.watchedAddresses[string(addr)] { + sm.watchedAddresses[string(addr)] = true + } +} + +// The following objects are used when changing a value and using the "watched" attribute +// to determine whether the reactor should be used to notify any subscribers on the address +func (sm *StateManager) Changed(stateObject *StateObject) { + if sm.watchedAddresses[string(stateObject.Address())] { + sm.Ethereum.Reactor().Post("addressChanged", stateObject) + } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index f562e5b04d..8d86ef44ee 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -18,6 +18,28 @@ type StateObject struct { initScript []byte } +// Converts an transaction in to a state object +func MakeContract(tx *Transaction, state *State) *StateObject { + // Create contract if there's no recipient + if tx.IsContract() { + // FIXME + addr := tx.Hash()[12:] + + value := tx.Value + contract := NewContract(addr, value, []byte("")) + state.UpdateStateObject(contract) + + contract.script = tx.Data + contract.initScript = tx.Init + + state.UpdateStateObject(contract) + + return contract + } + + return nil +} + func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) @@ -39,6 +61,10 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { return object } +func (c *StateObject) State() *State { + return c.state +} + func (c *StateObject) Addr(addr []byte) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } @@ -47,8 +73,10 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) State() *State { - return c.state +func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { + addr := ethutil.BigToBytes(num, 256) + c.SetAddr(addr, val) + //c.state.trie.Update(string(addr), string(val.Encode())) } func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { @@ -65,11 +93,6 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]}) } -func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) - c.state.trie.Update(string(addr), string(val.Encode())) -} - // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { remainder := new(big.Int).Mul(gas, price) @@ -77,11 +100,15 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { } func (c *StateObject) AddAmount(amount *big.Int) { - c.Amount.Add(c.Amount, amount) + c.SetAmount(new(big.Int).Add(c.Amount, amount)) } func (c *StateObject) SubAmount(amount *big.Int) { - c.Amount.Sub(c.Amount, amount) + c.SetAmount(new(big.Int).Sub(c.Amount, amount)) +} + +func (c *StateObject) SetAmount(amount *big.Int) { + c.Amount = amount } func (c *StateObject) ConvertGas(gas, price *big.Int) error { @@ -130,28 +157,6 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *State) *StateObject { - // Create contract if there's no recipient - if tx.IsContract() { - // FIXME - addr := tx.Hash()[12:] - - value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.UpdateStateObject(contract) - - contract.script = tx.Data - contract.initScript = tx.Init - - state.UpdateStateObject(contract) - - return contract - } - - return nil -} - // The cached state and state object cache are helpers which will give you somewhat // control over the nonce. When creating new transactions you're interested in the 'next' // nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. diff --git a/ethchain/vm.go b/ethchain/vm.go index bc4c65d03e..93557007dc 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -30,6 +30,8 @@ type Vm struct { vars RuntimeVars state *State + + stateManager *StateManager } type RuntimeVars struct { @@ -42,8 +44,8 @@ type RuntimeVars struct { TxData []string } -func NewVm(state *State, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state} +func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { + return &Vm{vars: vars, state: state, stateManager: stateManager} } var Pow256 = ethutil.BigPow(2, 256) diff --git a/ethutil/value.go b/ethutil/value.go index 04131aba90..b7756f9b16 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -20,7 +20,12 @@ func (val *Value) String() string { } func NewValue(val interface{}) *Value { - return &Value{Val: val} + t := val + if v, ok := val.(*Value); ok { + t = v.Val + } + + return &Value{Val: t} } func (val *Value) Type() reflect.Kind { From d3a159ad3d6842ffb137fc1df48a54703345faa4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 01:54:45 +0200 Subject: [PATCH 0245/1237] Fixed tests --- ethchain/vm_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index cca9b876a7..75a4f5afba 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -91,7 +91,7 @@ func TestRun4(t *testing.T) { Exit() `), false) script := ethutil.Assemble(asm...) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script, nil) + tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateStateObject(contract) @@ -133,7 +133,7 @@ func TestRun4(t *testing.T) { fmt.Println(asm) callerScript := ethutil.Assemble(asm...) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript, nil) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) // Contract addr as test address gas := big.NewInt(1000) @@ -148,7 +148,7 @@ func TestRun4(t *testing.T) { fmt.Println("account.Amount =", account.Amount) callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) - vm := NewVm(state, RuntimeVars{ + vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), BlockNumber: 1, PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), From ca6e3f6defae958cece52ee7d26ca1b53b0adebb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 02:06:25 +0200 Subject: [PATCH 0246/1237] Notify of changes --- ethchain/vm.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 93557007dc..a4b4d351ba 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -56,8 +56,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Recover from any require exception defer func() { if r := recover(); r != nil /*&& isRequireError*/ { - fmt.Println(r) - ret = closure.Return(nil) err = fmt.Errorf("%v", r) fmt.Println("vm err", err) @@ -158,7 +156,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) - fmt.Println(x, y, base) // Pop result back on the stack stack.Push(base) case oSUB: @@ -321,7 +318,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) offset := stack.Pop().Int64() val := closure.Args[offset : offset+32] - fmt.Println(ethutil.BigD(val)) stack.Push(ethutil.BigD(val)) case oCALLDATASIZE: @@ -394,7 +390,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) - fmt.Printf("load %x = %v\n", loc.Bytes(), val.BigInt()) stack.Push(val.BigInt()) case oSSTORE: require(2) @@ -452,8 +447,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ret, err := closure.Call(vm, args, hook) if err != nil { stack.Push(ethutil.BigFalse) + // Reset the changes applied this object + //contract.State().Reset() } else { stack.Push(ethutil.BigTrue) + // Notify of the changes + vm.stateManager.Changed(contract) } mem.Set(retOffset.Int64(), retSize.Int64(), ret) From 05d2d8f27d0bea5b20be9bc3b4a259a12298ecab Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 26 Apr 2014 02:11:00 +0200 Subject: [PATCH 0247/1237] Actually convert gas --- ethchain/state_manager.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1ab58386a2..628ab6a27f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -314,10 +314,17 @@ func (sm *StateManager) Stop() { } func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - caller := sm.procState.GetAccount(tx.Sender()) - closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) + account := sm.procState.GetAccount(tx.Sender()) + + err := account.ConvertGas(tx.Gas, tx.GasPrice) + if err != nil { + ethutil.Config.Log.Debugln(err) + return + } + + closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) vm := NewVm(sm.procState, sm, RuntimeVars{ - Origin: caller.Address(), + Origin: account.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, Coinbase: block.Coinbase, @@ -328,8 +335,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans closure.Call(vm, tx.Data, nil) // Update the account (refunds) - sm.procState.UpdateStateObject(caller) - sm.Changed(caller) + sm.procState.UpdateStateObject(account) + sm.Changed(account) sm.procState.UpdateStateObject(object) sm.Changed(object) } From 16e52327a4baa5547c38965fce53b3ff40b98173 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 16:50:44 +0200 Subject: [PATCH 0248/1237] Upped version number --- README.md | 2 +- ethchain/closure.go | 23 +++++++++++------ ethchain/stack.go | 12 +++++++++ ethchain/state.go | 29 +++++++++++++++++++++ ethchain/state_object.go | 4 +++ ethchain/vm.go | 54 ++++++++++++++++++++++++++++++++++++++-- ethutil/big.go | 8 ++++++ ethutil/common.go | 7 ++++++ ethutil/config.go | 2 +- 9 files changed, 129 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0f0a33edb0..9d810643bf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 3.5". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethchain/closure.go b/ethchain/closure.go index f8135c5143..57abaa91eb 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -8,21 +8,24 @@ import ( ) type Callee interface { - ReturnGas(*big.Int, *big.Int, *State) - Address() []byte } type Reference interface { Callee - ethutil.RlpEncodable +} + +type ClosureRef interface { + ReturnGas(*big.Int, *big.Int, *State) + Address() []byte GetMem(*big.Int) *ethutil.Value SetMem(*big.Int, *ethutil.Value) + N() *big.Int } // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee Callee - object Reference + callee ClosureRef + object ClosureRef Script []byte State *State @@ -34,7 +37,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -105,10 +108,14 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() Reference { +func (c *Closure) Object() ClosureRef { return c.object } -func (c *Closure) Callee() Callee { +func (c *Closure) Callee() ClosureRef { return c.callee } + +func (c *Closure) N() *big.Int { + return c.object.N() +} diff --git a/ethchain/stack.go b/ethchain/stack.go index 2883600627..e9297b3246 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -67,6 +67,18 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { func (st *Stack) Push(d *big.Int) { st.data = append(st.data, d) } + +func (st *Stack) Get(amount *big.Int) []*big.Int { + // offset + size <= len(data) + length := big.NewInt(int64(len(st.data))) + if amount.Cmp(length) <= 0 { + start := new(big.Int).Sub(length, amount) + return st.data[start.Int64():length.Int64()] + } + + return nil +} + func (st *Stack) Print() { fmt.Println("### stack ###") if len(st.data) > 0 { diff --git a/ethchain/state.go b/ethchain/state.go index fa63accf8f..1b5655d4cd 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -47,6 +47,7 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } +// XXX Deprecated func (s *State) GetContract(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -68,6 +69,32 @@ func (s *State) GetContract(addr []byte) *StateObject { return contract } +func (s *State) GetStateObject(addr []byte) *StateObject { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + stateObject := NewStateObjectFromBytes(addr, []byte(data)) + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + stateObject.state = cachedStateObject + } else { + // If it isn't cached, cache the state + s.states[string(addr)] = stateObject.state + } + + return stateObject +} + +func (s *State) SetStateObject(stateObject *StateObject) { + s.states[string(stateObject.address)] = stateObject.state + + s.UpdateStateObject(stateObject) +} + func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { @@ -97,6 +124,7 @@ const ( UnknownTy ) +/* // Returns the object stored at key and the type stored at key // Returns nil if nothing is stored func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { @@ -124,6 +152,7 @@ func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { return val, typ } +*/ // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8d86ef44ee..8e921795d7 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -65,6 +65,10 @@ func (c *StateObject) State() *State { return c.state } +func (c *StateObject) N() *big.Int { + return big.NewInt(int64(c.Nonce)) +} + func (c *StateObject) Addr(addr []byte) *ethutil.Value { return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) } diff --git a/ethchain/vm.go b/ethchain/vm.go index a4b4d351ba..b983e88ff1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -20,6 +20,17 @@ var ( GasMemory = big.NewInt(1) ) +func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { + totalGas := new(big.Int) + totalGas.Add(totalGas, GasCreate) + + txTotalBytes := new(big.Int).Add(initSize, scriptSize) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore)) + + return totalGas +} + type Vm struct { txPool *TxPool // Stack for processing contracts @@ -125,7 +136,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oBALANCE: useGas(GasBalance) case oCREATE: - useGas(GasCreate) + require(3) + + args := stack.Get(big.NewInt(3)) + initSize := new(big.Int).Add(args[1], args[0]) + + useGas(CalculateTxGas(initSize, ethutil.Big0)) case oCALL: useGas(GasCall) case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: @@ -413,6 +429,39 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range case oCREATE: + require(3) + + value := stack.Pop() + size, offset := stack.Popn() + + // Generate a new address + addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) + // Create a new contract + contract := NewContract(addr, value, []byte("")) + // Set the init script + contract.initScript = mem.Get(offset.Int64(), size.Int64()) + // Transfer all remaining gas to the new + // contract so it may run the init script + gas := new(big.Int).Set(closure.Gas) + closure.Gas.Sub(closure.Gas, gas) + // Create the closure + closure := NewClosure(closure.callee, + closure.Object(), + contract.initScript, + vm.state, + gas, + closure.Price, + value) + // Call the closure and set the return value as + // main script. + closure.Script, err = closure.Call(vm, nil, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigD(addr)) + + vm.state.SetStateObject(contract) + } case oCALL: require(7) // Closure addr @@ -438,7 +487,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Prepay for the gas // If gas is set to 0 use all remaining gas for the next call if gas.Cmp(big.NewInt(0)) == 0 { - gas = closure.Gas + // Copy + gas = new(big.Int).Set(closure.Gas) } closure.Gas.Sub(closure.Gas, gas) // Create a new callable closure diff --git a/ethutil/big.go b/ethutil/big.go index 1a3902fa3e..c0488a71f8 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -50,3 +50,11 @@ func BigCopy(src *big.Int) (ret *big.Int) { return } + +func BigMax(x, y *big.Int) *big.Int { + if x.Cmp(y) <= 0 { + return x + } + + return y +} diff --git a/ethutil/common.go b/ethutil/common.go index c63af29a69..d0ee7b5389 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -38,5 +38,12 @@ var ( Big1 = big.NewInt(1) Big2 = big.NewInt(1) Big0 = big.NewInt(0) + Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) ) + +func CreateAddress(b []byte, nonce *big.Int) []byte { + addrBytes := append(b, nonce.Bytes()...) + + return Sha3Bin(addrBytes)[12:] +} diff --git a/ethutil/config.go b/ethutil/config.go index 54b066fb95..86c0a855d3 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -48,7 +48,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.3.1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From 338b6980915c990c6e6287a7249ddd98e6be20eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 17:15:44 +0200 Subject: [PATCH 0249/1237] Refactoring and added documentation comments --- ethutil/{parsing.go => asm.go} | 55 ++++++++---------------- ethutil/{parsing_test.go => asm_test.go} | 0 ethutil/big.go | 31 ++++++++----- ethutil/bytes.go | 13 +++++- ethutil/common.go | 12 ++++-- ethutil/config.go | 9 +++- ethutil/rlp.go | 10 ----- 7 files changed, 68 insertions(+), 62 deletions(-) rename ethutil/{parsing.go => asm.go} (80%) rename ethutil/{parsing_test.go => asm_test.go} (100%) diff --git a/ethutil/parsing.go b/ethutil/asm.go similarity index 80% rename from ethutil/parsing.go rename to ethutil/asm.go index 514fd92cde..a547d3ac1a 100644 --- a/ethutil/parsing.go +++ b/ethutil/asm.go @@ -79,6 +79,10 @@ var OpCodes = map[string]byte{ "SUICIDE": 0x7f, } +// Is op code +// +// Check whether the given string matches anything in +// the OpCode list func IsOpCode(s string) bool { for key, _ := range OpCodes { if key == s { @@ -88,6 +92,10 @@ func IsOpCode(s string) bool { return false } +// Compile instruction +// +// Attempts to compile and parse the given instruction in "s" +// and returns the byte sequence func CompileInstr(s interface{}) ([]byte, error) { switch s.(type) { case string: @@ -119,8 +127,9 @@ func CompileInstr(s interface{}) ([]byte, error) { return nil, nil } -// Script compilation functions -// Compiles strings to machine code +// Assemble +// +// Assembles the given instructions and returns EVM byte code func Assemble(instructions ...interface{}) (script []byte) { //script = make([]string, len(instructions)) @@ -134,38 +143,22 @@ func Assemble(instructions ...interface{}) (script []byte) { return } -/* -Prepocessing function that takes init and main apart: -init() { - // something -} - -main() { - // main something -} +// Pre process script +// +// Take data apart and attempt to find the "init" section and +// "main" section. `main { } init { }` func PreProcess(data string) (mainInput, initInput string) { - reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" - mainReg := regexp.MustCompile("main" + reg) - initReg := regexp.MustCompile("init" + reg) - - main := mainReg.FindStringSubmatch(data) - if len(main) > 0 { - mainInput = main[1] - } else { + mainInput = getCodeSectionFor("main", data) + if mainInput == "" { mainInput = data } - - init := initReg.FindStringSubmatch(data) - if len(init) > 0 { - initInput = init[1] - } + initInput = getCodeSectionFor("init", data) return } -*/ // Very, very dumb parser. Heed no attention :-) -func FindFor(blockMatcher, input string) string { +func getCodeSectionFor(blockMatcher, input string) string { curCount := -1 length := len(blockMatcher) matchfst := rune(blockMatcher[0]) @@ -198,13 +191,3 @@ func FindFor(blockMatcher, input string) string { return currStr } - -func PreProcess(data string) (mainInput, initInput string) { - mainInput = FindFor("main", data) - if mainInput == "" { - mainInput = data - } - initInput = FindFor("init", data) - - return -} diff --git a/ethutil/parsing_test.go b/ethutil/asm_test.go similarity index 100% rename from ethutil/parsing_test.go rename to ethutil/asm_test.go diff --git a/ethutil/big.go b/ethutil/big.go index c0488a71f8..891d476ad8 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -12,7 +12,9 @@ var BigTrue *big.Int = big.NewInt(1) // False var BigFalse *big.Int = big.NewInt(0) -// Returns the power of two integers +// Big pow +// +// Returns the power of two big integers func BigPow(a, b int) *big.Int { c := new(big.Int) c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) @@ -20,7 +22,9 @@ func BigPow(a, b int) *big.Int { return c } -// Like big.NewInt(uint64); this takes a string instead. +// Big +// +// Shortcut for new(big.Int).SetString(..., 0) func Big(num string) *big.Int { n := new(big.Int) n.SetString(num, 0) @@ -28,7 +32,9 @@ func Big(num string) *big.Int { return n } -// Like big.NewInt(uint64); this takes a byte buffer instead. +// BigD +// +// Shortcut for new(big.Int).SetBytes(...) func BigD(data []byte) *big.Int { n := new(big.Int) n.SetBytes(data) @@ -36,21 +42,26 @@ func BigD(data []byte) *big.Int { return n } +// Big to bytes +// +// Returns the bytes of a big integer with the size specified by **base** +// Attempts to pad the byte array with zeros. func BigToBytes(num *big.Int, base int) []byte { ret := make([]byte, base/8) return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) } -// Functions like the build in "copy" function -// but works on big integers -func BigCopy(src *big.Int) (ret *big.Int) { - ret = new(big.Int) - ret.Add(ret, src) - - return +// Big copy +// +// Creates a copy of the given big integer +func BigCopy(src *big.Int) *big.Int { + return new(big.Int).Set(src) } +// Big max +// +// Returns the maximum size big integer func BigMax(x, y *big.Int) *big.Int { if x.Cmp(y) <= 0 { return x diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 40903a5f17..957fa254a9 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -6,6 +6,9 @@ import ( "fmt" ) +// Number to bytes +// +// Returns the number in bytes with the specified base func NumberToBytes(num interface{}, bits int) []byte { buf := new(bytes.Buffer) err := binary.Write(buf, binary.BigEndian, num) @@ -16,6 +19,9 @@ func NumberToBytes(num interface{}, bits int) []byte { return buf.Bytes()[buf.Len()-(bits/8):] } +// Bytes to number +// +// Attempts to cast a byte slice to a unsigned integer func BytesToNumber(b []byte) uint64 { var number uint64 @@ -32,7 +38,9 @@ func BytesToNumber(b []byte) uint64 { return number } -// Read variable integer in big endian +// Read variable int +// +// Read a variable length number in big endian byte order func ReadVarint(reader *bytes.Reader) (ret uint64) { if reader.Len() == 8 { var num uint64 @@ -55,6 +63,9 @@ func ReadVarint(reader *bytes.Reader) (ret uint64) { return ret } +// Binary length +// +// Returns the true binary length of the given number func BinaryLength(num int) int { if num == 0 { return 0 diff --git a/ethutil/common.go b/ethutil/common.go index d0ee7b5389..983ea5d1bc 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -5,16 +5,20 @@ import ( "math/big" ) +// The different number of units var ( Ether = BigPow(10, 18) Finney = BigPow(10, 15) Szabo = BigPow(10, 12) - Vito = BigPow(10, 9) + Vita = BigPow(10, 9) Turing = BigPow(10, 6) Eins = BigPow(10, 3) Wei = big.NewInt(1) ) +// Currency to string +// +// Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { case num.Cmp(Ether) >= 0: @@ -23,8 +27,8 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) case num.Cmp(Szabo) >= 0: return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) - case num.Cmp(Vito) >= 0: - return fmt.Sprintf("%v Vito", new(big.Int).Div(num, Vito)) + case num.Cmp(Vita) >= 0: + return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita)) case num.Cmp(Turing) >= 0: return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) case num.Cmp(Eins) >= 0: @@ -34,6 +38,7 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Wei", num) } +// Common big integers often used var ( Big1 = big.NewInt(1) Big2 = big.NewInt(1) @@ -42,6 +47,7 @@ var ( Big256 = big.NewInt(0xff) ) +// Creates an ethereum address given the bytes and the nonce func CreateAddress(b []byte, nonce *big.Int) []byte { addrBytes := append(b, nonce.Bytes()...) diff --git a/ethutil/config.go b/ethutil/config.go index 86c0a855d3..323773ba79 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -9,6 +9,7 @@ import ( "runtime" ) +// Log types available type LogType byte const ( @@ -16,7 +17,7 @@ const ( LogTypeFile = 2 ) -// Config struct isn't exposed +// Config struct type config struct { Db Database @@ -31,7 +32,9 @@ type config struct { var Config *config -// Read config doesn't read anything yet. +// Read config +// +// Initialize the global Config variable with default settings func ReadConfig(base string) *config { if Config == nil { usr, _ := user.Current() @@ -56,6 +59,8 @@ func ReadConfig(base string) *config { return Config } +// Set client string +// func (c *config) SetClientString(str string) { Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) } diff --git a/ethutil/rlp.go b/ethutil/rlp.go index d95ace4251..69f80a0a64 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -26,16 +26,6 @@ func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { return Encode(rlpData) } -/* -func FromBin(data []byte) uint64 { - if len(data) == 0 { - return 0 - } - - return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) -} -*/ - const ( RlpEmptyList = 0x80 RlpEmptyStr = 0x40 From bf850974f3e1794a3e2aa4ff33b527297cc50f91 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:00:38 +0200 Subject: [PATCH 0250/1237] Using mutan assembler stage --- ethchain/vm_test.go | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 75a4f5afba..35a7b2e3f5 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -82,7 +82,7 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - asm, err := mutan.Compile(strings.NewReader(` + script, err := mutan.Compile(strings.NewReader(` int32 a = 10 int32 b = 20 if a > b { @@ -90,14 +90,13 @@ func TestRun4(t *testing.T) { } Exit() `), false) - script := ethutil.Assemble(asm...) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) addr := tx.Hash()[12:] contract := MakeContract(tx, state) state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) - asm, err = mutan.Compile(strings.NewReader(` + callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store if store[1000] == 0 { store[1000] = 10^20 @@ -129,10 +128,7 @@ func TestRun4(t *testing.T) { if err != nil { fmt.Println(err) } - asm = append(asm, "LOG") - fmt.Println(asm) - callerScript := ethutil.Assemble(asm...) callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) // Contract addr as test address @@ -162,17 +158,3 @@ func TestRun4(t *testing.T) { } fmt.Println("account.Amount =", account.Amount) } - -func TestRun5(t *testing.T) { - ethutil.ReadConfig("") - - asm, _ := mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 20 - if a > b { - int32 c = this.caller() - } - exit() - `), false) - ethutil.Assemble(asm...) -} From 21f8806eed4c926ea31144c0e061ca8e0bbe35f8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:01:37 +0200 Subject: [PATCH 0251/1237] Moved assembler stage to the mutan compiler --- ethutil/asm.go | 193 -------------------------------------------- ethutil/asm_test.go | 31 ------- 2 files changed, 224 deletions(-) delete mode 100644 ethutil/asm.go delete mode 100644 ethutil/asm_test.go diff --git a/ethutil/asm.go b/ethutil/asm.go deleted file mode 100644 index a547d3ac1a..0000000000 --- a/ethutil/asm.go +++ /dev/null @@ -1,193 +0,0 @@ -package ethutil - -import ( - _ "fmt" - "math/big" - _ "regexp" -) - -// Op codes -var OpCodes = map[string]byte{ - // 0x0 range - arithmetic ops - "STOP": 0x00, - "ADD": 0x01, - "MUL": 0x02, - "SUB": 0x03, - "DIV": 0x04, - "SDIV": 0x05, - "MOD": 0x06, - "SMOD": 0x07, - "EXP": 0x08, - "NEG": 0x09, - "LT": 0x0a, - "GT": 0x0b, - "EQ": 0x0c, - "NOT": 0x0d, - - // 0x10 range - bit ops - "AND": 0x10, - "OR": 0x11, - "XOR": 0x12, - "BYTE": 0x13, - - // 0x20 range - crypto - "SHA3": 0x20, - - // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATALOAD": 0x35, - "CALLDATASIZE": 0x36, - "GASPRICE": 0x38, - - // 0x40 range - block operations - "PREVHASH": 0x40, - "COINBASE": 0x41, - "TIMESTAMP": 0x42, - "NUMBER": 0x43, - "DIFFICULTY": 0x44, - "GASLIMIT": 0x45, - - // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - - "POP": 0x51, - "DUP": 0x52, - "SWAP": 0x53, - "MLOAD": 0x54, - "MSTORE": 0x55, - "MSTORE8": 0x56, - "SLOAD": 0x57, - "SSTORE": 0x58, - "JUMP": 0x59, - "JUMPI": 0x5a, - "PC": 0x5b, - "MSIZE": 0x5c, - - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, - - // 0x70 range - other - "LOG": 0x70, - "SUICIDE": 0x7f, -} - -// Is op code -// -// Check whether the given string matches anything in -// the OpCode list -func IsOpCode(s string) bool { - for key, _ := range OpCodes { - if key == s { - return true - } - } - return false -} - -// Compile instruction -// -// Attempts to compile and parse the given instruction in "s" -// and returns the byte sequence -func CompileInstr(s interface{}) ([]byte, error) { - switch s.(type) { - case string: - str := s.(string) - isOp := IsOpCode(str) - if isOp { - return []byte{OpCodes[str]}, nil - } - - num := new(big.Int) - _, success := num.SetString(str, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(str)) - } else { - // tmp fix for 32 bytes - n := BigToBytes(num, 256) - return n, nil - } - - return num.Bytes(), nil - case int: - num := BigToBytes(big.NewInt(int64(s.(int))), 256) - return num, nil - case []byte: - return BigD(s.([]byte)).Bytes(), nil - } - - return nil, nil -} - -// Assemble -// -// Assembles the given instructions and returns EVM byte code -func Assemble(instructions ...interface{}) (script []byte) { - //script = make([]string, len(instructions)) - - for _, val := range instructions { - instr, _ := CompileInstr(val) - - //script[i] = string(instr) - script = append(script, instr...) - } - - return -} - -// Pre process script -// -// Take data apart and attempt to find the "init" section and -// "main" section. `main { } init { }` -func PreProcess(data string) (mainInput, initInput string) { - mainInput = getCodeSectionFor("main", data) - if mainInput == "" { - mainInput = data - } - initInput = getCodeSectionFor("init", data) - - return -} - -// Very, very dumb parser. Heed no attention :-) -func getCodeSectionFor(blockMatcher, input string) string { - curCount := -1 - length := len(blockMatcher) - matchfst := rune(blockMatcher[0]) - var currStr string - - for i, run := range input { - // Find init - if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher { - curCount = 0 - } else if curCount > -1 { - if run == '{' { - curCount++ - if curCount == 1 { - continue - } - } else if run == '}' { - curCount-- - if curCount == 0 { - // we are done - curCount = -1 - break - } - } - - if curCount > 0 { - currStr += string(run) - } - } - } - - return currStr -} diff --git a/ethutil/asm_test.go b/ethutil/asm_test.go deleted file mode 100644 index a9ad347dd2..0000000000 --- a/ethutil/asm_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ethutil - -import ( - "fmt" - "testing" -) - -func TestPreProcess(t *testing.T) { - main, init := PreProcess(` - init { - // init - if a > b { - if { - } - } - } - - main { - // main - if a > b { - if c > d { - } - } - } - `) - - fmt.Println("main") - fmt.Println(main) - fmt.Println("init") - fmt.Println(init) -} From 5516efdfa0494e028fc3649e4a38da81c56ed598 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 27 Apr 2014 18:05:30 +0200 Subject: [PATCH 0252/1237] Removed old code --- ethchain/asm.go | 68 ------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index a6c85cb602..3194549bac 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -4,55 +4,8 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" - "regexp" ) -func CompileInstr(s interface{}) ([]byte, error) { - switch s.(type) { - case string: - str := s.(string) - isOp := IsOpCode(str) - if isOp { - return []byte{OpCodes[str]}, nil - } - - num := new(big.Int) - _, success := num.SetString(str, 0) - // Assume regular bytes during compilation - if !success { - num.SetBytes([]byte(str)) - } else { - // tmp fix for 32 bytes - n := ethutil.BigToBytes(num, 256) - return n, nil - } - - return num.Bytes(), nil - case int: - num := ethutil.BigToBytes(big.NewInt(int64(s.(int))), 256) - return num, nil - case []byte: - return ethutil.BigD(s.([]byte)).Bytes(), nil - } - - return nil, nil -} - -// Script compilation functions -// Compiles strings to machine code -func Assemble(instructions ...interface{}) (script []byte) { - //script = make([]string, len(instructions)) - - for _, val := range instructions { - instr, _ := CompileInstr(val) - - //script[i] = string(instr) - script = append(script, instr...) - } - - return -} - func Disassemble(script []byte) (asm []string) { pc := new(big.Int) for { @@ -104,24 +57,3 @@ func Disassemble(script []byte) (asm []string) { return } - -func PreProcess(data string) (mainInput, initInput string) { - // Regexp for parsing anything between brackets - reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}" - mainReg := regexp.MustCompile("main" + reg) - initReg := regexp.MustCompile("init" + reg) - - main := mainReg.FindStringSubmatch(data) - if len(main) > 0 { - mainInput = main[1] - } else { - mainInput = data - } - - init := initReg.FindStringSubmatch(data) - if len(init) > 0 { - initInput = init[1] - } - - return -} From 38d6b67b5cfbfb63620a244ea01b5b534917128f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 29 Apr 2014 12:36:27 +0200 Subject: [PATCH 0253/1237] Fixed state problem --- ethchain/block.go | 5 +---- ethchain/block_chain.go | 3 ++- ethchain/state_manager.go | 13 +++++++------ ethminer/miner.go | 12 +++++++----- ethutil/bytes.go | 10 ++++++++++ ethutil/trie.go | 19 +++++++++++++++++-- peer.go | 6 ++++-- 7 files changed, 48 insertions(+), 20 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index d95ebf4b58..aac50ccb14 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -80,9 +80,6 @@ func CreateBlock(root interface{}, extra string, txes []*Transaction) *Block { - // Copy over the bytes - copiedRoot := ethutil.NewValue(root).Bytes() - block := &Block{ // Slice of transactions to include in this block transactions: txes, @@ -98,7 +95,7 @@ func CreateBlock(root interface{}, block.SetTransactions(txes) block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, copiedRoot)) + block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) for _, tx := range txes { block.MakeContract(tx) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 08886c9cda..2be4cd92b2 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -179,7 +179,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockNumber = info.Number } - bc.Ethereum.StateManager().PrepareDefault(returnTo) + // XXX Why are we resetting? This is the block chain, it has nothing to do with states + //bc.Ethereum.StateManager().PrepareDefault(returnTo) err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 628ab6a27f..70d4155c37 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -158,17 +158,18 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() + hash := block.Hash() + + if sm.bc.HasBlock(hash) { + fmt.Println("[STATE] We already have this block, ignoring") + return nil + } + // Defer the Undo on the Trie. If the block processing happened // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. defer sm.bc.CurrentBlock.Undo() - hash := block.Hash() - - if sm.bc.HasBlock(hash) { - fmt.Println("[SM] We already have this block, ignoring") - return nil - } // Check if we have the parent hash, if it isn't known we discard it // Reasons might be catching up or simply an invalid block diff --git a/ethminer/miner.go b/ethminer/miner.go index 791e8e4024..c93267161d 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -2,6 +2,7 @@ package ethminer import ( "bytes" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -61,10 +62,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - //log.Println("[MINER] Got new block via Reactor") + log.Println("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - //log.Println("[MINER] New top block found resetting state") + log.Println("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -86,7 +87,7 @@ func (miner *Miner) listener() { } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { - //log.Println("[MINER] Adding uncle block") + log.Println("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } @@ -133,8 +134,9 @@ func (miner *Miner) listener() { miner.ethereum.StateManager().PrepareDefault(miner.block) err := miner.ethereum.StateManager().ProcessBlock(miner.block, true) if err != nil { - log.Println("Error result from process block:", err) - miner.block.State().Reset() + log.Println(err) + miner.txs = []*ethchain.Transaction{} // Move this somewhere neat + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) } else { /* diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 957fa254a9..500368017b 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -73,3 +73,13 @@ func BinaryLength(num int) int { return 1 + BinaryLength(num>>8) } + +// Copy bytes +// +// Returns an exact copy of the provided bytes +func CopyBytes(b []byte) (copiedBytes []byte) { + copiedBytes = make([]byte, len(b)) + copy(copiedBytes, b) + + return +} diff --git a/ethutil/trie.go b/ethutil/trie.go index c67f750bc7..4d088ccff2 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -119,14 +119,29 @@ type Trie struct { cache *Cache } +func copyRoot(root interface{}) interface{} { + var prevRootCopy interface{} + if b, ok := root.([]byte); ok { + prevRootCopy = CopyBytes(b) + } else { + prevRootCopy = root + } + + return prevRootCopy +} + func NewTrie(db Database, Root interface{}) *Trie { - return &Trie{cache: NewCache(db), Root: Root, prevRoot: Root} + // Make absolute sure the root is copied + r := copyRoot(Root) + p := copyRoot(Root) + + return &Trie{cache: NewCache(db), Root: r, prevRoot: p} } // Save the cached value to the database. func (t *Trie) Sync() { t.cache.Commit() - t.prevRoot = t.Root + t.prevRoot = copyRoot(t.Root) } func (t *Trie) Undo() { diff --git a/peer.go b/peer.go index 0ecd13e604..28ccc324cd 100644 --- a/peer.go +++ b/peer.go @@ -449,8 +449,10 @@ func (p *Peer) HandleInbound() { if parent != nil { ethutil.Config.Log.Infof("[PEER] Found conical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) - ethutil.Config.Log.Infof("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) + if len(chain) > 0 { + ethutil.Config.Log.Infof("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) + } } else { ethutil.Config.Log.Infof("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain From 21724f7ef960f0f2df0d2b0f3cccfd030a4aaee8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 14:43:32 +0200 Subject: [PATCH 0254/1237] Added manifest changes and changed closures --- ethchain/closure.go | 17 +++------- ethchain/state_manager.go | 67 ++++++++++++++++++++++++++++----------- ethchain/vm.go | 7 ++-- ethminer/miner.go | 1 - 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 57abaa91eb..7e911ad993 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -7,13 +7,6 @@ import ( "math/big" ) -type Callee interface { -} - -type Reference interface { - Callee -} - type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte @@ -24,8 +17,8 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef - object ClosureRef + callee *StateObject + object *StateObject Script []byte State *State @@ -37,7 +30,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -108,11 +101,11 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() ClosureRef { +func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { +func (c *Closure) Callee() *StateObject { return c.callee } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 70d4155c37..072fabc0e1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -51,9 +51,7 @@ type StateManager struct { // results compState *State - // It's generally know that a map is faster for small lookups than arrays - // we'll eventually have to make a decision if the map grows too large - watchedAddresses map[string]bool + manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { @@ -64,7 +62,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Ethereum: ethereum, stateObjectCache: NewStateObjectCache(), bc: ethereum.BlockChain(), - watchedAddresses: make(map[string]bool), + manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -112,7 +110,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - fmt.Printf("Processing Tx: %x\n", tx.Hash()) // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. @@ -122,7 +119,6 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { contract := sm.MakeContract(tx) if contract != nil { sm.EvalScript(contract.Init(), contract, tx, block) - fmt.Printf("state root of contract %x\n", contract.State().Root()) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -214,6 +210,10 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) + + sm.notifyChanges() + + sm.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -337,22 +337,53 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.Changed(account) + sm.manifest.AddObjectChange(account) + sm.procState.UpdateStateObject(object) - sm.Changed(object) + sm.manifest.AddObjectChange(object) } -// Watch a specific address -func (sm *StateManager) Watch(addr []byte) { - if !sm.watchedAddresses[string(addr)] { - sm.watchedAddresses[string(addr)] = true +func (sm *StateManager) notifyChanges() { + for addr, stateObject := range sm.manifest.objectChanges { + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + } + + for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for addr, value := range mappedObjects { + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, value.String()) + } } } -// The following objects are used when changing a value and using the "watched" attribute -// to determine whether the reactor should be used to notify any subscribers on the address -func (sm *StateManager) Changed(stateObject *StateObject) { - if sm.watchedAddresses[string(stateObject.Address())] { - sm.Ethereum.Reactor().Post("addressChanged", stateObject) - } +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + objectChanges map[string]*StateObject + storageChanges map[string]map[string]*big.Int +} + +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.objectChanges = make(map[string]*StateObject) + m.storageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.objectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.storageChanges[string(stateObject.Address())] == nil { + m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) + } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } diff --git a/ethchain/vm.go b/ethchain/vm.go index b983e88ff1..0a3690c415 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -411,6 +411,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) + + // Add the change to manifest + vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() @@ -492,7 +495,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } closure.Gas.Sub(closure.Gas, gas) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -502,7 +505,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigTrue) // Notify of the changes - vm.stateManager.Changed(contract) + vm.stateManager.manifest.AddObjectChange(contract) } mem.Set(retOffset.Int64(), retSize.Int64(), ret) diff --git a/ethminer/miner.go b/ethminer/miner.go index c93267161d..3796c873ed 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -2,7 +2,6 @@ package ethminer import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" From c3293641e7b49c7e2d85d2bd69b37bc74cb5b00d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 17:13:32 +0200 Subject: [PATCH 0255/1237] Removed debug logging --- ethchain/error.go | 23 ++++++++++++++++++++++- ethchain/state_manager.go | 2 +- ethchain/transaction_pool.go | 10 +++------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/ethchain/error.go b/ethchain/error.go index 0f1d061c0d..8d37b0208a 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -1,6 +1,8 @@ package ethchain -import "fmt" +import ( + "fmt" +) // Parent error. In case a parent is unknown this error will be thrown // by the block manager @@ -40,3 +42,22 @@ func IsValidationErr(err error) bool { return ok } + +type NonceErr struct { + Message string + Is, Exp uint64 +} + +func (err *NonceErr) Error() string { + return err.Message +} + +func NonceError(is, exp uint64) *NonceErr { + return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp} +} + +func IsNonceErr(err error) bool { + _, ok := err.(*NonceErr) + + return ok +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 072fabc0e1..02d0345d75 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -157,7 +157,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { hash := block.Hash() if sm.bc.HasBlock(hash) { - fmt.Println("[STATE] We already have this block, ignoring") + //fmt.Println("[STATE] We already have this block, ignoring") return nil } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 91fad2635b..fc807c580f 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -98,7 +98,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := block.state.GetStateObject(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -112,7 +112,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := block.state.GetStateObject(tx.Recipient) sender.Nonce += 1 // Send Tx to self @@ -169,7 +169,6 @@ out: for { select { case tx := <-pool.queueChan: - log.Println("Received new Tx to queue") hash := tx.Hash() foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { return bytes.Compare(tx.Hash(), hash) == 0 @@ -186,11 +185,8 @@ out: log.Println("Validating Tx failed", err) } } else { - log.Println("Transaction ok, adding") - // Call blocking version. At this point it - // doesn't matter since this is a goroutine + // Call blocking version. pool.addTransaction(tx) - log.Println("Added") // Notify the subscribers pool.Ethereum.Reactor().Post("newTx", tx) From d2ab322267e489f47b4b908d060411eb0554a029 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 17:43:48 +0200 Subject: [PATCH 0256/1237] Removed debugging log --- ethchain/transaction_pool.go | 18 ++++++++++-------- peer.go | 16 ++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index fc807c580f..8fbe676f5b 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,14 +91,16 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { - defer func() { - if r := recover(); r != nil { - log.Println(r) - err = fmt.Errorf("%v", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() + */ // Get the sender - sender := block.state.GetStateObject(tx.Sender()) + sender := block.state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -112,7 +114,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract } // Get the receiver - receiver := block.state.GetStateObject(tx.Recipient) + receiver := block.state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self diff --git a/peer.go b/peer.go index 28ccc324cd..4f7005ac4d 100644 --- a/peer.go +++ b/peer.go @@ -320,14 +320,11 @@ func (p *Peer) HandleInbound() { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) - if p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { - fmt.Println("[PEER] We found a common ancestor, let's continue.") - } else { - + if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { // If we can't find a common ancenstor we need to request more blocks. // FIXME: At one point this won't scale anymore since we are not asking for an offset // we just keep increasing the amount of blocks. - fmt.Println("[PEER] No common ancestor found, requesting more blocks.") + //fmt.Println("[PEER] No common ancestor found, requesting more blocks.") p.blocksRequested = p.blocksRequested * 2 p.catchingUp = false p.SyncWithBlocks() @@ -336,17 +333,13 @@ func (p *Peer) HandleInbound() { for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) // Do we have this block on our chain? If so we can continue - if p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { - ethutil.Config.Log.Debugf("[PEER] Block found, checking next one.\n") - } else { + if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { - ethutil.Config.Log.Infof("[PEER] Local and foreign chain have diverted after %x, finding best chain!\n", block.PrevHash) + //ethutil.Config.Log.Infof("[PEER] Local and foreign chain have diverted after %x, finding best chain!\n", block.PrevHash) if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { return } - } else { - ethutil.Config.Log.Debugf("[PEER] Both local and foreign chain have same parent. Continue normally\n") } } } @@ -644,7 +637,6 @@ func (p *Peer) SyncWithBlocks() { for _, block := range blocks { hashes = append(hashes, block.Hash()) } - fmt.Printf("Requesting hashes from network: %x", hashes) msgInfo := append(hashes, uint64(50)) From e6a68f0c3ab4987fa5e0e35cac765d40ff305aea Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 1 May 2014 22:13:59 +0200 Subject: [PATCH 0257/1237] Removed debug log --- ethchain/state_object.go | 1 - ethchain/transaction_pool.go | 14 ++++------ peer.go | 54 ++++++++++++++++++------------------ 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e921795d7..4ec91d2e08 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -80,7 +80,6 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.SetAddr(addr, val) - //c.state.trie.Update(string(addr), string(val.Encode())) } func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 8fbe676f5b..72836d6cb1 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,14 +91,12 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { - /* - defer func() { - if r := recover(); r != nil { - log.Println(r) - err = fmt.Errorf("%v", r) - } - }() - */ + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = fmt.Errorf("%v", r) + } + }() // Get the sender sender := block.state.GetAccount(tx.Sender()) diff --git a/peer.go b/peer.go index 4f7005ac4d..80ddc5142a 100644 --- a/peer.go +++ b/peer.go @@ -440,14 +440,14 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { - ethutil.Config.Log.Infof("[PEER] Found conical block, returning chain from: %x ", parent.Hash()) + ethutil.Config.Log.Debugf("[PEER] Found conical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { - ethutil.Config.Log.Infof("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) + ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } } else { - ethutil.Config.Log.Infof("[PEER] Could not find a similar block") + ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain lastHash := msg.Data.Get(l - 1) @@ -455,7 +455,7 @@ func (p *Peer) HandleInbound() { p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) } case ethwire.MsgNotInChainTy: - ethutil.Config.Log.Infof("Not in chain %x\n", msg.Data) + ethutil.Config.Log.Debugf("Not in chain %x\n", msg.Data) // TODO case ethwire.MsgGetTxsTy: // Get the current transactions of the pool @@ -478,29 +478,6 @@ func (p *Peer) HandleInbound() { p.Stop() } -func packAddr(address, port string) ([]interface{}, uint16) { - addr := strings.Split(address, ".") - a, _ := strconv.Atoi(addr[0]) - b, _ := strconv.Atoi(addr[1]) - c, _ := strconv.Atoi(addr[2]) - d, _ := strconv.Atoi(addr[3]) - host := []interface{}{int32(a), int32(b), int32(c), int32(d)} - prt, _ := strconv.Atoi(port) - - return host, uint16(prt) -} - -func unpackAddr(value *ethutil.Value, p uint64) string { - a := strconv.Itoa(int(value.Get(0).Uint())) - b := strconv.Itoa(int(value.Get(1).Uint())) - c := strconv.Itoa(int(value.Get(2).Uint())) - d := strconv.Itoa(int(value.Get(3).Uint())) - host := strings.Join([]string{a, b, c, d}, ".") - port := strconv.Itoa(int(p)) - - return net.JoinHostPort(host, port) -} - func (p *Peer) Start() { peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String()) servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) @@ -662,3 +639,26 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { func (p *Peer) RlpData() []interface{} { return []interface{}{p.host, p.port, p.pubkey} } + +func packAddr(address, port string) ([]interface{}, uint16) { + addr := strings.Split(address, ".") + a, _ := strconv.Atoi(addr[0]) + b, _ := strconv.Atoi(addr[1]) + c, _ := strconv.Atoi(addr[2]) + d, _ := strconv.Atoi(addr[3]) + host := []interface{}{int32(a), int32(b), int32(c), int32(d)} + prt, _ := strconv.Atoi(port) + + return host, uint16(prt) +} + +func unpackAddr(value *ethutil.Value, p uint64) string { + a := strconv.Itoa(int(value.Get(0).Uint())) + b := strconv.Itoa(int(value.Get(1).Uint())) + c := strconv.Itoa(int(value.Get(2).Uint())) + d := strconv.Itoa(int(value.Get(3).Uint())) + host := strings.Join([]string{a, b, c, d}, ".") + port := strconv.Itoa(int(p)) + + return net.JoinHostPort(host, port) +} From 91aa189ef31adff7f4a084cae770aaa7c01f11e5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 1 May 2014 22:14:20 +0200 Subject: [PATCH 0258/1237] Fixed Upnp bug --- ethereum.go | 2 +- natupnp.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index c906a6954f..b9174eaf8f 100644 --- a/ethereum.go +++ b/ethereum.go @@ -350,7 +350,7 @@ func (s *Ethereum) WaitForShutdown() { func (s *Ethereum) upnpUpdateThread() { // Go off immediately to prevent code duplication, thereafter we renew // lease every 15 minutes. - timer := time.NewTimer(0 * time.Second) + timer := time.NewTimer(5 * time.Minute) lport, _ := strconv.ParseInt(s.Port, 10, 16) first := true out: diff --git a/natupnp.go b/natupnp.go index e4072d0ddb..c7f9eeb622 100644 --- a/natupnp.go +++ b/natupnp.go @@ -246,6 +246,10 @@ func soapRequest(url, function, message string) (r *http.Response, err error) { //fmt.Println(fullMessage) r, err = http.DefaultClient.Do(req) + if err != nil { + return + } + if r.Body != nil { defer r.Body.Close() } From 17674fb888d3dc2de081f1c781a227b61c961189 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 1 May 2014 22:14:34 +0200 Subject: [PATCH 0259/1237] Added suicide back in --- ethchain/vm.go | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 0a3690c415..3a3b3447aa 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -73,10 +73,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } }() - // If the amount of gas supplied is less equal to 0 - if closure.Gas.Cmp(big.NewInt(0)) <= 0 { - // TODO Do something - } + ethutil.Config.Log.Debugf("[VM] Running closure %x\n", closure.object.Address()) // Memory for the current closure mem := &Memory{} @@ -107,9 +104,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + /* + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } + */ gas := new(big.Int) useGas := func(amount *big.Int) { @@ -163,9 +162,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oLOG: stack.Print() mem.Print() - case oSTOP: // Stop the closure - return closure.Return(nil), nil - // 0x20 range case oADD: require(2) @@ -520,22 +516,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(ret), nil case oSUICIDE: - /* - recAddr := stack.Pop().Bytes() - // Purge all memory - deletedMemory := contract.state.Purge() - // Add refunds to the pop'ed address - refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) - account := state.GetAccount(recAddr) - account.Amount.Add(account.Amount, refund) - // Update the refunding address - state.UpdateAccount(recAddr, account) - // Delete the contract - state.trie.Update(string(addr), "") + require(1) - ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) - break out - */ + receiver := vm.state.GetAccount(stack.Pop().Bytes()) + receiver.AddAmount(closure.object.Amount) + + vm.stateManager.manifest.AddObjectChange(receiver) + + closure.object.state.Purge() + + fallthrough + case oSTOP: // Stop the closure + return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) From 70c8656640a861d93ac40181c6c0bdd8faef856b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 12:11:55 +0200 Subject: [PATCH 0260/1237] Added a KeyPairFromSec function which creates a new keypair based on the given seckey --- ethchain/keypair.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ethchain/keypair.go b/ethchain/keypair.go index a5af791d0d..0f23bacdf8 100644 --- a/ethchain/keypair.go +++ b/ethchain/keypair.go @@ -2,6 +2,7 @@ package ethchain import ( "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" "math/big" ) @@ -14,6 +15,15 @@ type KeyPair struct { state *State } +func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { + pubkey, err := secp256k1.GeneratePubKey(seckey) + if err != nil { + return nil, err + } + + return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil +} + func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} From ebdf339a614b9d03a0b0a0292d1ea24f854d6b3e Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 2 May 2014 13:35:25 +0200 Subject: [PATCH 0261/1237] Implemented RPC framework --- ethereum.go | 4 + etherpc/packages.go | 194 ++++++++++++++++++++++++++++++++++++++++++++ etherpc/server.go | 59 ++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 etherpc/packages.go create mode 100644 etherpc/server.go diff --git a/ethereum.go b/ethereum.go index c906a6954f..df8e9ef7d4 100644 --- a/ethereum.go +++ b/ethereum.go @@ -4,6 +4,7 @@ import ( "container/list" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/etherpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "io/ioutil" @@ -62,6 +63,8 @@ type Ethereum struct { MaxPeers int reactor *ethutil.ReactorEngine + + RpcServer *etherpc.JsonRpcServer } func New(caps Caps, usePnp bool) (*Ethereum, error) { @@ -338,6 +341,7 @@ func (s *Ethereum) Stop() { s.txPool.Stop() s.stateManager.Stop() + s.RpcServer.Stop() close(s.shutdownChan) } diff --git a/etherpc/packages.go b/etherpc/packages.go new file mode 100644 index 0000000000..8bc78498f7 --- /dev/null +++ b/etherpc/packages.go @@ -0,0 +1,194 @@ +package etherpc + +import ( + "encoding/json" + "errors" + "math/big" +) + +type MainPackage struct{} + +type JsonArgs interface { + requirements() error +} + +type BlockResponse struct { + Name string + Id int +} +type GetBlockArgs struct { + BlockNumber int + Hash string +} + +type ErrorResponse struct { + Error bool `json:"error"` + ErrorText string `json:"errorText"` +} + +type JsonResponse interface { +} + +type SuccessRes struct { + Error bool `json:"error"` + Result JsonResponse `json:"result"` +} + +func NewSuccessRes(object JsonResponse) string { + e := SuccessRes{Error: false, Result: object} + res, err := json.Marshal(e) + if err != nil { + // This should never happen + panic("Creating json error response failed, help") + } + success := string(res) + return success +} + +func NewErrorResponse(msg string) error { + e := ErrorResponse{Error: true, ErrorText: msg} + res, err := json.Marshal(e) + if err != nil { + // This should never happen + panic("Creating json error response failed, help") + } + newErr := errors.New(string(res)) + return newErr +} + +func (b *GetBlockArgs) requirements() error { + if b.BlockNumber == 0 && b.Hash == "" { + return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") + } + return nil +} + +func (p *MainPackage) GetBlock(args *GetBlockArgs, reply *BlockResponse) error { + err := args.requirements() + if err != nil { + return err + } + // Do something + + return nil +} + +type NewTxArgs struct { + Sec string + Recipient string + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Init string + Body string +} +type TxResponse struct { + Hash string +} + +func (a *NewTxArgs) requirements() error { + if a.Recipient == "" { + return NewErrorResponse("Transact requires a 'recipient' address as argument") + } + if a.Value == nil { + return NewErrorResponse("Transact requires a 'value' as argument") + } + if a.Gas == nil { + return NewErrorResponse("Transact requires a 'gas' value as argument") + } + if a.GasPrice == nil { + return NewErrorResponse("Transact requires a 'gasprice' value as argument") + } + return nil +} + +func (a *NewTxArgs) requirementsContract() error { + if a.Value == nil { + return NewErrorResponse("Create requires a 'value' as argument") + } + if a.Gas == nil { + return NewErrorResponse("Create requires a 'gas' value as argument") + } + if a.GasPrice == nil { + return NewErrorResponse("Create requires a 'gasprice' value as argument") + } + if a.Init == "" { + return NewErrorResponse("Create requires a 'init' value as argument") + } + if a.Body == "" { + return NewErrorResponse("Create requires a 'body' value as argument") + } + return nil +} + +func (p *MainPackage) Transact(args *NewTxArgs, reply *TxResponse) error { + err := args.requirements() + if err != nil { + return err + } + return nil +} + +func (p *MainPackage) Create(args *NewTxArgs, reply *string) error { + err := args.requirementsContract() + if err != nil { + return err + } + return nil +} + +func (p *MainPackage) getKey(args interface{}, reply *string) error { + return nil +} + +type GetStorageArgs struct { + Address string + Key string +} + +func (a *GetStorageArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetStorageAt requires an 'address' value as argument") + } + if a.Key == "" { + return NewErrorResponse("GetStorageAt requires an 'key' value as argument") + } + return nil +} + +func (p *MainPackage) getStorageAt(args *GetStorageArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + return nil +} + +type GetBalanceArgs struct { + Address string +} + +func (a *GetBalanceArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") + } + return nil +} + +func (p *MainPackage) GetBalanceAt(args *GetBalanceArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + return nil +} + +type TestRes struct { + JsonResponse `json:"-"` + Answer int `json:"answer"` +} + +func (p *MainPackage) Test(args *GetBlockArgs, reply *string) error { + *reply = NewSuccessRes(TestRes{Answer: 15}) + return nil +} diff --git a/etherpc/server.go b/etherpc/server.go new file mode 100644 index 0000000000..ba0c51006a --- /dev/null +++ b/etherpc/server.go @@ -0,0 +1,59 @@ +package etherpc + +import ( + "github.com/ethereum/eth-go/ethutil" + "net" + "net/rpc" + "net/rpc/jsonrpc" +) + +type JsonRpcServer struct { + quit chan bool + listener net.Listener +} + +func (s *JsonRpcServer) exitHandler() { +out: + for { + select { + case <-s.quit: + s.listener.Close() + break out + } + } + + ethutil.Config.Log.Infoln("[JSON] Shutdown JSON-RPC server") +} + +func (s *JsonRpcServer) Stop() { + close(s.quit) +} + +func (s *JsonRpcServer) Start() { + ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") + go s.exitHandler() + rpc.Register(new(MainPackage)) + rpc.HandleHTTP() + + for { + conn, err := s.listener.Accept() + if err != nil { + ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err) + continue + } + ethutil.Config.Log.Debugln("[JSON] Incoming request.") + go jsonrpc.ServeConn(conn) + } +} + +func NewJsonRpcServer() *JsonRpcServer { + l, err := net.Listen("tcp", ":30304") + if err != nil { + ethutil.Config.Log.Infoln("Error starting JSON-RPC") + } + + return &JsonRpcServer{ + listener: l, + quit: make(chan bool), + } +} From e798f221dd9d6aaffaa709d559f01a41447e4896 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 13:55:43 +0200 Subject: [PATCH 0262/1237] Added public interface --- ethpub/pub.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++ ethpub/types.go | 91 ++++++++++++++++++++++++++++++++++++++ ethutil/script.go | 41 ++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 ethpub/pub.go create mode 100644 ethpub/types.go create mode 100644 ethutil/script.go diff --git a/ethpub/pub.go b/ethpub/pub.go new file mode 100644 index 0000000000..4950f6eb55 --- /dev/null +++ b/ethpub/pub.go @@ -0,0 +1,108 @@ +package ethpub + +import ( + "github.com/ethereum/eth-go" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" +) + +type PEthereum struct { + stateManager *ethchain.StateManager + blockChain *ethchain.BlockChain + txPool *ethchain.TxPool +} + +func NewPEthereum(eth *eth.Ethereum) *PEthereum { + return &PEthereum{ + eth.StateManager(), + eth.BlockChain(), + eth.TxPool(), + } +} + +func (lib *PEthereum) GetBlock(hexHash string) *PBlock { + hash := ethutil.FromHex(hexHash) + + block := lib.blockChain.GetBlock(hash) + + return &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} +} + +func (lib *PEthereum) GetKey() *PKey { + keyPair, err := ethchain.NewKeyPairFromSec(ethutil.Config.Db.GetKeys()[0].PrivateKey) + if err != nil { + return nil + } + + return NewPKey(keyPair) +} + +func (lib *PEthereum) GetStateObject(address string) *PStateObject { + stateObject := lib.stateManager.ProcState().GetContract(ethutil.FromHex(address)) + if stateObject != nil { + return NewPStateObject(stateObject) + } + + // See GetStorage for explanation on "nil" + return NewPStateObject(nil) +} + +func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) { + return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "") +} + +func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (string, error) { + return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, initStr, bodyStr) +} + +func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (string, error) { + var hash []byte + var contractCreation bool + if len(recipient) == 0 { + contractCreation = true + } else { + hash = ethutil.FromHex(recipient) + } + + keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + if err != nil { + return "", err + } + + value := ethutil.Big(valueStr) + gas := ethutil.Big(gasStr) + gasPrice := ethutil.Big(gasPriceStr) + var tx *ethchain.Transaction + // Compile and assemble the given data + if contractCreation { + initScript, err := ethutil.Compile(initStr) + if err != nil { + return "", err + } + mainScript, err := ethutil.Compile(scriptStr) + if err != nil { + return "", err + } + + tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript) + } else { + // Just in case it was submitted as a 0x prefixed string + if initStr[0:2] == "0x" { + initStr = initStr[2:len(initStr)] + } + tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) + } + + acc := lib.stateManager.GetAddrState(keyPair.Address()) + tx.Nonce = acc.Nonce + tx.Sign(keyPair.PrivateKey) + lib.txPool.QueueTransaction(tx) + + if contractCreation { + ethutil.Config.Log.Infof("Contract addr %x", tx.Hash()[12:]) + } else { + ethutil.Config.Log.Infof("Tx hash %x", tx.Hash()) + } + + return ethutil.Hex(tx.Hash()), nil +} diff --git a/ethpub/types.go b/ethpub/types.go new file mode 100644 index 0000000000..5e7e4613db --- /dev/null +++ b/ethpub/types.go @@ -0,0 +1,91 @@ +package ethpub + +import ( + "encoding/hex" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethutil" +) + +// Block interface exposed to QML +type PBlock struct { + Number int + Hash string +} + +// Creates a new QML Block from a chain block +func NewPBlock(block *ethchain.Block) *PBlock { + info := block.BlockInfo() + hash := hex.EncodeToString(block.Hash()) + + return &PBlock{Number: int(info.Number), Hash: hash} +} + +type PTx struct { + Value, Hash, Address string + Contract bool +} + +func NewPTx(tx *ethchain.Transaction) *PTx { + hash := hex.EncodeToString(tx.Hash()) + sender := hex.EncodeToString(tx.Recipient) + isContract := len(tx.Data) > 0 + + return &PTx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract} +} + +type PKey struct { + Address string + PrivateKey string + PublicKey string +} + +func NewPKey(key *ethchain.KeyPair) *PKey { + return &PKey{ethutil.Hex(key.Address()), ethutil.Hex(key.PrivateKey), ethutil.Hex(key.PublicKey)} +} + +/* +type PKeyRing struct { + Keys []interface{} +} + +func NewPKeyRing(keys []interface{}) *PKeyRing { + return &PKeyRing{Keys: keys} +} +*/ + +type PStateObject struct { + object *ethchain.StateObject +} + +func NewPStateObject(object *ethchain.StateObject) *PStateObject { + return &PStateObject{object: object} +} + +func (c *PStateObject) GetStorage(address string) string { + // Because somehow, even if you return nil to QML it + // still has some magical object so we can't rely on + // undefined or null at the QML side + if c.object != nil { + val := c.object.GetMem(ethutil.Big("0x" + address)) + + return val.BigInt().String() + } + + return "" +} + +func (c *PStateObject) Value() string { + if c.object != nil { + return c.object.Amount.String() + } + + return "" +} + +func (c *PStateObject) Address() string { + if c.object != nil { + return ethutil.Hex(c.object.Address()) + } + + return "" +} diff --git a/ethutil/script.go b/ethutil/script.go new file mode 100644 index 0000000000..620658025a --- /dev/null +++ b/ethutil/script.go @@ -0,0 +1,41 @@ +package ethutil + +import ( + "fmt" + "github.com/obscuren/mutan" + "strings" +) + +// General compile function +func Compile(script string) ([]byte, error) { + byteCode, errors := mutan.Compile(strings.NewReader(script), false) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } + } + return nil, fmt.Errorf("%v", errs) + } + + return byteCode, nil +} + +func CompileScript(script string) ([]byte, []byte, error) { + // Preprocess + mainInput, initInput := mutan.PreProcess(script) + // Compile main script + mainScript, err := Compile(mainInput) + if err != nil { + return nil, nil, err + } + + // Compile init script + initScript, err := Compile(initInput) + if err != nil { + return nil, nil, err + } + + return mainScript, initScript, nil +} From 1f6df0cd522842095c5ca723d2e11fc6b97b8b6a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 2 May 2014 14:08:54 +0200 Subject: [PATCH 0263/1237] Added receipts for tx creation --- ethchain/transaction.go | 4 ++++ ethpub/pub.go | 16 ++++++++-------- ethpub/types.go | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 421f26c98c..e93e610be5 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -59,6 +59,10 @@ func (tx *Transaction) IsContract() bool { return tx.contractCreation } +func (tx *Transaction) CreationAddress() []byte { + return tx.Hash()[12:] +} + func (tx *Transaction) Signature(key []byte) []byte { hash := tx.Hash() diff --git a/ethpub/pub.go b/ethpub/pub.go index 4950f6eb55..c6f177124a 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -47,15 +47,15 @@ func (lib *PEthereum) GetStateObject(address string) *PStateObject { return NewPStateObject(nil) } -func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) { +func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "") } -func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (string, error) { +func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (*PReceipt, error) { return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, initStr, bodyStr) } -func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (string, error) { +func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool if len(recipient) == 0 { @@ -66,7 +66,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) if err != nil { - return "", err + return nil, err } value := ethutil.Big(valueStr) @@ -77,11 +77,11 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in if contractCreation { initScript, err := ethutil.Compile(initStr) if err != nil { - return "", err + return nil, err } mainScript, err := ethutil.Compile(scriptStr) if err != nil { - return "", err + return nil, err } tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript) @@ -99,10 +99,10 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in lib.txPool.QueueTransaction(tx) if contractCreation { - ethutil.Config.Log.Infof("Contract addr %x", tx.Hash()[12:]) + ethutil.Config.Log.Infof("Contract addr %x", tx.CreationAddress()) } else { ethutil.Config.Log.Infof("Tx hash %x", tx.Hash()) } - return ethutil.Hex(tx.Hash()), nil + return NewPReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil } diff --git a/ethpub/types.go b/ethpub/types.go index 5e7e4613db..bf06ce2f64 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -43,6 +43,22 @@ func NewPKey(key *ethchain.KeyPair) *PKey { return &PKey{ethutil.Hex(key.Address()), ethutil.Hex(key.PrivateKey), ethutil.Hex(key.PublicKey)} } +type PReceipt struct { + CreatedContract bool + Address string + Hash string + Sender string +} + +func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { + return &PReceipt{ + contractCreation, + ethutil.Hex(creationAddress), + ethutil.Hex(hash), + ethutil.Hex(address), + } +} + /* type PKeyRing struct { Keys []interface{} From 4f20e8f649a19168718a7f0fe7619e3bdb626aa8 Mon Sep 17 00:00:00 2001 From: Maran Date: Fri, 2 May 2014 20:00:58 +0200 Subject: [PATCH 0264/1237] Implemented first few methods via public api --- ethereum.go | 5 ++--- etherpc/packages.go | 39 +++++++++++++++++++++++---------------- etherpc/server.go | 7 +++++-- ethpub/pub.go | 2 +- ethpub/types.go | 12 ++++++------ 5 files changed, 37 insertions(+), 28 deletions(-) diff --git a/ethereum.go b/ethereum.go index 4181f9cd84..6cb1a916fd 100644 --- a/ethereum.go +++ b/ethereum.go @@ -4,7 +4,6 @@ import ( "container/list" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/etherpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "io/ioutil" @@ -64,7 +63,7 @@ type Ethereum struct { reactor *ethutil.ReactorEngine - RpcServer *etherpc.JsonRpcServer + // TODO: This no worky: RpcServer *etherpc.JsonRpcServer } func New(caps Caps, usePnp bool) (*Ethereum, error) { @@ -341,7 +340,7 @@ func (s *Ethereum) Stop() { s.txPool.Stop() s.stateManager.Stop() - s.RpcServer.Stop() + // TODO: THIS NO WORKY: s.RpcServer.Stop() close(s.shutdownChan) } diff --git a/etherpc/packages.go b/etherpc/packages.go index 8bc78498f7..271a59879c 100644 --- a/etherpc/packages.go +++ b/etherpc/packages.go @@ -3,18 +3,20 @@ package etherpc import ( "encoding/json" "errors" - "math/big" + "github.com/ethereum/eth-go/ethpub" + _ "log" ) -type MainPackage struct{} +type MainPackage struct { + ethp *ethpub.PEthereum +} type JsonArgs interface { requirements() error } type BlockResponse struct { - Name string - Id int + JsonResponse } type GetBlockArgs struct { BlockNumber int @@ -63,22 +65,23 @@ func (b *GetBlockArgs) requirements() error { return nil } -func (p *MainPackage) GetBlock(args *GetBlockArgs, reply *BlockResponse) error { +func (p *MainPackage) GetBlock(args *GetBlockArgs, reply *string) error { err := args.requirements() if err != nil { return err } // Do something - + block := p.ethp.GetBlock(args.Hash) + *reply = NewSuccessRes(block) return nil } type NewTxArgs struct { Sec string Recipient string - Value *big.Int - Gas *big.Int - GasPrice *big.Int + Value string + Gas string + GasPrice string Init string Body string } @@ -90,26 +93,26 @@ func (a *NewTxArgs) requirements() error { if a.Recipient == "" { return NewErrorResponse("Transact requires a 'recipient' address as argument") } - if a.Value == nil { + if a.Value == "" { return NewErrorResponse("Transact requires a 'value' as argument") } - if a.Gas == nil { + if a.Gas == "" { return NewErrorResponse("Transact requires a 'gas' value as argument") } - if a.GasPrice == nil { + if a.GasPrice == "" { return NewErrorResponse("Transact requires a 'gasprice' value as argument") } return nil } func (a *NewTxArgs) requirementsContract() error { - if a.Value == nil { + if a.Value == "" { return NewErrorResponse("Create requires a 'value' as argument") } - if a.Gas == nil { + if a.Gas == "" { return NewErrorResponse("Create requires a 'gas' value as argument") } - if a.GasPrice == nil { + if a.GasPrice == "" { return NewErrorResponse("Create requires a 'gasprice' value as argument") } if a.Init == "" { @@ -121,11 +124,13 @@ func (a *NewTxArgs) requirementsContract() error { return nil } -func (p *MainPackage) Transact(args *NewTxArgs, reply *TxResponse) error { +func (p *MainPackage) Transact(args *NewTxArgs, reply *string) error { err := args.requirements() if err != nil { return err } + result, _ := p.ethp.Transact(p.ethp.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + *reply = NewSuccessRes(result) return nil } @@ -134,6 +139,8 @@ func (p *MainPackage) Create(args *NewTxArgs, reply *string) error { if err != nil { return err } + result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body) + *reply = NewSuccessRes(result) return nil } diff --git a/etherpc/server.go b/etherpc/server.go index ba0c51006a..7929563cb3 100644 --- a/etherpc/server.go +++ b/etherpc/server.go @@ -1,6 +1,7 @@ package etherpc import ( + "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethutil" "net" "net/rpc" @@ -10,6 +11,7 @@ import ( type JsonRpcServer struct { quit chan bool listener net.Listener + ethp *ethpub.PEthereum } func (s *JsonRpcServer) exitHandler() { @@ -32,7 +34,7 @@ func (s *JsonRpcServer) Stop() { func (s *JsonRpcServer) Start() { ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") go s.exitHandler() - rpc.Register(new(MainPackage)) + rpc.Register(&MainPackage{ethp: s.ethp}) rpc.HandleHTTP() for { @@ -46,7 +48,7 @@ func (s *JsonRpcServer) Start() { } } -func NewJsonRpcServer() *JsonRpcServer { +func NewJsonRpcServer(ethp *ethpub.PEthereum) *JsonRpcServer { l, err := net.Listen("tcp", ":30304") if err != nil { ethutil.Config.Log.Infoln("Error starting JSON-RPC") @@ -55,5 +57,6 @@ func NewJsonRpcServer() *JsonRpcServer { return &JsonRpcServer{ listener: l, quit: make(chan bool), + ethp: ethp, } } diff --git a/ethpub/pub.go b/ethpub/pub.go index c6f177124a..3c579001e3 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -87,7 +87,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript) } else { // Just in case it was submitted as a 0x prefixed string - if initStr[0:2] == "0x" { + if len(initStr) > 0 && initStr[0:2] == "0x" { initStr = initStr[2:len(initStr)] } tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) diff --git a/ethpub/types.go b/ethpub/types.go index bf06ce2f64..4d9f9ad850 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -8,8 +8,8 @@ import ( // Block interface exposed to QML type PBlock struct { - Number int - Hash string + Number int `json:"number"` + Hash string `json:"hash"` } // Creates a new QML Block from a chain block @@ -44,10 +44,10 @@ func NewPKey(key *ethchain.KeyPair) *PKey { } type PReceipt struct { - CreatedContract bool - Address string - Hash string - Sender string + CreatedContract bool `json:"createdContract"` + Address string `json:"address"` + Hash string `json:"hash"` + Sender string `json:"sender"` } func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { From 7c91159449c528daa099aec5a3744aa8a6b5a826 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 11:56:25 +0200 Subject: [PATCH 0265/1237] Added different storage notification object --- ethchain/state_manager.go | 2 +- ethchain/state_object.go | 6 ++++++ ethpub/pub.go | 12 ++++++++++++ ethpub/types.go | 36 ++++++++++++++++++++++++++---------- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 02d0345d75..501ec102bf 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -350,7 +350,7 @@ func (sm *StateManager) notifyChanges() { for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { for addr, value := range mappedObjects { - sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, value.String()) + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4ec91d2e08..6176460777 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -186,3 +186,9 @@ type CachedStateObject struct { Nonce uint64 Object *StateObject } + +type StorageState struct { + StateAddress []byte + Address []byte + Value *big.Int +} diff --git a/ethpub/pub.go b/ethpub/pub.go index c6f177124a..5f23018f7f 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -47,6 +47,18 @@ func (lib *PEthereum) GetStateObject(address string) *PStateObject { return NewPStateObject(nil) } +func (lib *PEthereum) GetStorage(address, storageAddress string) string { + return lib.GetStateObject(address).GetStorage(storageAddress) +} + +func (lib *PEthereum) GetTxCount(address string) int { + return lib.GetStateObject(address).Nonce() +} + +func (lib *PEthereum) IsContract(address string) bool { + return lib.GetStateObject(address).IsContract() +} + func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "") } diff --git a/ethpub/types.go b/ethpub/types.go index bf06ce2f64..7ae476339d 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -59,16 +59,6 @@ func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) * } } -/* -type PKeyRing struct { - Keys []interface{} -} - -func NewPKeyRing(keys []interface{}) *PKeyRing { - return &PKeyRing{Keys: keys} -} -*/ - type PStateObject struct { object *ethchain.StateObject } @@ -105,3 +95,29 @@ func (c *PStateObject) Address() string { return "" } + +func (c *PStateObject) Nonce() int { + if c.object != nil { + return int(c.object.Nonce) + } + + return 0 +} + +func (c *PStateObject) IsContract() bool { + if c.object != nil { + return len(c.object.Script()) > 0 + } + + return false +} + +type PStorageState struct { + StateAddress string + Address string + Value string +} + +func NewPStorageState(storageObject *ethchain.StorageState) *PStorageState { + return &PStorageState{ethutil.Hex(storageObject.StateAddress), ethutil.Hex(storageObject.Address), storageObject.Value.String()} +} From 39b8c83ba66d429d04fa8b9be62813c848f0d606 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 13:01:02 +0200 Subject: [PATCH 0266/1237] Impelemented GetStorageAt --- etherpc/packages.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/etherpc/packages.go b/etherpc/packages.go index 271a59879c..85306d3d76 100644 --- a/etherpc/packages.go +++ b/etherpc/packages.go @@ -115,9 +115,6 @@ func (a *NewTxArgs) requirementsContract() error { if a.GasPrice == "" { return NewErrorResponse("Create requires a 'gasprice' value as argument") } - if a.Init == "" { - return NewErrorResponse("Create requires a 'init' value as argument") - } if a.Body == "" { return NewErrorResponse("Create requires a 'body' value as argument") } @@ -144,7 +141,8 @@ func (p *MainPackage) Create(args *NewTxArgs, reply *string) error { return nil } -func (p *MainPackage) getKey(args interface{}, reply *string) error { +func (p *MainPackage) GetKey(args interface{}, reply *string) error { + *reply = NewSuccessRes(p.ethp.GetKey()) return nil } @@ -163,11 +161,20 @@ func (a *GetStorageArgs) requirements() error { return nil } -func (p *MainPackage) getStorageAt(args *GetStorageArgs, reply *string) error { +type GetStorageAtRes struct { + Key string `json:"key"` + Value string `json:"value"` + Address string `json:"address"` +} + +func (p *MainPackage) GetStorageAt(args *GetStorageArgs, reply *string) error { err := args.requirements() if err != nil { return err } + state := p.ethp.GetStateObject(args.Address) + value := state.GetStorage(args.Key) + *reply = NewSuccessRes(&GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil } From 5757f5df2a5ffc4207ab2be5f1280d4f2e95d303 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 13:09:29 +0200 Subject: [PATCH 0267/1237] Added secret to address method --- ethpub/pub.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethpub/pub.go b/ethpub/pub.go index 5f23018f7f..f9d2ebc72e 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -59,6 +59,15 @@ func (lib *PEthereum) IsContract(address string) bool { return lib.GetStateObject(address).IsContract() } +func (lib *PEthereum) SecretToAddress(key string) string { + pair, err := ethchain.NewKeyPairFromSec(ethutil.FromHex(key)) + if err != nil { + return "" + } + + return ethutil.Hex(pair.Address()) +} + func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "") } From 8adad0654a46e4cad925a14f1c238081958558df Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 13:49:46 +0200 Subject: [PATCH 0268/1237] Added more JSON niceties to types --- ethpub/types.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index 4d9f9ad850..522f0e7ac8 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -34,9 +34,9 @@ func NewPTx(tx *ethchain.Transaction) *PTx { } type PKey struct { - Address string - PrivateKey string - PublicKey string + Address string `json:"address"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` } func NewPKey(key *ethchain.KeyPair) *PKey { From c496aad20bebdeea240ee4b6cc8730d484240ca8 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 13:49:59 +0200 Subject: [PATCH 0269/1237] Renamed Ethereum RPC package --- etherpc/packages.go | 25 ++++++++++++++++--------- etherpc/server.go | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/etherpc/packages.go b/etherpc/packages.go index 85306d3d76..5074b02190 100644 --- a/etherpc/packages.go +++ b/etherpc/packages.go @@ -7,7 +7,7 @@ import ( _ "log" ) -type MainPackage struct { +type EthereumApi struct { ethp *ethpub.PEthereum } @@ -65,7 +65,7 @@ func (b *GetBlockArgs) requirements() error { return nil } -func (p *MainPackage) GetBlock(args *GetBlockArgs, reply *string) error { +func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { err := args.requirements() if err != nil { return err @@ -121,7 +121,7 @@ func (a *NewTxArgs) requirementsContract() error { return nil } -func (p *MainPackage) Transact(args *NewTxArgs, reply *string) error { +func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { err := args.requirements() if err != nil { return err @@ -131,7 +131,7 @@ func (p *MainPackage) Transact(args *NewTxArgs, reply *string) error { return nil } -func (p *MainPackage) Create(args *NewTxArgs, reply *string) error { +func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { err := args.requirementsContract() if err != nil { return err @@ -141,7 +141,7 @@ func (p *MainPackage) Create(args *NewTxArgs, reply *string) error { return nil } -func (p *MainPackage) GetKey(args interface{}, reply *string) error { +func (p *EthereumApi) GetKey(args interface{}, reply *string) error { *reply = NewSuccessRes(p.ethp.GetKey()) return nil } @@ -167,14 +167,14 @@ type GetStorageAtRes struct { Address string `json:"address"` } -func (p *MainPackage) GetStorageAt(args *GetStorageArgs, reply *string) error { +func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { err := args.requirements() if err != nil { return err } state := p.ethp.GetStateObject(args.Address) value := state.GetStorage(args.Key) - *reply = NewSuccessRes(&GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) + *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil } @@ -189,11 +189,18 @@ func (a *GetBalanceArgs) requirements() error { return nil } -func (p *MainPackage) GetBalanceAt(args *GetBalanceArgs, reply *string) error { +type BalanceRes struct { + Balance string `json:"balance"` + Address string `json:"address"` +} + +func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { err := args.requirements() if err != nil { return err } + state := p.ethp.GetStateObject(args.Address) + *reply = NewSuccessRes(BalanceRes{Balance: state.Value(), Address: args.Address}) return nil } @@ -202,7 +209,7 @@ type TestRes struct { Answer int `json:"answer"` } -func (p *MainPackage) Test(args *GetBlockArgs, reply *string) error { +func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error { *reply = NewSuccessRes(TestRes{Answer: 15}) return nil } diff --git a/etherpc/server.go b/etherpc/server.go index 7929563cb3..49b4604cc8 100644 --- a/etherpc/server.go +++ b/etherpc/server.go @@ -34,7 +34,7 @@ func (s *JsonRpcServer) Stop() { func (s *JsonRpcServer) Start() { ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") go s.exitHandler() - rpc.Register(&MainPackage{ethp: s.ethp}) + rpc.Register(&EthereumApi{ethp: s.ethp}) rpc.HandleHTTP() for { From fde3e01f80420c367139a9fe647c618b0223842d Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 14:15:31 +0200 Subject: [PATCH 0270/1237] Fixed import cycle --- ethereum.go | 5 +++-- etherpc/server.go | 2 +- ethpub/pub.go | 9 ++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethereum.go b/ethereum.go index 6cb1a916fd..d6154e2138 100644 --- a/ethereum.go +++ b/ethereum.go @@ -4,6 +4,7 @@ import ( "container/list" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/etherpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "io/ioutil" @@ -63,7 +64,7 @@ type Ethereum struct { reactor *ethutil.ReactorEngine - // TODO: This no worky: RpcServer *etherpc.JsonRpcServer + RpcServer *etherpc.JsonRpcServer } func New(caps Caps, usePnp bool) (*Ethereum, error) { @@ -338,9 +339,9 @@ func (s *Ethereum) Stop() { close(s.quit) + s.RpcServer.Stop() s.txPool.Stop() s.stateManager.Stop() - // TODO: THIS NO WORKY: s.RpcServer.Stop() close(s.shutdownChan) } diff --git a/etherpc/server.go b/etherpc/server.go index 49b4604cc8..0eb2295360 100644 --- a/etherpc/server.go +++ b/etherpc/server.go @@ -41,7 +41,7 @@ func (s *JsonRpcServer) Start() { conn, err := s.listener.Accept() if err != nil { ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err) - continue + break } ethutil.Config.Log.Debugln("[JSON] Incoming request.") go jsonrpc.ServeConn(conn) diff --git a/ethpub/pub.go b/ethpub/pub.go index 3c579001e3..5dc08160f7 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -1,7 +1,6 @@ package ethpub import ( - "github.com/ethereum/eth-go" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" ) @@ -12,11 +11,11 @@ type PEthereum struct { txPool *ethchain.TxPool } -func NewPEthereum(eth *eth.Ethereum) *PEthereum { +func NewPEthereum(sm *ethchain.StateManager, bc *ethchain.BlockChain, txp *ethchain.TxPool) *PEthereum { return &PEthereum{ - eth.StateManager(), - eth.BlockChain(), - eth.TxPool(), + sm, + bc, + txp, } } From b98cc2fb4e296c7a9efe50293cc43d6f9ef6f23d Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 14:15:58 +0200 Subject: [PATCH 0271/1237] Fixed GetBlock when no block can be found --- ethpub/pub.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 5dc08160f7..64109dbfa3 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -24,7 +24,15 @@ func (lib *PEthereum) GetBlock(hexHash string) *PBlock { block := lib.blockChain.GetBlock(hash) - return &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} + var blockInfo *PBlock + + if block != nil { + blockInfo = &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} + } else { + blockInfo = &PBlock{Number: -1, Hash: ""} + } + + return blockInfo } func (lib *PEthereum) GetKey() *PKey { From 9b1f11695d544b99ba0b7ddedc4ac561a68d8197 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 14:20:20 +0200 Subject: [PATCH 0272/1237] Get rid of that annoying number that keeps popping up in stdout --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 323773ba79..6092006499 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -139,7 +139,7 @@ func (log *Logger) Infoln(v ...interface{}) { return } - fmt.Println(len(log.logSys)) + //fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } From a4ca9927abc774fe524635a38d2f3bf2c4831278 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 15:15:14 +0200 Subject: [PATCH 0273/1237] Renamed etherpc to ethrpc --- ethereum.go | 4 +- etherpc/packages.go | 215 -------------------------------------------- etherpc/server.go | 62 ------------- 3 files changed, 2 insertions(+), 279 deletions(-) delete mode 100644 etherpc/packages.go delete mode 100644 etherpc/server.go diff --git a/ethereum.go b/ethereum.go index d6154e2138..707938639a 100644 --- a/ethereum.go +++ b/ethereum.go @@ -4,7 +4,7 @@ import ( "container/list" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/etherpc" + "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "io/ioutil" @@ -64,7 +64,7 @@ type Ethereum struct { reactor *ethutil.ReactorEngine - RpcServer *etherpc.JsonRpcServer + RpcServer *ethrpc.JsonRpcServer } func New(caps Caps, usePnp bool) (*Ethereum, error) { diff --git a/etherpc/packages.go b/etherpc/packages.go deleted file mode 100644 index 5074b02190..0000000000 --- a/etherpc/packages.go +++ /dev/null @@ -1,215 +0,0 @@ -package etherpc - -import ( - "encoding/json" - "errors" - "github.com/ethereum/eth-go/ethpub" - _ "log" -) - -type EthereumApi struct { - ethp *ethpub.PEthereum -} - -type JsonArgs interface { - requirements() error -} - -type BlockResponse struct { - JsonResponse -} -type GetBlockArgs struct { - BlockNumber int - Hash string -} - -type ErrorResponse struct { - Error bool `json:"error"` - ErrorText string `json:"errorText"` -} - -type JsonResponse interface { -} - -type SuccessRes struct { - Error bool `json:"error"` - Result JsonResponse `json:"result"` -} - -func NewSuccessRes(object JsonResponse) string { - e := SuccessRes{Error: false, Result: object} - res, err := json.Marshal(e) - if err != nil { - // This should never happen - panic("Creating json error response failed, help") - } - success := string(res) - return success -} - -func NewErrorResponse(msg string) error { - e := ErrorResponse{Error: true, ErrorText: msg} - res, err := json.Marshal(e) - if err != nil { - // This should never happen - panic("Creating json error response failed, help") - } - newErr := errors.New(string(res)) - return newErr -} - -func (b *GetBlockArgs) requirements() error { - if b.BlockNumber == 0 && b.Hash == "" { - return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") - } - return nil -} - -func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - // Do something - block := p.ethp.GetBlock(args.Hash) - *reply = NewSuccessRes(block) - return nil -} - -type NewTxArgs struct { - Sec string - Recipient string - Value string - Gas string - GasPrice string - Init string - Body string -} -type TxResponse struct { - Hash string -} - -func (a *NewTxArgs) requirements() error { - if a.Recipient == "" { - return NewErrorResponse("Transact requires a 'recipient' address as argument") - } - if a.Value == "" { - return NewErrorResponse("Transact requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Transact requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Transact requires a 'gasprice' value as argument") - } - return nil -} - -func (a *NewTxArgs) requirementsContract() error { - if a.Value == "" { - return NewErrorResponse("Create requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Create requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Create requires a 'gasprice' value as argument") - } - if a.Body == "" { - return NewErrorResponse("Create requires a 'body' value as argument") - } - return nil -} - -func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - result, _ := p.ethp.Transact(p.ethp.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) - *reply = NewSuccessRes(result) - return nil -} - -func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { - err := args.requirementsContract() - if err != nil { - return err - } - result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body) - *reply = NewSuccessRes(result) - return nil -} - -func (p *EthereumApi) GetKey(args interface{}, reply *string) error { - *reply = NewSuccessRes(p.ethp.GetKey()) - return nil -} - -type GetStorageArgs struct { - Address string - Key string -} - -func (a *GetStorageArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetStorageAt requires an 'address' value as argument") - } - if a.Key == "" { - return NewErrorResponse("GetStorageAt requires an 'key' value as argument") - } - return nil -} - -type GetStorageAtRes struct { - Key string `json:"key"` - Value string `json:"value"` - Address string `json:"address"` -} - -func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - state := p.ethp.GetStateObject(args.Address) - value := state.GetStorage(args.Key) - *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) - return nil -} - -type GetBalanceArgs struct { - Address string -} - -func (a *GetBalanceArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") - } - return nil -} - -type BalanceRes struct { - Balance string `json:"balance"` - Address string `json:"address"` -} - -func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - state := p.ethp.GetStateObject(args.Address) - *reply = NewSuccessRes(BalanceRes{Balance: state.Value(), Address: args.Address}) - return nil -} - -type TestRes struct { - JsonResponse `json:"-"` - Answer int `json:"answer"` -} - -func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error { - *reply = NewSuccessRes(TestRes{Answer: 15}) - return nil -} diff --git a/etherpc/server.go b/etherpc/server.go deleted file mode 100644 index 0eb2295360..0000000000 --- a/etherpc/server.go +++ /dev/null @@ -1,62 +0,0 @@ -package etherpc - -import ( - "github.com/ethereum/eth-go/ethpub" - "github.com/ethereum/eth-go/ethutil" - "net" - "net/rpc" - "net/rpc/jsonrpc" -) - -type JsonRpcServer struct { - quit chan bool - listener net.Listener - ethp *ethpub.PEthereum -} - -func (s *JsonRpcServer) exitHandler() { -out: - for { - select { - case <-s.quit: - s.listener.Close() - break out - } - } - - ethutil.Config.Log.Infoln("[JSON] Shutdown JSON-RPC server") -} - -func (s *JsonRpcServer) Stop() { - close(s.quit) -} - -func (s *JsonRpcServer) Start() { - ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") - go s.exitHandler() - rpc.Register(&EthereumApi{ethp: s.ethp}) - rpc.HandleHTTP() - - for { - conn, err := s.listener.Accept() - if err != nil { - ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err) - break - } - ethutil.Config.Log.Debugln("[JSON] Incoming request.") - go jsonrpc.ServeConn(conn) - } -} - -func NewJsonRpcServer(ethp *ethpub.PEthereum) *JsonRpcServer { - l, err := net.Listen("tcp", ":30304") - if err != nil { - ethutil.Config.Log.Infoln("Error starting JSON-RPC") - } - - return &JsonRpcServer{ - listener: l, - quit: make(chan bool), - ethp: ethp, - } -} From 3e5a7b34b111e5b72cd4878cdee42af956143406 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 5 May 2014 15:15:43 +0200 Subject: [PATCH 0274/1237] Now with files --- ethrpc/packages.go | 215 +++++++++++++++++++++++++++++++++++++++++++++ ethrpc/server.go | 62 +++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 ethrpc/packages.go create mode 100644 ethrpc/server.go diff --git a/ethrpc/packages.go b/ethrpc/packages.go new file mode 100644 index 0000000000..b989a65cb3 --- /dev/null +++ b/ethrpc/packages.go @@ -0,0 +1,215 @@ +package ethrpc + +import ( + "encoding/json" + "errors" + "github.com/ethereum/eth-go/ethpub" + _ "log" +) + +type EthereumApi struct { + ethp *ethpub.PEthereum +} + +type JsonArgs interface { + requirements() error +} + +type BlockResponse struct { + JsonResponse +} +type GetBlockArgs struct { + BlockNumber int + Hash string +} + +type ErrorResponse struct { + Error bool `json:"error"` + ErrorText string `json:"errorText"` +} + +type JsonResponse interface { +} + +type SuccessRes struct { + Error bool `json:"error"` + Result JsonResponse `json:"result"` +} + +func NewSuccessRes(object JsonResponse) string { + e := SuccessRes{Error: false, Result: object} + res, err := json.Marshal(e) + if err != nil { + // This should never happen + panic("Creating json error response failed, help") + } + success := string(res) + return success +} + +func NewErrorResponse(msg string) error { + e := ErrorResponse{Error: true, ErrorText: msg} + res, err := json.Marshal(e) + if err != nil { + // This should never happen + panic("Creating json error response failed, help") + } + newErr := errors.New(string(res)) + return newErr +} + +func (b *GetBlockArgs) requirements() error { + if b.BlockNumber == 0 && b.Hash == "" { + return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") + } + return nil +} + +func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + // Do something + block := p.ethp.GetBlock(args.Hash) + *reply = NewSuccessRes(block) + return nil +} + +type NewTxArgs struct { + Sec string + Recipient string + Value string + Gas string + GasPrice string + Init string + Body string +} +type TxResponse struct { + Hash string +} + +func (a *NewTxArgs) requirements() error { + if a.Recipient == "" { + return NewErrorResponse("Transact requires a 'recipient' address as argument") + } + if a.Value == "" { + return NewErrorResponse("Transact requires a 'value' as argument") + } + if a.Gas == "" { + return NewErrorResponse("Transact requires a 'gas' value as argument") + } + if a.GasPrice == "" { + return NewErrorResponse("Transact requires a 'gasprice' value as argument") + } + return nil +} + +func (a *NewTxArgs) requirementsContract() error { + if a.Value == "" { + return NewErrorResponse("Create requires a 'value' as argument") + } + if a.Gas == "" { + return NewErrorResponse("Create requires a 'gas' value as argument") + } + if a.GasPrice == "" { + return NewErrorResponse("Create requires a 'gasprice' value as argument") + } + if a.Body == "" { + return NewErrorResponse("Create requires a 'body' value as argument") + } + return nil +} + +func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + result, _ := p.ethp.Transact(p.ethp.GetKey().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + *reply = NewSuccessRes(result) + return nil +} + +func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { + err := args.requirementsContract() + if err != nil { + return err + } + result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body) + *reply = NewSuccessRes(result) + return nil +} + +func (p *EthereumApi) GetKey(args interface{}, reply *string) error { + *reply = NewSuccessRes(p.ethp.GetKey()) + return nil +} + +type GetStorageArgs struct { + Address string + Key string +} + +func (a *GetStorageArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetStorageAt requires an 'address' value as argument") + } + if a.Key == "" { + return NewErrorResponse("GetStorageAt requires an 'key' value as argument") + } + return nil +} + +type GetStorageAtRes struct { + Key string `json:"key"` + Value string `json:"value"` + Address string `json:"address"` +} + +func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + state := p.ethp.GetStateObject(args.Address) + value := state.GetStorage(args.Key) + *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) + return nil +} + +type GetBalanceArgs struct { + Address string +} + +func (a *GetBalanceArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") + } + return nil +} + +type BalanceRes struct { + Balance string `json:"balance"` + Address string `json:"address"` +} + +func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + state := p.ethp.GetStateObject(args.Address) + *reply = NewSuccessRes(BalanceRes{Balance: state.Value(), Address: args.Address}) + return nil +} + +type TestRes struct { + JsonResponse `json:"-"` + Answer int `json:"answer"` +} + +func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error { + *reply = NewSuccessRes(TestRes{Answer: 15}) + return nil +} diff --git a/ethrpc/server.go b/ethrpc/server.go new file mode 100644 index 0000000000..40787fadec --- /dev/null +++ b/ethrpc/server.go @@ -0,0 +1,62 @@ +package ethrpc + +import ( + "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethutil" + "net" + "net/rpc" + "net/rpc/jsonrpc" +) + +type JsonRpcServer struct { + quit chan bool + listener net.Listener + ethp *ethpub.PEthereum +} + +func (s *JsonRpcServer) exitHandler() { +out: + for { + select { + case <-s.quit: + s.listener.Close() + break out + } + } + + ethutil.Config.Log.Infoln("[JSON] Shutdown JSON-RPC server") +} + +func (s *JsonRpcServer) Stop() { + close(s.quit) +} + +func (s *JsonRpcServer) Start() { + ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") + go s.exitHandler() + rpc.Register(&EthereumApi{ethp: s.ethp}) + rpc.HandleHTTP() + + for { + conn, err := s.listener.Accept() + if err != nil { + ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err) + break + } + ethutil.Config.Log.Debugln("[JSON] Incoming request.") + go jsonrpc.ServeConn(conn) + } +} + +func NewJsonRpcServer(ethp *ethpub.PEthereum) *JsonRpcServer { + l, err := net.Listen("tcp", ":30304") + if err != nil { + ethutil.Config.Log.Infoln("Error starting JSON-RPC") + } + + return &JsonRpcServer{ + listener: l, + quit: make(chan bool), + ethp: ethp, + } +} From 14a6e6a9cea48bcc7f6d5286e4f85b1a0cce84d8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 15:48:17 +0200 Subject: [PATCH 0275/1237] Added the ability to submit byte code for contracts instead of Mutan code. --- ethpub/pub.go | 23 +++++++++++++++++------ ethutil/bytes.go | 5 +++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 431f173a09..4ec9877b2f 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -103,13 +103,24 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in var tx *ethchain.Transaction // Compile and assemble the given data if contractCreation { - initScript, err := ethutil.Compile(initStr) - if err != nil { - return nil, err + var initScript, mainScript []byte + var err error + if ethutil.IsHex(initStr) { + initScript = ethutil.FromHex(initStr) + } else { + initScript, err = ethutil.Compile(initStr[2:]) + if err != nil { + return nil, err + } } - mainScript, err := ethutil.Compile(scriptStr) - if err != nil { - return nil, err + + if ethutil.IsHex(scriptStr) { + mainScript = ethutil.FromHex(scriptStr[2:]) + } else { + mainScript, err = ethutil.Compile(scriptStr) + if err != nil { + return nil, err + } } tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 500368017b..b298675a29 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -83,3 +83,8 @@ func CopyBytes(b []byte) (copiedBytes []byte) { return } + +func IsHex(str string) bool { + l := len(str) + return l >= 4 && l%2 == 0 && str[0:2] == "0x" +} From 78cb04cca3daafa178558a3dec5f4814f824dc95 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 15:51:43 +0200 Subject: [PATCH 0276/1237] wrong string --- ethpub/pub.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 4ec9877b2f..5e7792a9f2 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -106,9 +106,9 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in var initScript, mainScript []byte var err error if ethutil.IsHex(initStr) { - initScript = ethutil.FromHex(initStr) + initScript = ethutil.FromHex(initStr[2:]) } else { - initScript, err = ethutil.Compile(initStr[2:]) + initScript, err = ethutil.Compile(initStr) if err != nil { return nil, err } From fedd4c906ff9f6139cb2d88e4f1adefbf6ea81a6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 15:55:26 +0200 Subject: [PATCH 0277/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d810643bf..0a622fdcbd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC1". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index 6092006499..382396ceb6 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -51,7 +51,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From af6875f4b25145402b20e37ab037d912f54ec968 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 5 May 2014 17:14:29 +0200 Subject: [PATCH 0278/1237] Changed to lower case --- ethchain/vm_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 35a7b2e3f5..f4a0197ea0 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -86,7 +86,7 @@ func TestRun4(t *testing.T) { int32 a = 10 int32 b = 20 if a > b { - int32 c = this.Caller() + int32 c = this.caller() } Exit() `), false) @@ -98,21 +98,21 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store - if store[1000] == 0 { - store[1000] = 10^20 + if this.store[1000] == 0 { + this.store[1000] = 10^20 } - store[1001] = this.Value() * 20 - store[this.Origin()] = store[this.Origin()] + 1000 + this.store[1001] = this.value() * 20 + this.store[this.origin()] = this.store[this.origin()] + 1000 - if store[1001] > 20 { - store[1001] = 10^50 + if this.store[1001] > 20 { + this.store[1001] = 10^50 } int8 ret = 0 int8 arg = 10 - Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) + call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) big t for int8 i = 0; i < 10; i++ { From e18b96b486abefb587fd93cfe33fe6edcd8cbb87 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 6 May 2014 14:15:02 +0200 Subject: [PATCH 0279/1237] Fix an issue where we don't have the rpc so we dont have to close it --- ethereum.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index 707938639a..2f4db7336b 100644 --- a/ethereum.go +++ b/ethereum.go @@ -339,7 +339,9 @@ func (s *Ethereum) Stop() { close(s.quit) - s.RpcServer.Stop() + if s.RpcServer != nil { + s.RpcServer.Stop() + } s.txPool.Stop() s.stateManager.Stop() From 050684450befaac8972120688b69825e8f0acbca Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 6 May 2014 17:04:52 +0200 Subject: [PATCH 0280/1237] Assume arguments are supplied as strings to the rpc interface --- ethrpc/packages.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index b989a65cb3..4ec2b46028 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -4,7 +4,8 @@ import ( "encoding/json" "errors" "github.com/ethereum/eth-go/ethpub" - _ "log" + "github.com/ethereum/eth-go/ethutil" + "math/big" ) type EthereumApi struct { @@ -173,7 +174,10 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { return err } state := p.ethp.GetStateObject(args.Address) - value := state.GetStorage(args.Key) + // Convert the incoming string (which is a bigint) into hex + i, _ := new(big.Int).SetString(args.Key, 10) + hx := ethutil.Hex(i.Bytes()) + value := state.GetStorage(hx) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil } From a0af7de58eeba598c8e967ae9deefb4ee287a1df Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 6 May 2014 17:43:27 +0200 Subject: [PATCH 0281/1237] Optimizations --- ethchain/asm.go | 16 +----- ethchain/types.go | 134 +++++++++++++++++++++++++++++++++++++++------- ethchain/vm.go | 30 ++++------- 3 files changed, 125 insertions(+), 55 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index 3194549bac..d46e46af7e 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,7 +21,7 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH: // Push PC+1 on to the stack + case oPUSH32: // Push PC+1 on to the stack pc.Add(pc, ethutil.Big1) data := script[pc.Int64() : pc.Int64()+32] val := ethutil.BigD(data) @@ -36,20 +36,6 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("0x%x", b)) pc.Add(pc, big.NewInt(31)) - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+20] - val := ethutil.BigD(data) - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(19)) } pc.Add(pc, ethutil.Big1) diff --git a/ethchain/types.go b/ethchain/types.go index 827d4f27f4..f9b7a84f58 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -48,8 +48,6 @@ const ( oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution - oPUSH = 0x50 - oPUSH20 = 0x80 oPOP = 0x51 oDUP = 0x52 oSWAP = 0x53 @@ -63,14 +61,48 @@ const ( oPC = 0x5b oMSIZE = 0x5c - // 0x60 range - closures - oCREATE = 0x60 - oCALL = 0x61 - oRETURN = 0x62 + // 0x60 range + oPUSH1 = 0x60 + oPUSH2 = 0x61 + oPUSH3 = 0x62 + oPUSH4 = 0x63 + oPUSH5 = 0x64 + oPUSH6 = 0x65 + oPUSH7 = 0x66 + oPUSH8 = 0x67 + oPUSH9 = 0x68 + oPUSH10 = 0x69 + oPUSH11 = 0x6a + oPUSH12 = 0x6b + oPUSH13 = 0x6c + oPUSH14 = 0x6d + oPUSH15 = 0x6e + oPUSH16 = 0x6f + oPUSH17 = 0x70 + oPUSH18 = 0x71 + oPUSH19 = 0x72 + oPUSH20 = 0x73 + oPUSH21 = 0x74 + oPUSH22 = 0x75 + oPUSH23 = 0x76 + oPUSH24 = 0x77 + oPUSH25 = 0x78 + oPUSH26 = 0x79 + oPUSH27 = 0x7a + oPUSH28 = 0x7b + oPUSH29 = 0x7c + oPUSH30 = 0x7d + oPUSH31 = 0x7e + oPUSH32 = 0x7f + + // 0xf0 range - closures + oCREATE = 0xf0 + oCALL = 0xf2 + oRETURN = 0xf3 // 0x70 range - other - oLOG = 0x70 // XXX Unofficial - oSUICIDE = 0x7f + oLOG = 0xfe // XXX Unofficial + oSUICIDE = 0xff ) // Since the opcodes aren't all in order we can't use a regular slice @@ -119,8 +151,6 @@ var opCodeToString = map[OpCode]string{ oGASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution - oPUSH: "PUSH", - oPOP: "POP", oDUP: "DUP", oSWAP: "SWAP", oMLOAD: "MLOAD", @@ -133,7 +163,41 @@ var opCodeToString = map[OpCode]string{ oPC: "PC", oMSIZE: "MSIZE", - // 0x60 range - closures + // 0x60 range - push + oPUSH1: "PUSH1", + oPUSH2: "PUSH2", + oPUSH3: "PUSH3", + oPUSH4: "PUSH4", + oPUSH5: "PUSH5", + oPUSH6: "PUSH6", + oPUSH7: "PUSH7", + oPUSH8: "PUSH8", + oPUSH9: "PUSH9", + oPUSH10: "PUSH10", + oPUSH11: "PUSH11", + oPUSH12: "PUSH12", + oPUSH13: "PUSH13", + oPUSH14: "PUSH14", + oPUSH15: "PUSH15", + oPUSH16: "PUSH16", + oPUSH17: "PUSH17", + oPUSH18: "PUSH18", + oPUSH19: "PUSH19", + oPUSH20: "PUSH20", + oPUSH21: "PUSH21", + oPUSH22: "PUSH22", + oPUSH23: "PUSH23", + oPUSH24: "PUSH24", + oPUSH25: "PUSH25", + oPUSH26: "PUSH26", + oPUSH27: "PUSH27", + oPUSH28: "PUSH28", + oPUSH29: "PUSH29", + oPUSH30: "PUSH30", + oPUSH31: "PUSH31", + oPUSH32: "PUSH32", + + // 0xf0 range oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", @@ -193,10 +257,6 @@ var OpCodes = map[string]byte{ "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - "POP": 0x51, "DUP": 0x52, "SWAP": 0x53, @@ -210,13 +270,47 @@ var OpCodes = map[string]byte{ "PC": 0x5b, "MSIZE": 0x5c, - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, + // 0x70 range - 'push' + "PUSH1": 0x60, + "PUSH2": 0x61, + "PUSH3": 0x62, + "PUSH4": 0x63, + "PUSH5": 0x64, + "PUSH6": 0x65, + "PUSH7": 0x66, + "PUSH8": 0x67, + "PUSH9": 0x68, + "PUSH10": 0x69, + "PUSH11": 0x6a, + "PUSH12": 0x6b, + "PUSH13": 0x6c, + "PUSH14": 0x6d, + "PUSH15": 0x6e, + "PUSH16": 0x6f, + "PUSH17": 0x70, + "PUSH18": 0x71, + "PUSH19": 0x72, + "PUSH20": 0x73, + "PUSH21": 0x74, + "PUSH22": 0x75, + "PUSH23": 0x76, + "PUSH24": 0x77, + "PUSH25": 0x78, + "PUSH26": 0x70, + "PUSH27": 0x7a, + "PUSH28": 0x7b, + "PUSH29": 0x7c, + "PUSH30": 0x7d, + "PUSH31": 0x7e, + "PUSH32": 0x7f, + + // 0xf0 range - closures + "CREATE": 0xf0, + "CALL": 0xf1, + "RETURN": 0xf2, // 0x70 range - other - "LOG": 0x70, + "LOG": 0xfe, "SUICIDE": 0x7f, } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a3b3447aa..bac3130061 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,6 +95,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("# op\n") } + fmt.Println(closure.Script) + for { // The base for all big integer arithmetic base := new(big.Int) @@ -104,11 +106,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } gas := new(big.Int) useGas := func(amount *big.Int) { @@ -352,27 +352,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO stack.Push(big.NewInt(0)) - // 0x50 range - case oPUSH: // Push PC+1 on to the stack + // 0x50 range + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: + a := big.NewInt(int64(op) - int64(oPUSH1) + 1) pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(32)) + data := closure.Gets(pc, a) val := ethutil.BigD(data.Bytes()) - // Push value to stack stack.Push(val) - - pc.Add(pc, big.NewInt(31)) + pc.Add(pc, a.Sub(a, big.NewInt(1))) step++ - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(20)) - val := ethutil.BigD(data.Bytes()) - // Push value to stack - stack.Push(val) - - pc.Add(pc, big.NewInt(19)) - step++ case oPOP: require(1) stack.Pop() From 45ce820b111ab2b4e4c7b8d83dd8bebf1bb37bad Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 7 May 2014 11:05:49 +0200 Subject: [PATCH 0282/1237] Implemented value() --- ethchain/state_manager.go | 1 + ethchain/vm.go | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 501ec102bf..e8843a89e5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -331,6 +331,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + Value: tx.Value, //Price: tx.GasPrice, }) closure.Call(vm, tx.Data, nil) diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a3b3447aa..234f7f72ae 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" + "log" _ "math" "math/big" ) @@ -53,6 +54,7 @@ type RuntimeVars struct { Time int64 Diff *big.Int TxData []string + Value *big.Int } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { @@ -324,8 +326,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: - // FIXME: Original value of the call, not the current value - stack.Push(closure.Value) + log.Println("Value:", vm.vars.Value) + stack.Push(vm.vars.Value) case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() From 554f4f6f7d8b8bc5332d42631ec9de0d7015eccf Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 14:20:06 +0200 Subject: [PATCH 0283/1237] Fixed disasamble for all pushes --- ethchain/asm.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index d46e46af7e..492be09991 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,9 +21,10 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH32: // Push PC+1 on to the stack + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+32] + a := int64(op) - int64(oPUSH1) + 1 + data := script[pc.Int64() : pc.Int64()+a] val := ethutil.BigD(data) var b []byte @@ -35,7 +36,7 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("0x%x", b)) - pc.Add(pc, big.NewInt(31)) + pc.Add(pc, big.NewInt(a-1)) } pc.Add(pc, ethutil.Big1) From f0440e85dc306f270666e3aee1fe419b684a2ae8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 14:20:45 +0200 Subject: [PATCH 0284/1237] Removed value from closure. --- ethchain/closure.go | 4 +--- ethchain/state_manager.go | 2 +- ethchain/types.go | 4 ++-- ethchain/vm.go | 26 +++++++++++++++++--------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 7e911ad993..0f1e386ae2 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -24,20 +24,18 @@ type Closure struct { Gas *big.Int Price *big.Int - Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects // and we don't want the transaction's values to change. c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) - c.Value = new(big.Int).Set(val) return c } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e8843a89e5..b8a893d15e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -323,7 +323,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) + closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) vm := NewVm(sm.procState, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, diff --git a/ethchain/types.go b/ethchain/types.go index f9b7a84f58..9964bbe3bf 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -97,8 +97,8 @@ const ( // 0xf0 range - closures oCREATE = 0xf0 - oCALL = 0xf2 - oRETURN = 0xf3 + oCALL = 0xf1 + oRETURN = 0xf2 // 0x70 range - other oLOG = 0xfe // XXX Unofficial diff --git a/ethchain/vm.go b/ethchain/vm.go index b4c77c849f..ee470c269d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" - "log" _ "math" "math/big" ) @@ -96,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } - fmt.Println(closure.Script) for { @@ -320,13 +318,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: - stack.Push(closure.Value) + stack.Push(closure.object.Amount) case oORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case oCALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: - log.Println("Value:", vm.vars.Value) stack.Push(vm.vars.Value) case oCALLDATALOAD: require(1) @@ -406,13 +403,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue case oJUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue } case oPC: stack.Push(pc) @@ -441,8 +440,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro contract.initScript, vm.state, gas, - closure.Price, - value) + closure.Price) // Call the closure and set the return value as // main script. closure.Script, err = closure.Call(vm, nil, hook) @@ -469,10 +467,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro break } + // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) + fmt.Println("before", contract.Amount) if contract != nil { // Prepay for the gas @@ -482,8 +483,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas = new(big.Int).Set(closure.Gas) } closure.Gas.Sub(closure.Gas, gas) + + // Add the value to the state object + contract.AddAmount(value) + // Create a new callable closure - closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -496,6 +501,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.stateManager.manifest.AddObjectChange(contract) } + vm.state.SetStateObject(contract) + fmt.Println("after", contract.Amount) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) From d709815106824a3469b5f4152fd32705d7d142d4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 18:26:46 +0200 Subject: [PATCH 0285/1237] Added trans state and removed watch address etc The transient state can be used to test out changes before committing them to the proc state. The transient state is currently being used by the gui to support proper nonce updating without having to wait for a block. This used to be done by a cached state mechanism which can now safely by removed. --- ethchain/state_manager.go | 24 ++++++++---------------- ethchain/transaction_pool.go | 3 +-- ethpub/pub.go | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b8a893d15e..fb5753ab38 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -50,6 +50,10 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State + // Transiently state. The trans state isn't ever saved, validated and + // it could be used for setting account nonces without effecting + // the main states. + transState *State manifest *Manifest } @@ -65,6 +69,8 @@ func NewStateManager(ethereum EthManager) *StateManager { manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() + sm.transState = sm.procState.Copy() + return sm } @@ -72,22 +78,8 @@ func (sm *StateManager) ProcState() *State { return sm.procState } -// Watches any given address and puts it in the address state store -func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { - //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) - account := sm.procState.GetAccount(addr) - - return sm.stateObjectCache.Add(addr, account) -} - -func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject { - account := sm.stateObjectCache.Get(addr) - if account == nil { - a := sm.procState.GetAccount(addr) - account = &CachedStateObject{Nonce: a.Nonce, Object: a} - } - - return account +func (sm *StateManager) TransState() *State { + return sm.transState } func (sm *StateManager) BlockChain() *BlockChain { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 72836d6cb1..56deae0c69 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -148,8 +148,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) - sender := accountState.Object + sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient diff --git a/ethpub/pub.go b/ethpub/pub.go index 5e7792a9f2..f7e641b359 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -92,7 +92,14 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in hash = ethutil.FromHex(recipient) } - keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + var keyPair *ethchain.KeyPair + var err error + if key[0:2] == "0x" { + keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2]))) + } else { + keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + } + if err != nil { return nil, err } @@ -132,8 +139,11 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) } - acc := lib.stateManager.GetAddrState(keyPair.Address()) + acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) + //acc := lib.stateManager.GetAddrState(keyPair.Address()) tx.Nonce = acc.Nonce + lib.stateManager.TransState().SetStateObject(acc) + tx.Sign(keyPair.PrivateKey) lib.txPool.QueueTransaction(tx) From e8fb965ccbb65807c1f462e8f2ee82508a822b58 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 18:41:45 +0200 Subject: [PATCH 0286/1237] Cleaned up Removed the unneeded address watch mechanism. State manager's transient state should now take care of this. --- ethchain/state_manager.go | 33 +++++++++------------------------ ethchain/state_object.go | 29 ++--------------------------- 2 files changed, 11 insertions(+), 51 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index fb5753ab38..76b02f9abf 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -25,24 +25,16 @@ type EthManager interface { type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex - // Canonical block chain bc *BlockChain - // States for addresses. You can watch any address - // at any given time - stateObjectCache *StateObjectCache - // Stack for processing contracts stack *Stack // non-persistent key/value memory storage mem map[string]*big.Int - + // Proof of work used for validating Pow PoW - + // The ethereum manager interface Ethereum EthManager - - SecondaryBlockProcessor BlockProcessor - // The managed states // Processor state. Anything processed will be applied to this // state @@ -54,19 +46,18 @@ type StateManager struct { // it could be used for setting account nonces without effecting // the main states. transState *State - + // Manifest for keeping changes regarding state objects. See `notify` manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - stateObjectCache: NewStateObjectCache(), - bc: ethereum.BlockChain(), - manifest: NewManifest(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + bc: ethereum.BlockChain(), + manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.transState = sm.procState.Copy() @@ -193,12 +184,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Add the block to the chain sm.bc.Add(block) - // If there's a block processor present, pass in the block for further - // processing - if sm.SecondaryBlockProcessor != nil { - sm.SecondaryBlockProcessor.ProcessBlock(block) - } - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 6176460777..b38ee4f5c9 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -160,33 +160,8 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } -// The cached state and state object cache are helpers which will give you somewhat -// control over the nonce. When creating new transactions you're interested in the 'next' -// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. -type StateObjectCache struct { - cachedObjects map[string]*CachedStateObject -} - -func NewStateObjectCache() *StateObjectCache { - return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)} -} - -func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject { - state := &CachedStateObject{Nonce: object.Nonce, Object: object} - s.cachedObjects[string(addr)] = state - - return state -} - -func (s *StateObjectCache) Get(addr []byte) *CachedStateObject { - return s.cachedObjects[string(addr)] -} - -type CachedStateObject struct { - Nonce uint64 - Object *StateObject -} - +// Storage change object. Used by the manifest for notifying changes to +// the sub channels. type StorageState struct { StateAddress []byte Address []byte From 5a0bae1dae831818740a2f20ca308c4176f5201d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 8 May 2014 19:09:36 +0200 Subject: [PATCH 0287/1237] Auto update state changes notifications --- ethchain/closure.go | 6 +++--- ethchain/state.go | 35 ++++------------------------------- ethchain/state_manager.go | 15 +++++++-------- ethchain/state_object.go | 2 +- ethchain/vm.go | 11 +++-------- 5 files changed, 18 insertions(+), 51 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 0f1e386ae2..59194e4e82 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -11,7 +11,7 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte GetMem(*big.Int) *ethutil.Value - SetMem(*big.Int, *ethutil.Value) + SetStore(*big.Int, *ethutil.Value) N() *big.Int } @@ -64,8 +64,8 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { return ethutil.NewValue(partial) } -func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { - c.object.SetMem(x, val) +func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { + c.object.SetStorage(x, val) } func (c *Closure) Address() []byte { diff --git a/ethchain/state.go b/ethchain/state.go index 1b5655d4cd..5d42c40c0f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -15,11 +15,13 @@ type State struct { trie *ethutil.Trie // Nested states states map[string]*State + + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State)} + return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} } // Resets the trie and all siblings @@ -124,36 +126,6 @@ const ( UnknownTy ) -/* -// Returns the object stored at key and the type stored at key -// Returns nil if nothing is stored -func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { - // Fetch data from the trie - data := s.trie.Get(string(key)) - // Returns the nil type, indicating nothing could be retrieved. - // Anything using this function should check for this ret val - if data == "" { - return nil, NilTy - } - - var typ ObjType - val := ethutil.NewValueFromBytes([]byte(data)) - // Check the length of the retrieved value. - // Len 2 = Account - // Len 3 = Contract - // Other = invalid for now. If other types emerge, add them here - if val.Len() == 2 { - typ = AccountTy - } else if val.Len() == 3 { - typ = ContractTy - } else { - typ = UnknownTy - } - - return val, typ -} -*/ - // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() @@ -163,6 +135,7 @@ func (s *State) UpdateStateObject(object *StateObject) { } s.trie.Update(string(addr), string(object.RlpEncode())) + s.manifest.AddObjectChange(object) } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 76b02f9abf..9ab378b675 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -47,7 +47,9 @@ type StateManager struct { // the main states. transState *State // Manifest for keeping changes regarding state objects. See `notify` - manifest *Manifest + // XXX Should we move the manifest to the State object. Benefit: + // * All states can keep their own local changes + //manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { @@ -57,7 +59,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Pow: &EasyPow{}, Ethereum: ethereum, bc: ethereum.BlockChain(), - manifest: NewManifest(), + //manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.transState = sm.procState.Copy() @@ -190,7 +192,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { sm.notifyChanges() - sm.manifest.Reset() + sm.procState.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -315,18 +317,15 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.manifest.AddObjectChange(account) - sm.procState.UpdateStateObject(object) - sm.manifest.AddObjectChange(object) } func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.manifest.objectChanges { + for addr, stateObject := range sm.procState.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index b38ee4f5c9..7a11a11522 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { +func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index ee470c269d..584c666112 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -395,10 +395,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oSSTORE: require(2) val, loc := stack.Popn() - closure.SetMem(loc, ethutil.NewValue(val)) + closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest - vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) + vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() @@ -473,7 +473,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) - fmt.Println("before", contract.Amount) if contract != nil { // Prepay for the gas @@ -497,12 +496,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //contract.State().Reset() } else { stack.Push(ethutil.BigTrue) - // Notify of the changes - vm.stateManager.manifest.AddObjectChange(contract) } vm.state.SetStateObject(contract) - fmt.Println("after", contract.Amount) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { @@ -520,8 +516,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - - vm.stateManager.manifest.AddObjectChange(receiver) + vm.state.SetStateObject(receiver) closure.object.state.Purge() From afe83af219c2146e022f6665cf30097b582d3e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 9 May 2014 16:09:28 +0200 Subject: [PATCH 0288/1237] Moved seeding and moved manifest --- ethchain/state.go | 47 +++++++++++++++++----- ethchain/state_manager.go | 33 --------------- ethereum.go | 84 ++++++++++++++++++++------------------- ethutil/config.go | 1 - 4 files changed, 81 insertions(+), 84 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 5d42c40c0f..d02584d679 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -116,16 +116,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -type ObjType byte - -const ( - NilTy ObjType = iota - AccountTy - ContractTy - - UnknownTy -) - // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() @@ -145,3 +135,40 @@ func (s *State) Put(key, object []byte) { func (s *State) Root() interface{} { return s.trie.Root } + +// Object manifest +// +// The object manifest is used to keep changes to the state so we can keep track of the changes +// that occurred during a state transitioning phase. +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + objectChanges map[string]*StateObject + storageChanges map[string]map[string]*big.Int +} + +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.objectChanges = make(map[string]*StateObject) + m.storageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.objectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.storageChanges[string(stateObject.Address())] == nil { + m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) + } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9ab378b675..dd21a31b1d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -331,36 +331,3 @@ func (sm *StateManager) notifyChanges() { } } } - -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - objectChanges map[string]*StateObject - storageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.objectChanges = make(map[string]*StateObject) - m.storageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.objectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.storageChanges[string(stateObject.Address())] == nil { - m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage -} diff --git a/ethereum.go b/ethereum.go index 2f4db7336b..e3140b5ce5 100644 --- a/ethereum.go +++ b/ethereum.go @@ -253,7 +253,7 @@ func (s *Ethereum) ReapDeadPeerHandler() { } // Start the ethereum -func (s *Ethereum) Start() { +func (s *Ethereum) Start(seed bool) { // Bind to addr and port ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { @@ -272,47 +272,51 @@ func (s *Ethereum) Start() { // Start the reaping processes go s.ReapDeadPeerHandler() - if ethutil.Config.Seed { - ethutil.Config.Log.Debugln("Seeding") - // DNS Bootstrapping - _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") - if err == nil { - peers := []string{} - // Iterate SRV nodes - for _, n := range nodes { - target := n.Target - port := strconv.Itoa(int(n.Port)) - // Resolve target to ip (Go returns list, so may resolve to multiple ips?) - addr, err := net.LookupHost(target) - if err == nil { - for _, a := range addr { - // Build string out of SRV port and Resolved IP - peer := net.JoinHostPort(a, port) - log.Println("Found DNS Bootstrap Peer:", peer) - peers = append(peers, peer) - } - } else { - log.Println("Couldn't resolve :", target) - } - } - // Connect to Peer list - s.ProcessPeerList(peers) - } else { - // Fallback to servers.poc3.txt - resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } + if seed { + s.Seed() + } +} - s.ConnectToPeer(string(body)) +func (s *Ethereum) Seed() { + ethutil.Config.Log.Debugln("Seeding") + // DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if err == nil { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := strconv.Itoa(int(n.Port)) + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if err == nil { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, port) + log.Println("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) + } + } else { + log.Println("Couldn't resolve :", target) + } } + // Connect to Peer list + s.ProcessPeerList(peers) + } else { + // Fallback to servers.poc3.txt + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } + + s.ConnectToPeer(string(body)) } } diff --git a/ethutil/config.go b/ethutil/config.go index 382396ceb6..db07e1d182 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -27,7 +27,6 @@ type config struct { Ver string ClientString string Pubkey []byte - Seed bool } var Config *config From c03bf14e02fe7f13944b71f5370b1d7bd5978ffe Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 02:01:09 +0200 Subject: [PATCH 0289/1237] Fixed some tests --- ethchain/vm_test.go | 67 +----------------------------------------- ethutil/common_test.go | 2 +- ethutil/rlp_test.go | 15 +++------- 3 files changed, 6 insertions(+), 78 deletions(-) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index f4a0197ea0..b919b496f1 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -11,71 +11,6 @@ import ( "testing" ) -/* -func TestRun3(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "300", - "PUSH", "0", - "MSTORE", - - "PUSH", "32", - "CALLDATA", - - "PUSH", "64", - "PUSH", "0", - "RETURN", - }) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) - addr := tx.Hash()[12:] - contract := MakeContract(tx, state) - state.UpdateContract(contract) - - callerScript := ethutil.Assemble( - "PUSH", 1337, // Argument - "PUSH", 65, // argument mem offset - "MSTORE", - "PUSH", 64, // ret size - "PUSH", 0, // ret offset - - "PUSH", 32, // arg size - "PUSH", 65, // arg offset - "PUSH", 1000, /// Gas - "PUSH", 0, /// value - "PUSH", addr, // Sender - "CALL", - "PUSH", 64, - "PUSH", 0, - "RETURN", - ) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) - - // Contract addr as test address - account := NewAccount(ContractAddr, big.NewInt(10000000)) - callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) - - vm := NewVm(state, RuntimeVars{ - origin: account.Address(), - blockNumber: 1, - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - txData: nil, - }) - ret := callerClosure.Call(vm, nil) - - exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57} - if bytes.Compare(ret, exp) != 0 { - t.Errorf("expected return value to be %v, got %v", exp, ret) - } -}*/ - func TestRun4(t *testing.T) { ethutil.ReadConfig("") @@ -142,7 +77,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) + callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), diff --git a/ethutil/common_test.go b/ethutil/common_test.go index b5c733ff3a..8031f08ab5 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -26,7 +26,7 @@ func TestCommon(t *testing.T) { t.Error("Got", szabo) } - if vito != "10 Vito" { + if vito != "10 Vita" { t.Error("Got", vito) } diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 9e8127aab2..095c01ecc3 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,7 +2,6 @@ package ethutil import ( "bytes" - "fmt" "math/big" "reflect" "testing" @@ -56,15 +55,6 @@ func TestValue(t *testing.T) { } } -func TestEncodeDecodeMaran(t *testing.T) { - b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"}) - a := b.Encode() - fmt.Println("voor maran", a) - f, i := Decode(a, 0) - fmt.Println("voor maran 2", f) - fmt.Println(i) -} - func TestEncode(t *testing.T) { strRes := "\x83dog" bytes := Encode("dog") @@ -131,7 +121,10 @@ func TestEncodeDecodeBytes(t *testing.T) { func TestEncodeZero(t *testing.T) { b := NewValue(0).Encode() - fmt.Println(b) + exp := []byte{0xc0} + if bytes.Compare(b, exp) == 0 { + t.Error("Expected", exp, "got", b) + } } func BenchmarkEncodeDecode(b *testing.B) { From dbf8645aafb19837d01b939ba9b1d3e1a2fffbf9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 02:02:54 +0200 Subject: [PATCH 0290/1237] Bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index db07e1d182..5e36b06d2f 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From d3d9ed62e26247c680e23a94fd84b078d45cb3bc Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 16:23:07 +0200 Subject: [PATCH 0291/1237] Upgraded to new mutan --- ethutil/config.go | 2 +- ethutil/script.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index 5e36b06d2f..feab23e023 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC3"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } diff --git a/ethutil/script.go b/ethutil/script.go index 620658025a..94e4014069 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -24,7 +24,7 @@ func Compile(script string) ([]byte, error) { func CompileScript(script string) ([]byte, []byte, error) { // Preprocess - mainInput, initInput := mutan.PreProcess(script) + mainInput, initInput := mutan.PreParse(script) // Compile main script mainScript, err := Compile(mainInput) if err != nil { From e22e83b19aabc7711a6cd4e95bae460142d4db04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 10 May 2014 16:23:50 +0200 Subject: [PATCH 0292/1237] bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a622fdcbd..617a1ac8a3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC1". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC3". 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. From 4eb3ad192e58bc42dec4e44b4a8be6cb36473c0f Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 12:28:56 +0200 Subject: [PATCH 0293/1237] Made the debug line for invalid peer versions dynamic --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 80ddc5142a..9b8b3f2aed 100644 --- a/peer.go +++ b/peer.go @@ -549,7 +549,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data if c.Get(0).Uint() != ProtocolVersion { - ethutil.Config.Log.Debugln("Invalid peer version. Require protocol v5") + ethutil.Config.Log.Debugln("Invalid peer version. Require protocol:", ProtocolVersion) p.Stop() return } From 8b4ed8c505111cb570c7c694675b833ebf0bba21 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 13:39:37 +0200 Subject: [PATCH 0294/1237] Properly exchange peer capabilities between peers --- ethereum.go | 4 ++++ peer.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ethereum.go b/ethereum.go index e3140b5ce5..97ea35d453 100644 --- a/ethereum.go +++ b/ethereum.go @@ -122,6 +122,10 @@ func (s *Ethereum) TxPool() *ethchain.TxPool { return s.txPool } +func (s *Ethereum) ServerCaps() Caps { + return s.serverCaps +} + func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) diff --git a/peer.go b/peer.go index 9b8b3f2aed..54e6af823c 100644 --- a/peer.go +++ b/peer.go @@ -146,6 +146,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { port: 30303, pubkey: pubkey, blocksRequested: 10, + caps: ethereum.ServerCaps(), } } @@ -573,7 +574,6 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } // Catch up with the connected peer - // p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) p.SyncWithBlocks() // Set the peer's caps From 7f9fd0879207b7aba6c8e27d3e0b4672cba98bfb Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 15:08:21 +0200 Subject: [PATCH 0295/1237] Implemented proper peer checking when adding new peers We now resolve a hostname to IP before we try to compare it to the existing peer pool --- ethereum.go | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/ethereum.go b/ethereum.go index 97ea35d453..0f5bd11a20 100644 --- a/ethereum.go +++ b/ethereum.go @@ -2,6 +2,7 @@ package eth import ( "container/list" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethrpc" @@ -9,9 +10,11 @@ import ( "github.com/ethereum/eth-go/ethwire" "io/ioutil" "log" + "math/rand" "net" "net/http" "strconv" + "strings" "sync" "sync/atomic" "time" @@ -146,15 +149,51 @@ func (s *Ethereum) ConnectToPeer(addr string) error { if s.peers.Len() < s.MaxPeers { var alreadyConnected bool + ahost, _, _ := net.SplitHostPort(addr) + var chost string + + ips, err := net.LookupIP(ahost) + + if err != nil { + return err + } else { + // If more then one ip is available try stripping away the ipv6 ones + if len(ips) > 1 { + var ipsv4 []net.IP + // For now remove the ipv6 addresses + for _, ip := range ips { + if strings.Contains(ip.String(), "::") { + continue + } else { + ipsv4 = append(ipsv4, ip) + } + } + if len(ipsv4) == 0 { + return fmt.Errorf("[SERV] No IPV4 addresses available for hostname") + } + + // Pick a random ipv4 address, simulating round-robin DNS. + rand.Seed(time.Now().UTC().UnixNano()) + i := rand.Intn(len(ipsv4)) + chost = ipsv4[i].String() + } else { + if len(ips) == 0 { + return fmt.Errorf("[SERV] No IPs resolved for the given hostname") + return nil + } + chost = ips[0].String() + } + } + eachPeer(s.peers, func(p *Peer, v *list.Element) { if p.conn == nil { return } phost, _, _ := net.SplitHostPort(p.conn.RemoteAddr().String()) - ahost, _, _ := net.SplitHostPort(addr) - if phost == ahost { + if phost == chost { alreadyConnected = true + ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost) return } }) From 5fcbaefd0b20af2a13ad9f6c3359b8c1ca096ba6 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 15:43:10 +0200 Subject: [PATCH 0296/1237] Don't forward localhost connections over the public network --- peer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 54e6af823c..d8168e455a 100644 --- a/peer.go +++ b/peer.go @@ -534,7 +534,10 @@ func (p *Peer) peersMessage() *ethwire.Msg { outPeers := make([]interface{}, len(p.ethereum.InOutPeers())) // Serialise each peer for i, peer := range p.ethereum.InOutPeers() { - outPeers[i] = peer.RlpData() + // Don't return localhost as valid peer + if !net.ParseIP(peer.conn.RemoteAddr().String()).IsLoopback() { + outPeers[i] = peer.RlpData() + } } // Return the message to the peer with the known list of connected clients From 8fe0864680b40c3fa5e47775856d8ae1997ba003 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 16:09:23 +0200 Subject: [PATCH 0297/1237] Only accept peers if we asked for them --- peer.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/peer.go b/peer.go index d8168e455a..359e835665 100644 --- a/peer.go +++ b/peer.go @@ -401,22 +401,22 @@ func (p *Peer) HandleInbound() { case ethwire.MsgPeersTy: // Received a list of peers (probably because MsgGetPeersTy was send) // Only act on message if we actually requested for a peers list - //if p.requestedPeerList { - data := msg.Data - // Create new list of possible peers for the ethereum to process - peers := make([]string, data.Len()) - // Parse each possible peer - for i := 0; i < data.Len(); i++ { - value := data.Get(i) - peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint()) + if p.requestedPeerList { + data := msg.Data + // Create new list of possible peers for the ethereum to process + peers := make([]string, data.Len()) + // Parse each possible peer + for i := 0; i < data.Len(); i++ { + value := data.Get(i) + peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint()) + } + + // Connect to the list of peers + p.ethereum.ProcessPeerList(peers) + // Mark unrequested again + p.requestedPeerList = false + } - - // Connect to the list of peers - p.ethereum.ProcessPeerList(peers) - // Mark unrequested again - p.requestedPeerList = false - - //} case ethwire.MsgGetChainTy: var parent *ethchain.Block // Length minus one since the very last element in the array is a count From 52b664b0aec24bffc040da06bbe8be1d3e7e4ab8 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 16:30:21 +0200 Subject: [PATCH 0298/1237] Removed peers from peerlist as soon as they disconnect. Might fix #13 We used to wait for the reaping timer to clean up the peerlist, not any longer --- peer.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/peer.go b/peer.go index 359e835665..932dbdc18a 100644 --- a/peer.go +++ b/peer.go @@ -2,6 +2,7 @@ package eth import ( "bytes" + "container/list" "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" @@ -515,6 +516,15 @@ func (p *Peer) Stop() { p.writeMessage(ethwire.NewMessage(ethwire.MsgDiscTy, "")) p.conn.Close() } + + // Pre-emptively remove the peer; don't wait for reaping. We already know it's dead if we are here + p.ethereum.peerMut.Lock() + defer p.ethereum.peerMut.Unlock() + eachPeer(p.ethereum.peers, func(peer *Peer, e *list.Element) { + if peer == p { + p.ethereum.peers.Remove(e) + } + }) } func (p *Peer) pushHandshake() error { From cc341b8734cf2c424b9b4adf7861400992755d7a Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 12 May 2014 16:36:14 +0200 Subject: [PATCH 0299/1237] Added debug message if you try to add a peer when max peers has been reached. --- ethereum.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ethereum.go b/ethereum.go index 0f5bd11a20..bd391ba371 100644 --- a/ethereum.go +++ b/ethereum.go @@ -132,9 +132,13 @@ func (s *Ethereum) ServerCaps() Caps { func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) - if peer != nil && s.peers.Len() < s.MaxPeers { - s.peers.PushBack(peer) - peer.Start() + if peer != nil { + if s.peers.Len() < s.MaxPeers { + s.peers.PushBack(peer) + peer.Start() + } else { + ethutil.Config.Log.Debugf("[SERV] Max connected peers reached. Not adding incoming peer.") + } } } From 3647cc5b073b9c82d50394074c978628a32719e4 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 11:35:21 +0200 Subject: [PATCH 0300/1237] Implemented our own makeshift go seed. Fixes #16 --- ethereum.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ethereum.go b/ethereum.go index bd391ba371..92c4e4ba17 100644 --- a/ethereum.go +++ b/ethereum.go @@ -325,8 +325,21 @@ func (s *Ethereum) Start(seed bool) { } func (s *Ethereum) Seed() { - ethutil.Config.Log.Debugln("Seeding") - // DNS Bootstrapping + ethutil.Config.Log.Debugln("[SERV] Retrieving seed nodes") + + // Eth-Go Bootstrapping + ips, er := net.LookupIP("seed.bysh.me") + if er == nil { + peers := []string{} + for _, ip := range ips { + node := fmt.Sprintf("%s:%d", ip.String(), 30303) + ethutil.Config.Log.Debugln("[SERV] Found DNS Go Peer:", node) + peers = append(peers, node) + } + s.ProcessPeerList(peers) + } + + // Official DNS Bootstrapping _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") if err == nil { peers := []string{} @@ -340,11 +353,11 @@ func (s *Ethereum) Seed() { for _, a := range addr { // Build string out of SRV port and Resolved IP peer := net.JoinHostPort(a, port) - log.Println("Found DNS Bootstrap Peer:", peer) + ethutil.Config.Log.Debugln("[SERV] Found DNS Bootstrap Peer:", peer) peers = append(peers, peer) } } else { - log.Println("Couldn't resolve :", target) + ethutil.Config.Log.Debugln("[SERV} Couldn't resolve :", target) } } // Connect to Peer list From a9d5656a466f2d57bcf97efdc4644ca20ae8bd6b Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 11:49:55 +0200 Subject: [PATCH 0301/1237] Added support to NewJsonRpc to return an error as well as an interface Also changed default port to 8080. Fixes #18 --- ethrpc/server.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ethrpc/server.go b/ethrpc/server.go index 40787fadec..a612f1163d 100644 --- a/ethrpc/server.go +++ b/ethrpc/server.go @@ -48,15 +48,15 @@ func (s *JsonRpcServer) Start() { } } -func NewJsonRpcServer(ethp *ethpub.PEthereum) *JsonRpcServer { - l, err := net.Listen("tcp", ":30304") +func NewJsonRpcServer(ethp *ethpub.PEthereum) (*JsonRpcServer, error) { + l, err := net.Listen("tcp", ":8080") if err != nil { - ethutil.Config.Log.Infoln("Error starting JSON-RPC") + return nil, err } return &JsonRpcServer{ listener: l, quit: make(chan bool), ethp: ethp, - } + }, nil } From d31303a592bcf8662fbbe66e542535e0e82c5a83 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 12:01:34 +0200 Subject: [PATCH 0302/1237] Implemented support for a custom RPC port --- ethrpc/server.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethrpc/server.go b/ethrpc/server.go index a612f1163d..3960e641c3 100644 --- a/ethrpc/server.go +++ b/ethrpc/server.go @@ -1,6 +1,7 @@ package ethrpc import ( + "fmt" "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethutil" "net" @@ -48,8 +49,9 @@ func (s *JsonRpcServer) Start() { } } -func NewJsonRpcServer(ethp *ethpub.PEthereum) (*JsonRpcServer, error) { - l, err := net.Listen("tcp", ":8080") +func NewJsonRpcServer(ethp *ethpub.PEthereum, port int) (*JsonRpcServer, error) { + sport := fmt.Sprintf(":%d", port) + l, err := net.Listen("tcp", sport) if err != nil { return nil, err } From cac9562c059a94902dc420fea697026a682014bc Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 13 May 2014 12:42:24 +0200 Subject: [PATCH 0303/1237] Use EthManager interface instead --- ethpub/pub.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index f7e641b359..4ced632f5c 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -6,16 +6,18 @@ import ( ) type PEthereum struct { + manager ethchain.EthManager stateManager *ethchain.StateManager blockChain *ethchain.BlockChain txPool *ethchain.TxPool } -func NewPEthereum(sm *ethchain.StateManager, bc *ethchain.BlockChain, txp *ethchain.TxPool) *PEthereum { +func NewPEthereum(manager ethchain.EthManager) *PEthereum { return &PEthereum{ - sm, - bc, - txp, + manager, + manager.StateManager(), + manager.BlockChain(), + manager.TxPool(), } } From 28357d657b8c46e841fc96a61758652d2617b068 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 14:43:29 +0200 Subject: [PATCH 0304/1237] Implemented new JS/EthPub methods - getTxCountAt - getPeerCount - getIsMining - getIsListening - getCoinbase --- ethchain/state_manager.go | 3 +++ ethereum.go | 15 +++++++++++++++ ethpub/pub.go | 25 ++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index dd21a31b1d..bc8b468310 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -20,6 +20,9 @@ type EthManager interface { TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) Reactor() *ethutil.ReactorEngine + PeerCount() int + IsMining() bool + IsListening() bool } type StateManager struct { diff --git a/ethereum.go b/ethereum.go index 92c4e4ba17..94e338c560 100644 --- a/ethereum.go +++ b/ethereum.go @@ -65,6 +65,10 @@ type Ethereum struct { // Specifies the desired amount of maximum peers MaxPeers int + Mining bool + + listening bool + reactor *ethutil.ReactorEngine RpcServer *ethrpc.JsonRpcServer @@ -128,6 +132,15 @@ func (s *Ethereum) TxPool() *ethchain.TxPool { func (s *Ethereum) ServerCaps() Caps { return s.serverCaps } +func (s *Ethereum) IsMining() bool { + return s.Mining +} +func (s *Ethereum) PeerCount() int { + return s.peers.Len() +} +func (s *Ethereum) IsListening() bool { + return s.listening +} func (s *Ethereum) AddPeer(conn net.Conn) { peer := NewPeer(conn, s, true) @@ -305,7 +318,9 @@ func (s *Ethereum) Start(seed bool) { ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { log.Println("Connection listening disabled. Acting as client") + s.listening = false } else { + s.listening = true // Starting accepting connections ethutil.Config.Log.Infoln("Ready and accepting connections") // Start the peer handler diff --git a/ethpub/pub.go b/ethpub/pub.go index 4ced632f5c..1866d6fdfa 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -1,6 +1,8 @@ package ethpub import ( + "encoding/hex" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" ) @@ -56,11 +58,32 @@ func (lib *PEthereum) GetStateObject(address string) *PStateObject { return NewPStateObject(nil) } +func (lib *PEthereum) GetPeerCount() int { + return lib.manager.PeerCount() +} + +func (lib *PEthereum) GetIsMining() bool { + return lib.manager.IsMining() +} + +func (lib *PEthereum) GetIsListening() bool { + return lib.manager.IsListening() +} + +func (lib *PEthereum) GetCoinBase() string { + data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) + keyRing := ethutil.NewValueFromBytes(data) + key := keyRing.Get(0).Bytes() + + return lib.SecretToAddress(hex.EncodeToString(key)) +} + func (lib *PEthereum) GetStorage(address, storageAddress string) string { return lib.GetStateObject(address).GetStorage(storageAddress) } -func (lib *PEthereum) GetTxCount(address string) int { +func (lib *PEthereum) GetTxCountAt(address string) int { + fmt.Println("GO") return lib.GetStateObject(address).Nonce() } From c9ac5b0f74e3b1b3026fa1351e682916bf8f7c71 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 13 May 2014 14:44:12 +0200 Subject: [PATCH 0305/1237] Removed lingering log statement --- ethpub/pub.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 1866d6fdfa..4d15363689 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -2,7 +2,6 @@ package ethpub import ( "encoding/hex" - "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" ) @@ -83,7 +82,6 @@ func (lib *PEthereum) GetStorage(address, storageAddress string) string { } func (lib *PEthereum) GetTxCountAt(address string) int { - fmt.Println("GO") return lib.GetStateObject(address).Nonce() } From 86d6aba0127d6f35f5dda50d08dff05581031701 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 13 May 2014 16:36:43 +0200 Subject: [PATCH 0306/1237] Bumped --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 617a1ac8a3..72e187db70 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC3". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC4". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index feab23e023..07dc85f086 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC3"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC4"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From a4883a029f3585d7e263661c30cbd147f3d5d655 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 13 May 2014 17:51:33 +0200 Subject: [PATCH 0307/1237] Propagate back to network --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index bc8b468310..8f1eb1ce50 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -197,6 +197,9 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { sm.procState.manifest.Reset() } + + sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + } else { fmt.Println("total diff failed") } From 0c1f732c64b7c1380b2f0422ee82d462ea88dc03 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 11:29:57 +0200 Subject: [PATCH 0308/1237] Do not queue messages if the peer isn't connected (e.g. timing out) --- ethchain/state_manager.go | 1 - peer.go | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8f1eb1ce50..f830f2022c 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -199,7 +199,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - } else { fmt.Println("total diff failed") } diff --git a/peer.go b/peer.go index 932dbdc18a..70759f246d 100644 --- a/peer.go +++ b/peer.go @@ -187,6 +187,10 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { // Outputs any RLP encoded data to the peer func (p *Peer) QueueMessage(msg *ethwire.Msg) { + if atomic.LoadInt32(&p.connected) != 1 { + return + } + p.outputQueue <- msg } From 7c0df348f86d4ee47111b57b83fb1613e6338e05 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 11:52:16 +0200 Subject: [PATCH 0309/1237] Increased deadline --- ethwire/messaging.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index b622376f36..cc0e7a9a0b 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -69,6 +69,12 @@ func NewMessage(msgType MsgType, data interface{}) *Msg { } func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { + defer func() { + if r := recover(); r != nil { + panic(fmt.Sprintf("message error %d %v", len(data), data)) + } + }() + if len(data) == 0 { return nil, nil, true, nil } @@ -124,7 +130,7 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { var totalBytes int for { // Give buffering some time - conn.SetReadDeadline(time.Now().Add(20 * time.Millisecond)) + conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) // Create a new temporarily buffer b := make([]byte, 1440) // Wait for a message from this peer @@ -134,7 +140,6 @@ func ReadMessages(conn net.Conn) (msgs []*Msg, err error) { fmt.Println("err now", err) return nil, err } else { - fmt.Println("IOF NOW") break } From 0512113bdd5cc55ae35abd442b668ab5ed7a116b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 11:56:06 +0200 Subject: [PATCH 0310/1237] Removed defer --- ethwire/messaging.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index cc0e7a9a0b..cbcbbb8b7a 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -69,12 +69,6 @@ func NewMessage(msgType MsgType, data interface{}) *Msg { } func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { - defer func() { - if r := recover(); r != nil { - panic(fmt.Sprintf("message error %d %v", len(data), data)) - } - }() - if len(data) == 0 { return nil, nil, true, nil } From f4fa0d48cb10f925908062357be965c54370cba9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 13:54:40 +0200 Subject: [PATCH 0311/1237] Moved keyring to ethutil & removed old methods. Implements #20 --- ethchain/keypair.go | 87 ------------------------------- ethdb/database.go | 2 + ethdb/memory_database.go | 2 + ethpub/pub.go | 13 ++--- ethpub/types.go | 2 +- ethutil/db.go | 2 +- ethutil/key.go | 19 ------- ethutil/keypair.go | 109 +++++++++++++++++++++++++++++++++++++++ peer.go | 4 +- 9 files changed, 122 insertions(+), 118 deletions(-) delete mode 100644 ethchain/keypair.go delete mode 100644 ethutil/key.go create mode 100644 ethutil/keypair.go diff --git a/ethchain/keypair.go b/ethchain/keypair.go deleted file mode 100644 index 0f23bacdf8..0000000000 --- a/ethchain/keypair.go +++ /dev/null @@ -1,87 +0,0 @@ -package ethchain - -import ( - "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/secp256k1-go" - "math/big" -) - -type KeyPair struct { - PrivateKey []byte - PublicKey []byte - - // The associated account - account *StateObject - state *State -} - -func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { - pubkey, err := secp256k1.GeneratePubKey(seckey) - if err != nil { - return nil, err - } - - return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil -} - -func NewKeyPairFromValue(val *ethutil.Value) *KeyPair { - keyPair := &KeyPair{PrivateKey: val.Get(0).Bytes(), PublicKey: val.Get(1).Bytes()} - - return keyPair -} - -func (k *KeyPair) Address() []byte { - return ethutil.Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *KeyPair) Account() *StateObject { - if k.account == nil { - k.account = k.state.GetAccount(k.Address()) - } - - return k.account -} - -// Create transaction, creates a new and signed transaction, ready for processing -func (k *KeyPair) CreateTx(receiver []byte, value *big.Int, data []string) *Transaction { - /* TODO - tx := NewTransaction(receiver, value, data) - tx.Nonce = k.account.Nonce - - // Sign the transaction with the private key in this key chain - tx.Sign(k.PrivateKey) - - return tx - */ - return nil -} - -func (k *KeyPair) RlpEncode() []byte { - return ethutil.EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() -} - -type KeyRing struct { - keys []*KeyPair -} - -func (k *KeyRing) Add(pair *KeyPair) { - k.keys = append(k.keys, pair) -} - -// The public "singleton" keyring -var keyRing *KeyRing - -func GetKeyRing(state *State) *KeyRing { - if keyRing == nil { - keyRing = &KeyRing{} - - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - it := ethutil.NewValueFromBytes(data).NewIterator() - for it.Next() { - v := it.Value() - keyRing.Add(NewKeyPairFromValue(v)) - } - } - - return keyRing -} diff --git a/ethdb/database.go b/ethdb/database.go index 3dbff36dea..09e9d8c7d7 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -54,11 +54,13 @@ func (db *LDBDatabase) LastKnownTD() []byte { return data } +/* func (db *LDBDatabase) GetKeys() []*ethutil.Key { data, _ := db.Get([]byte("KeyRing")) return []*ethutil.Key{ethutil.NewKeyFromBytes(data)} } +*/ func (db *LDBDatabase) Close() { // Close the leveldb database diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index b0fa64ed78..1e9d2899ab 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -26,11 +26,13 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) { return db.db[string(key)], nil } +/* func (db *MemDatabase) GetKeys() []*ethutil.Key { data, _ := db.Get([]byte("KeyRing")) return []*ethutil.Key{ethutil.NewKeyFromBytes(data)} } +*/ func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) diff --git a/ethpub/pub.go b/ethpub/pub.go index 4d15363689..daacb9d782 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -39,10 +39,7 @@ func (lib *PEthereum) GetBlock(hexHash string) *PBlock { } func (lib *PEthereum) GetKey() *PKey { - keyPair, err := ethchain.NewKeyPairFromSec(ethutil.Config.Db.GetKeys()[0].PrivateKey) - if err != nil { - return nil - } + keyPair := ethutil.GetKeyRing().Get(0) return NewPKey(keyPair) } @@ -90,7 +87,7 @@ func (lib *PEthereum) IsContract(address string) bool { } func (lib *PEthereum) SecretToAddress(key string) string { - pair, err := ethchain.NewKeyPairFromSec(ethutil.FromHex(key)) + pair, err := ethutil.NewKeyPairFromSec(ethutil.FromHex(key)) if err != nil { return "" } @@ -115,12 +112,12 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in hash = ethutil.FromHex(recipient) } - var keyPair *ethchain.KeyPair + var keyPair *ethutil.KeyPair var err error if key[0:2] == "0x" { - keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2]))) + keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2]))) } else { - keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) } if err != nil { diff --git a/ethpub/types.go b/ethpub/types.go index 7f25e48a60..c902afc564 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -39,7 +39,7 @@ type PKey struct { PublicKey string `json:"publicKey"` } -func NewPKey(key *ethchain.KeyPair) *PKey { +func NewPKey(key *ethutil.KeyPair) *PKey { return &PKey{ethutil.Hex(key.Address()), ethutil.Hex(key.PrivateKey), ethutil.Hex(key.PublicKey)} } diff --git a/ethutil/db.go b/ethutil/db.go index abbf4a2b09..e02a80fca7 100644 --- a/ethutil/db.go +++ b/ethutil/db.go @@ -4,7 +4,7 @@ package ethutil type Database interface { Put(key []byte, value []byte) Get(key []byte) ([]byte, error) - GetKeys() []*Key + //GetKeys() []*Key Delete(key []byte) error LastKnownTD() []byte Close() diff --git a/ethutil/key.go b/ethutil/key.go deleted file mode 100644 index ec195f2136..0000000000 --- a/ethutil/key.go +++ /dev/null @@ -1,19 +0,0 @@ -package ethutil - -type Key struct { - PrivateKey []byte - PublicKey []byte -} - -func NewKeyFromBytes(data []byte) *Key { - val := NewValueFromBytes(data) - return &Key{val.Get(0).Bytes(), val.Get(1).Bytes()} -} - -func (k *Key) Address() []byte { - return Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *Key) RlpEncode() []byte { - return EmptyValue().Append(k.PrivateKey).Append(k.PublicKey).Encode() -} diff --git a/ethutil/keypair.go b/ethutil/keypair.go new file mode 100644 index 0000000000..cf5882e2c4 --- /dev/null +++ b/ethutil/keypair.go @@ -0,0 +1,109 @@ +package ethutil + +import ( + "github.com/obscuren/secp256k1-go" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + account *StateObject +} + +func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { + pubkey, err := secp256k1.GeneratePubKey(seckey) + if err != nil { + return nil, err + } + + return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil +} + +func NewKeyPairFromValue(val *Value) *KeyPair { + v, _ := NewKeyPairFromSec(val.Bytes()) + + return v +} + +func (k *KeyPair) Address() []byte { + return Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) RlpEncode() []byte { + return k.RlpValue().Encode() +} + +func (k *KeyPair) RlpValue() *Value { + return NewValue(k.PrivateKey) +} + +type KeyRing struct { + keys []*KeyPair +} + +func (k *KeyRing) Add(pair *KeyPair) { + k.keys = append(k.keys, pair) +} + +func (k *KeyRing) Get(i int) *KeyPair { + if len(k.keys) > i { + return k.keys[i] + } + + return nil +} + +func (k *KeyRing) Len() int { + return len(k.keys) +} + +func (k *KeyRing) NewKeyPair(sec []byte) (*KeyPair, error) { + keyPair, err := NewKeyPairFromSec(sec) + if err != nil { + return nil, err + } + + k.Add(keyPair) + Config.Db.Put([]byte("KeyRing"), k.RlpValue().Encode()) + + return keyPair, nil +} + +func (k *KeyRing) Reset() { + Config.Db.Put([]byte("KeyRing"), nil) + k.keys = nil +} + +func (k *KeyRing) RlpValue() *Value { + v := EmptyValue() + for _, keyPair := range k.keys { + v.Append(keyPair.RlpValue()) + } + + return v +} + +// The public "singleton" keyring +var keyRing *KeyRing + +func GetKeyRing() *KeyRing { + if keyRing == nil { + keyRing = &KeyRing{} + + data, _ := Config.Db.Get([]byte("KeyRing")) + it := NewValueFromBytes(data).NewIterator() + for it.Next() { + v := it.Value() + + key, err := NewKeyPairFromSec(v.Bytes()) + if err != nil { + panic(err) + } + keyRing.Add(key) + } + } + + return keyRing +} diff --git a/peer.go b/peer.go index 70759f246d..433ce161fb 100644 --- a/peer.go +++ b/peer.go @@ -581,8 +581,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.port = uint16(c.Get(4).Uint()) // Self connect detection - key := ethutil.Config.Db.GetKeys()[0] - if bytes.Compare(key.PublicKey, p.pubkey) == 0 { + keyPair := ethutil.GetKeyRing().Get(0) + if bytes.Compare(keyPair.PublicKey, p.pubkey) == 0 { p.Stop() return From 3ac74b1e7840720e8ae426c751328ed7595188a8 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 14 May 2014 13:57:04 +0200 Subject: [PATCH 0312/1237] Implemented IsUpToDate to mark the node as ready to start mining --- ethereum.go | 12 ++++++++++++ peer.go | 2 ++ 2 files changed, 14 insertions(+) diff --git a/ethereum.go b/ethereum.go index 94e338c560..83a74f3021 100644 --- a/ethereum.go +++ b/ethereum.go @@ -138,6 +138,18 @@ func (s *Ethereum) IsMining() bool { func (s *Ethereum) PeerCount() int { return s.peers.Len() } +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 { + upToDate = false + } + } + }) + return upToDate +} + func (s *Ethereum) IsListening() bool { return s.listening } diff --git a/peer.go b/peer.go index 70759f246d..0f968d664f 100644 --- a/peer.go +++ b/peer.go @@ -389,6 +389,8 @@ func (p *Peer) HandleInbound() { p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } } + + p.catchingUp = false case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and From 98a631b5563b8a87c3fc83f14256087251926a61 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 16:29:34 +0200 Subject: [PATCH 0313/1237] Remove any invalid transactions after block processing --- ethchain/state_manager.go | 2 ++ ethchain/transaction_pool.go | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f830f2022c..57d56469b2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -199,6 +199,8 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) + + sm.Ethereum.TxPool().RemoveInvalid(sm.procState) } else { fmt.Println("total diff failed") } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 56deae0c69..6c0282dc60 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -210,9 +210,9 @@ func (pool *TxPool) CurrentTransactions() []*Transaction { txList := make([]*Transaction, pool.pool.Len()) i := 0 for e := pool.pool.Front(); e != nil; e = e.Next() { - if tx, ok := e.Value.(*Transaction); ok { - txList[i] = tx - } + tx := e.Value.(*Transaction) + + txList[i] = tx i++ } @@ -220,6 +220,17 @@ func (pool *TxPool) CurrentTransactions() []*Transaction { return txList } +func (pool *TxPool) RemoveInvalid(state *State) { + for e := pool.pool.Front(); e != nil; e = e.Next() { + tx := e.Value.(*Transaction) + sender := state.GetAccount(tx.Sender()) + err := pool.ValidateTransaction(tx) + if err != nil || sender.Nonce != tx.Nonce { + pool.pool.Remove(e) + } + } +} + func (pool *TxPool) Flush() []*Transaction { txList := pool.CurrentTransactions() From 166853aed94484b327a89a2554312f6739fce8a9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 20:35:23 +0200 Subject: [PATCH 0314/1237] Test --- peer.go | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/peer.go b/peer.go index 29f98a4fbb..a509178d25 100644 --- a/peer.go +++ b/peer.go @@ -299,28 +299,6 @@ func (p *Peer) HandleInbound() { var block, lastBlock *ethchain.Block var err error - // 1. Compare the first block over the wire's prev-hash with the hash of your last block - // 2. If these two values are the same you can just link the chains together. - // [1:0,2:1,3:2] <- Current blocks (format block:previous_block) - // [1:0,2:1,3:2,4:3,5:4] <- incoming blocks - // == [1,2,3,4,5] - // 3. If the values are not the same we will have to go back and calculate the chain with the highest total difficulty - // [1:0,2:1,3:2,11:3,12:11,13:12] - // [1:0,2:1,3:2,4:3,5:4,6:5] - - // [3:2,11:3,12:11,13:12] - // [3:2,4:3,5:4,6:5] - // Heb ik dit blok? - // Nee: heb ik een blok met PrevHash 3? - // Ja: DIVERSION - // Nee; Adding to chain - - // See if we can find a common ancestor - // 1. Get the earliest block in the package. - // 2. Do we have this block? - // 3. Yes: Let's continue what we are doing - // 4. No: Let's request more blocks back. - // Make sure we are actually receiving anything if msg.Data.Len()-1 > 1 && p.catchingUp { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find @@ -342,8 +320,9 @@ func (p *Peer) HandleInbound() { if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { - //ethutil.Config.Log.Infof("[PEER] Local and foreign chain have diverted after %x, finding best chain!\n", block.PrevHash) if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { + p.catchingUp = false + return } } @@ -375,7 +354,8 @@ func (p *Peer) HandleInbound() { p.catchingUp = false p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } else if ethchain.IsValidationErr(err) { - // TODO + fmt.Println(err) + p.catchingUp = false } } else { // XXX Do we want to catch up if there were errors? @@ -385,12 +365,20 @@ func (p *Peer) HandleInbound() { blockInfo := lastBlock.BlockInfo() ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } + p.catchingUp = false - p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) + + hash := p.ethereum.BlockChain().CurrentBlock.Hash() + p.CatchupWithPeer(hash) } } - p.catchingUp = false + if lastBlock != nil && err == nil { + fmt.Println("Did proc. no err") + } else { + fmt.Println("other") + } + fmt.Println("length of chain", msg.Data.Len()) case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and @@ -453,7 +441,10 @@ func (p *Peer) HandleInbound() { if len(chain) > 0 { ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) + } else { + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{})) } + } else { ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain From a6b9ea05e8dc291f69f9384071864a475e7872e6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 20:36:21 +0200 Subject: [PATCH 0315/1237] Test --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index a509178d25..3e1e4a1811 100644 --- a/peer.go +++ b/peer.go @@ -442,7 +442,7 @@ func (p *Peer) HandleInbound() { ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { - p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{})) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{}{})) } } else { From 65f570271cc6bf2ea73a7ba2bf83d92a1ba42986 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 20:50:37 +0200 Subject: [PATCH 0316/1237] Fixed catching up --- peer.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/peer.go b/peer.go index 3e1e4a1811..4093a4902b 100644 --- a/peer.go +++ b/peer.go @@ -321,8 +321,6 @@ func (p *Peer) HandleInbound() { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { - p.catchingUp = false - return } } @@ -373,12 +371,11 @@ func (p *Peer) HandleInbound() { } } - if lastBlock != nil && err == nil { - fmt.Println("Did proc. no err") - } else { - fmt.Println("other") + if msg.Data.Len() == 0 { + // Set catching up to false if + // the peer has nothing left to give + p.catchingUp = false } - fmt.Println("length of chain", msg.Data.Len()) case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and From ad4ffdc9474aca48ab1d3d361797398f795a6d31 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 14 May 2014 21:34:13 +0200 Subject: [PATCH 0317/1237] Bumped version --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 72e187db70..2627bc85e2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC4". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC6". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index 07dc85f086..b4bd9158ec 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -50,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC4"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From 7bf2ae0b116fff0fede5b1455c5fda20caf98252 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 14:05:15 +0200 Subject: [PATCH 0318/1237] Removed old tx pool notification system. Fixes #19 --- ethchain/block_chain.go | 3 ++- ethchain/transaction_pool.go | 19 +++---------------- ethminer/miner.go | 4 ++-- ethutil/reactor.go | 3 ++- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2be4cd92b2..11fbc77957 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) @@ -268,6 +268,7 @@ func AddTestNetFunds(block *Block) { account.Amount = ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } + log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6c0282dc60..21ce8cdc1e 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -133,7 +133,8 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) - pool.notifySubscribers(TxPost, tx) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) return } @@ -188,10 +189,7 @@ out: pool.addTransaction(tx) // Notify the subscribers - pool.Ethereum.Reactor().Post("newTx", tx) - - // Notify the subscribers - pool.notifySubscribers(TxPre, tx) + pool.Ethereum.Reactor().Post("newTx:pre", tx) } case <-pool.quit: break out @@ -252,14 +250,3 @@ func (pool *TxPool) Stop() { log.Println("[TXP] Stopped") } - -func (pool *TxPool) Subscribe(channel chan TxMsg) { - pool.subscribers = append(pool.subscribers, channel) -} - -func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) { - msg := TxMsg{Type: ty, Tx: tx} - for _, subscriber := range pool.subscribers { - subscriber <- msg - } -} diff --git a/ethminer/miner.go b/ethminer/miner.go index 3796c873ed..f1d0caae9d 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -26,7 +26,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread ethereum.Reactor().Subscribe("newBlock", reactChan) - ethereum.Reactor().Subscribe("newTx", reactChan) + ethereum.Reactor().Subscribe("newTx:post", reactChan) // We need the quit chan to be a Reactor event. // The POW search method is actually blocking and if we don't @@ -34,7 +34,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { // The miner overseer will never get the reactor events themselves // Only after the miner will find the sha ethereum.Reactor().Subscribe("newBlock", quitChan) - ethereum.Reactor().Subscribe("newTx", quitChan) + ethereum.Reactor().Subscribe("newTx:post", quitChan) miner := Miner{ pow: ðchain.EasyPow{}, diff --git a/ethutil/reactor.go b/ethutil/reactor.go index f8084986c3..7cf1452456 100644 --- a/ethutil/reactor.go +++ b/ethutil/reactor.go @@ -46,6 +46,7 @@ func (e *ReactorEvent) Remove(ch chan React) { // Basic reactor resource type React struct { Resource interface{} + Event string } // The reactor basic engine. Acts as bridge @@ -81,6 +82,6 @@ func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) { func (reactor *ReactorEngine) Post(event string, resource interface{}) { ev := reactor.patterns[event] if ev != nil { - ev.Post(React{Resource: resource}) + ev.Post(React{Resource: resource, Event: event}) } } From f95993e326567555d0a2e1f96974c34e7b3a214f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 14:54:07 +0200 Subject: [PATCH 0319/1237] M --- ethchain/block_chain.go | 2 +- ethchain/state_manager.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 11fbc77957..1848b9ddb4 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 57d56469b2..143d9d6471 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -193,11 +193,11 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - sm.notifyChanges() - sm.procState.manifest.Reset() } + sm.notifyChanges() + sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.TxPool().RemoveInvalid(sm.procState) From 88686cbed27ad2e7d5c111051e06c270b1b352a3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 15 May 2014 15:00:25 +0200 Subject: [PATCH 0320/1237] listen to pre instead of post --- ethminer/miner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index f1d0caae9d..bc29b2588c 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -26,7 +26,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread ethereum.Reactor().Subscribe("newBlock", reactChan) - ethereum.Reactor().Subscribe("newTx:post", reactChan) + ethereum.Reactor().Subscribe("newTx:pre", reactChan) // We need the quit chan to be a Reactor event. // The POW search method is actually blocking and if we don't @@ -34,7 +34,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { // The miner overseer will never get the reactor events themselves // Only after the miner will find the sha ethereum.Reactor().Subscribe("newBlock", quitChan) - ethereum.Reactor().Subscribe("newTx:post", quitChan) + ethereum.Reactor().Subscribe("newTx:pre", quitChan) miner := Miner{ pow: ðchain.EasyPow{}, From 8730dfdcc2e2b40410a57385e4864d15f2f0336b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 17 May 2014 14:07:52 +0200 Subject: [PATCH 0321/1237] Changed how changes are being applied to states --- ethchain/block_chain.go | 4 +- ethchain/block_chain_test.go | 17 +++++- ethchain/state_manager.go | 109 ++++++++++++++++------------------- ethchain/transaction_pool.go | 3 +- ethchain/vm_test.go | 2 +- ethereum.go | 2 +- ethminer/miner.go | 24 ++------ ethpub/pub.go | 2 +- ethutil/config.go | 12 +--- peer.go | 5 +- 10 files changed, 82 insertions(+), 98 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 1848b9ddb4..6c3b15a6a3 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -280,7 +280,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = info.Number - log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -295,7 +295,7 @@ func (bc *BlockChain) setLastBlock() { // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) + ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 30eb622660..4e4bb9dd40 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -18,6 +18,18 @@ type TestManager struct { Blocks []*Block } +func (s *TestManager) IsListening() bool { + return false +} + +func (s *TestManager) IsMining() bool { + return false +} + +func (s *TestManager) PeerCount() int { + return 0 +} + func (s *TestManager) BlockChain() *BlockChain { return s.blockChain } @@ -38,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest") + ethutil.ReadConfig(".ethtest", ethutil.LogStd) db, err := ethdb.NewMemDatabase() if err != nil { @@ -62,8 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - tm.StateManager().PrepareDefault(block) - err := tm.StateManager().ProcessBlock(block, false) + err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 143d9d6471..28570775ba 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -39,20 +39,13 @@ type StateManager struct { // The ethereum manager interface Ethereum EthManager // The managed states - // Processor state. Anything processed will be applied to this - // state - procState *State - // Comparative state it used for comparing and validating end - // results - compState *State // Transiently state. The trans state isn't ever saved, validated and // it could be used for setting account nonces without effecting // the main states. transState *State - // Manifest for keeping changes regarding state objects. See `notify` - // XXX Should we move the manifest to the State object. Benefit: - // * All states can keep their own local changes - //manifest *Manifest + // Mining state. The mining state is used purely and solely by the mining + // operation. + miningState *State } func NewStateManager(ethereum EthManager) *StateManager { @@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager { Pow: &EasyPow{}, Ethereum: ethereum, bc: ethereum.BlockChain(), - //manifest: NewManifest(), } - sm.procState = ethereum.BlockChain().CurrentBlock.State() - sm.transState = sm.procState.Copy() + sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy() + sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy() return sm } -func (sm *StateManager) ProcState() *State { - return sm.procState +func (sm *StateManager) CurrentState() *State { + return sm.Ethereum.BlockChain().CurrentBlock.State() } func (sm *StateManager) TransState() *State { return sm.transState } +func (sm *StateManager) MiningState() *State { + return sm.miningState +} + +func (sm *StateManager) NewMiningState() *State { + sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() + + return sm.miningState +} + func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { - contract := MakeContract(tx, sm.procState) +func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) if contract != nil { - sm.procState.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.Hash()[12:])] = contract.state return contract } @@ -95,7 +97,7 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { // If there's no recipient, it's a contract @@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { if tx.IsContract() { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) if err == nil { - contract := sm.MakeContract(tx) + contract := sm.MakeContract(state, tx) if contract != nil { - sm.EvalScript(contract.Init(), contract, tx, block) + sm.EvalScript(state, contract.Init(), contract, tx, block) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -115,9 +117,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := sm.procState.GetContract(tx.Recipient) + contract := state.GetContract(tx.Recipient) if err == nil && len(contract.Script()) > 0 { - sm.EvalScript(contract.Script(), contract, tx, block) + sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { ethutil.Config.Log.Infoln("[STATE] process:", err) } @@ -125,20 +127,8 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { } } -// The prepare function, prepares the state manager for the next -// "ProcessBlock" action. -func (sm *StateManager) Prepare(processor *State, comparative *State) { - sm.compState = comparative - sm.procState = processor -} - -// Default prepare function -func (sm *StateManager) PrepareDefault(block *Block) { - sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State()) -} - // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -153,7 +143,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. - defer sm.bc.CurrentBlock.Undo() + defer state.Reset() // Check if we have the parent hash, if it isn't known we discard it // Reasons might be catching up or simply an invalid block @@ -162,7 +152,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { } // Process the transactions on to current block - sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -172,19 +162,20 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(block); err != nil { + if err := sm.AccumelateRewards(state, block); err != nil { fmt.Println("[SM] Error accumulating reward", err) return err } - if !sm.compState.Cmp(sm.procState) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) + //if !sm.compState.Cmp(state) { + if !block.State().Cmp(state) { + return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db if sm.CalculateTD(block) { // Sync the current block's state to the database and cancelling out the deferred Undo - sm.procState.Sync() + state.Sync() // Add the block to the chain sm.bc.Add(block) @@ -193,14 +184,14 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) - sm.procState.manifest.Reset() + state.manifest.Reset() } - sm.notifyChanges() + sm.notifyChanges(state) sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) - sm.Ethereum.TxPool().RemoveInvalid(sm.procState) + sm.Ethereum.TxPool().RemoveInvalid(state) } else { fmt.Println("total diff failed") } @@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int { return UncleReward } -func (sm *StateManager) AccumelateRewards(block *Block) error { +func (sm *StateManager) AccumelateRewards(state *State, block *Block) error { // Get the account associated with the coinbase - account := sm.procState.GetAccount(block.Coinbase) + account := state.GetAccount(block.Coinbase) // Reward amount of ether to the coinbase address account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) addr := make([]byte, len(block.Coinbase)) copy(addr, block.Coinbase) - sm.procState.UpdateStateObject(account) + state.UpdateStateObject(account) for _, uncle := range block.Uncles { - uncleAccount := sm.procState.GetAccount(uncle.Coinbase) + uncleAccount := state.GetAccount(uncle.Coinbase) uncleAccount.AddAmount(CalculateUncleReward(uncle)) - sm.procState.UpdateStateObject(uncleAccount) + state.UpdateStateObject(uncleAccount) } return nil @@ -300,8 +291,8 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { - account := sm.procState.GetAccount(tx.Sender()) +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { + account := state.GetAccount(tx.Sender()) err := account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { @@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) - vm := NewVm(sm.procState, sm, RuntimeVars{ + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, PrevHash: block.PrevHash, @@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans closure.Call(vm, tx.Data, nil) // Update the account (refunds) - sm.procState.UpdateStateObject(account) - sm.procState.UpdateStateObject(object) + state.UpdateStateObject(account) + state.UpdateStateObject(object) } -func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.procState.manifest.objectChanges { +func (sm *StateManager) notifyChanges(state *State) { + for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range state.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 21ce8cdc1e..da77f32b3a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -149,7 +149,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) + sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index b919b496f1..5d03ccf0cf 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -12,7 +12,7 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("") + ethutil.ReadConfig("", ethutil.LogStd) db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) diff --git a/ethereum.go b/ethereum.go index 83a74f3021..14418023e1 100644 --- a/ethereum.go +++ b/ethereum.go @@ -235,7 +235,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { s.peers.PushBack(peer) - log.Printf("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers) + ethutil.Config.Log.Infof("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers) } return nil diff --git a/ethminer/miner.go b/ethminer/miner.go index bc29b2588c..233a8bc32f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -53,8 +53,8 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { } func (miner *Miner) Start() { // Prepare inital block - miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) - go func() { miner.listener() }() + //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) + go miner.listener() } func (miner *Miner) listener() { for { @@ -88,7 +88,7 @@ func (miner *Miner) listener() { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { log.Println("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) - miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) + //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } } } @@ -119,31 +119,19 @@ func (miner *Miner) listener() { miner.block.SetUncles(miner.uncles) } - // FIXME @ maranh, first block doesn't need this. Everything after the first block does. - // Please check and fix - miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) // Apply all transactions to the block - miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions()) - miner.ethereum.StateManager().AccumelateRewards(miner.block) + miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions()) + miner.ethereum.StateManager().AccumelateRewards(miner.block.State(), miner.block) // Search the nonce - //log.Println("[MINER] Initialision complete, starting mining") miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) if miner.block.Nonce != nil { - miner.ethereum.StateManager().PrepareDefault(miner.block) - err := miner.ethereum.StateManager().ProcessBlock(miner.block, true) + err := miner.ethereum.StateManager().ProcessBlock(miner.ethereum.StateManager().CurrentState(), miner.block, true) if err != nil { log.Println(err) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) } else { - - /* - // XXX @maranh This is already done in the state manager, why a 2nd time? - if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) { - log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce)) - } - */ miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) diff --git a/ethpub/pub.go b/ethpub/pub.go index daacb9d782..2513f83ed1 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -45,7 +45,7 @@ func (lib *PEthereum) GetKey() *PKey { } func (lib *PEthereum) GetStateObject(address string) *PStateObject { - stateObject := lib.stateManager.ProcState().GetContract(ethutil.FromHex(address)) + stateObject := lib.stateManager.CurrentState().GetContract(ethutil.FromHex(address)) if stateObject != nil { return NewPStateObject(stateObject) } diff --git a/ethutil/config.go b/ethutil/config.go index b4bd9158ec..296b72d9ee 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -9,14 +9,6 @@ import ( "runtime" ) -// Log types available -type LogType byte - -const ( - LogTypeStdIn = 1 - LogTypeFile = 2 -) - // Config struct type config struct { Db Database @@ -34,7 +26,7 @@ var Config *config // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string) *config { +func ReadConfig(base string, logTypes LoggerType) *config { if Config == nil { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) @@ -51,7 +43,7 @@ func ReadConfig(base string) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} - Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) + Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } diff --git a/peer.go b/peer.go index 4093a4902b..45ff0a795a 100644 --- a/peer.go +++ b/peer.go @@ -331,8 +331,9 @@ func (p *Peer) HandleInbound() { for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) - p.ethereum.StateManager().PrepareDefault(block) - err = p.ethereum.StateManager().ProcessBlock(block, false) + //p.ethereum.StateManager().PrepareDefault(block) + state := p.ethereum.StateManager().CurrentState() + err = p.ethereum.StateManager().ProcessBlock(state, block, false) if err != nil { if ethutil.Config.Debug { From bd48690f63d07d9a0568f0d8092006ebaa12af5f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 11:25:27 +0200 Subject: [PATCH 0322/1237] Testing different mining state --- ethchain/dagger.go | 4 ++-- ethchain/transaction_pool.go | 2 +- ethminer/miner.go | 19 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 9d2df40694..18e53d3a8c 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - log.Println("[POW] Received reactor event; breaking out.") + ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - log.Println("[POW] Hashing @", int64(hashes), "khash") + ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index da77f32b3a..796ec7c9a6 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -131,7 +131,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract block.state.UpdateStateObject(sender) - log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) // Notify all subscribers pool.Ethereum.Reactor().Post("newTx:post", tx) diff --git a/ethminer/miner.go b/ethminer/miner.go index 233a8bc32f..294bc7b3d2 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -5,7 +5,6 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" ) type Miner struct { @@ -61,10 +60,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - log.Println("[MINER] Got new block via Reactor") + ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - log.Println("[MINER] New top block found resetting state") + ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -86,7 +85,7 @@ func (miner *Miner) listener() { } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { - log.Println("[MINER] Adding uncle block") + ethutil.Config.Log.Infoln("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } @@ -94,7 +93,7 @@ func (miner *Miner) listener() { } if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { - //log.Println("[MINER] Got new transaction from Reactor", tx) + //log.Infoln("[MINER] Got new transaction from Reactor", tx) found := false for _, ctx := range miner.txs { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { @@ -103,16 +102,16 @@ func (miner *Miner) listener() { } if found == false { - //log.Println("[MINER] We did not know about this transaction, adding") + //log.Infoln("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block.SetTransactions(miner.txs) } else { - //log.Println("[MINER] We already had this transaction, ignoring") + //log.Infoln("[MINER] We already had this transaction, ignoring") } } default: - log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions") + ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions") // Apply uncles if len(miner.uncles) > 0 { @@ -128,12 +127,12 @@ func (miner *Miner) listener() { if miner.block.Nonce != nil { err := miner.ethereum.StateManager().ProcessBlock(miner.ethereum.StateManager().CurrentState(), miner.block, true) if err != nil { - log.Println(err) + ethutil.Config.Log.Infoln(err) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) } else { miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) - log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) + ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) From b8034f4d9ed7eea29a219a2d894ae22041a906a7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 12:14:04 +0200 Subject: [PATCH 0323/1237] Increment nonce in the public api --- ethchain/vm.go | 1 - ethpub/pub.go | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 584c666112..6579830ecb 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } - fmt.Println(closure.Script) for { // The base for all big integer arithmetic diff --git a/ethpub/pub.go b/ethpub/pub.go index 2513f83ed1..8c9a0666c0 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -162,6 +162,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) //acc := lib.stateManager.GetAddrState(keyPair.Address()) tx.Nonce = acc.Nonce + acc.Nonce += 1 lib.stateManager.TransState().SetStateObject(acc) tx.Sign(keyPair.PrivateKey) From a2fb265563a3a6eb80efc5720bb0c6f3fec6f397 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 19 May 2014 17:02:16 +0200 Subject: [PATCH 0324/1237] Added a fatal method --- ethutil/config.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 296b72d9ee..fd590fbdb8 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -130,7 +130,6 @@ func (log *Logger) Infoln(v ...interface{}) { return } - //fmt.Println(len(log.logSys)) for _, logger := range log.logSys { logger.Println(v...) } @@ -145,3 +144,15 @@ func (log *Logger) Infof(format string, v ...interface{}) { logger.Printf(format, v...) } } + +func (log *Logger) Fatal(v ...interface{}) { + if log.logLevel > LogLevelInfo { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } + + os.Exit(1) +} From fd19142c0db3d2b6651989f5389944f3e211d84f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 11:19:07 +0200 Subject: [PATCH 0325/1237] No longer store script directly in the state tree --- ethchain/block.go | 2 +- ethchain/block_chain.go | 2 +- ethchain/state.go | 49 +++++++++++------------------------ ethchain/state_manager.go | 5 ++-- ethchain/state_object.go | 21 ++++++++------- ethchain/state_object_test.go | 25 ++++++++++++++++++ ethchain/transaction.go | 2 +- ethchain/vm.go | 2 +- ethpub/pub.go | 3 +-- ethpub/types.go | 9 +++++++ peer.go | 2 +- 11 files changed, 70 insertions(+), 52 deletions(-) create mode 100644 ethchain/state_object_test.go diff --git a/ethchain/block.go b/ethchain/block.go index aac50ccb14..ca84dc19cf 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -122,7 +122,7 @@ func (block *Block) Transactions() []*Transaction { } func (block *Block) PayFee(addr []byte, fee *big.Int) bool { - contract := block.state.GetContract(addr) + contract := block.state.GetStateObject(addr) // If we can't pay the fee return if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { fmt.Println("Contract has insufficient funds", contract.Amount, fee) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6c3b15a6a3..99e17727c3 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,7 +260,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) diff --git a/ethchain/state.go b/ethchain/state.go index d02584d679..63c4a32a63 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -49,28 +49,6 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -// XXX Deprecated -func (s *State) GetContract(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - // build contract - contract := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedState := s.states[string(addr)] - if cachedState != nil { - contract.state = cachedState - } else { - // If it isn't cached, cache the state - s.states[string(addr)] = contract.state - } - - return contract -} - func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -91,6 +69,21 @@ func (s *State) GetStateObject(addr []byte) *StateObject { return stateObject } +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + func (s *State) SetStateObject(stateObject *StateObject) { s.states[string(stateObject.address)] = stateObject.state @@ -116,18 +109,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil { - s.states[string(addr)] = object.state - } - - s.trie.Update(string(addr), string(object.RlpEncode())) - s.manifest.AddObjectChange(object) -} - func (s *State) Put(key, object []byte) { s.trie.Update(string(key), string(object)) } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 28570775ba..098263e8ad 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -87,7 +87,7 @@ func (sm *StateManager) BlockChain() *BlockChain { func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { - state.states[string(tx.Hash()[12:])] = contract.state + state.states[string(tx.CreationAddress())] = contract.state return contract } @@ -117,7 +117,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetContract(tx.Recipient) + contract := state.GetStateObject(tx.Recipient) + ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) if err == nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7a11a11522..cb6211ea61 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -10,8 +10,9 @@ type StateObject struct { // Address of the object address []byte // Shared attributes - Amount *big.Int - Nonce uint64 + Amount *big.Int + ScriptHash []byte + Nonce uint64 // Contract related attributes state *State script []byte @@ -22,12 +23,10 @@ type StateObject struct { func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient if tx.IsContract() { - // FIXME - addr := tx.Hash()[12:] + addr := tx.CreationAddress() value := tx.Value - contract := NewContract(addr, value, []byte("")) - state.UpdateStateObject(contract) + contract := NewContract(addr, value, ZeroHash256) contract.script = tx.Data contract.initScript = tx.Init @@ -146,9 +145,10 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = nil + root = ZeroHash256 } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script}) + + return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { @@ -157,7 +157,10 @@ func (c *StateObject) RlpDecode(data []byte) { c.Amount = decoder.Get(0).BigInt() c.Nonce = decoder.Get(1).Uint() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) - c.script = decoder.Get(3).Bytes() + + c.ScriptHash = decoder.Get(3).Bytes() + + c.script, _ = ethutil.Config.Db.Get(c.ScriptHash) } // Storage change object. Used by the manifest for notifying changes to diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go new file mode 100644 index 0000000000..1db01a5373 --- /dev/null +++ b/ethchain/state_object_test.go @@ -0,0 +1,25 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSync(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + + contract.script = []byte{42} + + state.UpdateStateObject(contract) + state.Sync() + + object := state.GetStateObject([]byte("aa")) + fmt.Printf("%x\n", object.Script()) +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index e93e610be5..8ea4704cb6 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -60,7 +60,7 @@ func (tx *Transaction) IsContract() bool { } func (tx *Transaction) CreationAddress() []byte { - return tx.Hash()[12:] + return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6579830ecb..e732d22a42 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -471,7 +471,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) // Fetch the contract which will serve as the closure body - contract := vm.state.GetContract(addr.Bytes()) + contract := vm.state.GetStateObject(addr.Bytes()) if contract != nil { // Prepay for the gas diff --git a/ethpub/pub.go b/ethpub/pub.go index 8c9a0666c0..fb1018d471 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -45,7 +45,7 @@ func (lib *PEthereum) GetKey() *PKey { } func (lib *PEthereum) GetStateObject(address string) *PStateObject { - stateObject := lib.stateManager.CurrentState().GetContract(ethutil.FromHex(address)) + stateObject := lib.stateManager.CurrentState().GetStateObject(ethutil.FromHex(address)) if stateObject != nil { return NewPStateObject(stateObject) } @@ -160,7 +160,6 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in } acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) - //acc := lib.stateManager.GetAddrState(keyPair.Address()) tx.Nonce = acc.Nonce acc.Nonce += 1 lib.stateManager.TransState().SetStateObject(acc) diff --git a/ethpub/types.go b/ethpub/types.go index c902afc564..75115f4e87 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -2,6 +2,7 @@ package ethpub import ( "encoding/hex" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" ) @@ -112,6 +113,14 @@ func (c *PStateObject) IsContract() bool { return false } +func (c *PStateObject) Script() string { + if c.object != nil { + return ethutil.Hex(c.object.Script()) + } + + return "" +} + type PStorageState struct { StateAddress string Address string diff --git a/peer.go b/peer.go index 45ff0a795a..f84b4d472a 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 8 + ProtocolVersion = 9 ) type DiscReason byte From 12f30e6220354c4a8b08ecf41bb53444143f3660 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 11:50:34 +0200 Subject: [PATCH 0326/1237] Refactored a lot of the chain catchup/reorg. --- ethchain/block_chain.go | 2 +- ethereum.go | 4 +- peer.go | 131 +++++++++++++++++++++++----------------- 3 files changed, 79 insertions(+), 58 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6c3b15a6a3..2ce0f90a6b 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -127,7 +127,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte log.Println("[CHAIN] We have found the common parent block, breaking") break } - log.Println("Checking incoming blocks:") chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } @@ -182,6 +181,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { // XXX Why are we resetting? This is the block chain, it has nothing to do with states //bc.Ethereum.StateManager().PrepareDefault(returnTo) + // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { return err diff --git a/ethereum.go b/ethereum.go index 14418023e1..3a7202d535 100644 --- a/ethereum.go +++ b/ethereum.go @@ -222,7 +222,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { if phost == chost { alreadyConnected = true - ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost) + //ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost) return } }) @@ -235,7 +235,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { s.peers.PushBack(peer) - ethutil.Config.Log.Infof("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers) + ethutil.Config.Log.Infof("[SERV] Adding peer (%s) %d / %d\n", addr, s.peers.Len(), s.MaxPeers) } return nil diff --git a/peer.go b/peer.go index 45ff0a795a..879361b2b4 100644 --- a/peer.go +++ b/peer.go @@ -127,6 +127,7 @@ type Peer struct { // Indicated whether the node is catching up or not catchingUp bool + diverted bool blocksRequested int Version string @@ -190,7 +191,6 @@ func (p *Peer) QueueMessage(msg *ethwire.Msg) { if atomic.LoadInt32(&p.connected) != 1 { return } - p.outputQueue <- msg } @@ -268,7 +268,6 @@ func (p *Peer) HandleInbound() { for atomic.LoadInt32(&p.disconnect) == 0 { // HMM? time.Sleep(500 * time.Millisecond) - // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { @@ -300,32 +299,36 @@ func (p *Peer) HandleInbound() { var err error // Make sure we are actually receiving anything - if msg.Data.Len()-1 > 1 && p.catchingUp { + if msg.Data.Len()-1 > 1 && p.diverted { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) - if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { - // If we can't find a common ancenstor we need to request more blocks. - // FIXME: At one point this won't scale anymore since we are not asking for an offset - // we just keep increasing the amount of blocks. - //fmt.Println("[PEER] No common ancestor found, requesting more blocks.") - p.blocksRequested = p.blocksRequested * 2 - p.catchingUp = false - p.SyncWithBlocks() - } - + ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) // Do we have this block on our chain? If so we can continue if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { // We don't have this block, but we do have a block with the same prevHash, diversion time! if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { - if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { - return + p.diverted = false + if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { + p.SyncWithPeerToLastKnown() } + break } } } + if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { + // If we can't find a common ancenstor we need to request more blocks. + // FIXME: At one point this won't scale anymore since we are not asking for an offset + // we just keep increasing the amount of blocks. + p.blocksRequested = p.blocksRequested * 2 + + ethutil.Config.Log.Infof("[PEER] No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) + p.catchingUp = false + p.FindCommonParentBlock() + break + } } for i := msg.Data.Len() - 1; i >= 0; i-- { @@ -346,23 +349,28 @@ func (p *Peer) HandleInbound() { } } + if msg.Data.Len() == 0 { + // Set catching up to false if + // the peer has nothing left to give + p.catchingUp = false + } + if err != nil { // If the parent is unknown try to catch up with this peer if ethchain.IsParentErr(err) { - ethutil.Config.Log.Infoln("Attempting to catch up") + ethutil.Config.Log.Infoln("Attempting to catch up since we don't know the parent") p.catchingUp = false p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } else if ethchain.IsValidationErr(err) { - fmt.Println(err) + fmt.Println("Err:", err) p.catchingUp = false } } else { - // XXX Do we want to catch up if there were errors? // If we're catching up, try to catch up further. if p.catchingUp && msg.Data.Len() > 1 { - if ethutil.Config.Debug && lastBlock != nil { + if lastBlock != nil { blockInfo := lastBlock.BlockInfo() - ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + ethutil.Config.Log.Debugf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false @@ -372,11 +380,6 @@ func (p *Peer) HandleInbound() { } } - if msg.Data.Len() == 0 { - // Set catching up to false if - // the peer has nothing left to give - p.catchingUp = false - } case ethwire.MsgTxTy: // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and @@ -444,7 +447,7 @@ func (p *Peer) HandleInbound() { } } else { - ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") + //ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain lastHash := msg.Data.Get(l - 1) @@ -452,8 +455,14 @@ func (p *Peer) HandleInbound() { p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) } case ethwire.MsgNotInChainTy: - ethutil.Config.Log.Debugf("Not in chain %x\n", msg.Data) - // TODO + ethutil.Config.Log.Debugf("Not in chain: %x\n", msg.Data.Get(0).Bytes()) + if p.diverted == true { + // If were already looking for a common parent and we get here again we need to go deeper + p.blocksRequested = p.blocksRequested * 2 + } + p.diverted = true + p.catchingUp = false + p.FindCommonParentBlock() case ethwire.MsgGetTxsTy: // Get the current transactions of the pool txs := p.ethereum.TxPool().CurrentTransactions() @@ -471,7 +480,6 @@ func (p *Peer) HandleInbound() { } } } - p.Stop() } @@ -581,14 +589,18 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { } - // Catch up with the connected peer - p.SyncWithBlocks() - // Set the peer's caps p.caps = Caps(c.Get(3).Byte()) // Get a reference to the peers version p.Version = c.Get(2).Str() + // Catch up with the connected peer + if !p.ethereum.IsUpToDate() { + ethutil.Config.Log.Debugln("Already syncing up with a peer; sleeping") + time.Sleep(10 * time.Second) + } + p.SyncWithPeerToLastKnown() + ethutil.Config.Log.Debugln("[PEER]", p) } @@ -609,38 +621,47 @@ func (p *Peer) String() string { return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) } -func (p *Peer) SyncWithBlocks() { - if !p.catchingUp { - p.catchingUp = true - // FIXME: THIS SHOULD NOT BE NEEDED - if p.blocksRequested == 0 { - p.blocksRequested = 10 - } - blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested) - - var hashes []interface{} - for _, block := range blocks { - hashes = append(hashes, block.Hash()) - } - - msgInfo := append(hashes, uint64(50)) - - msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) - p.QueueMessage(msg) - } +func (p *Peer) SyncWithPeerToLastKnown() { + p.catchingUp = false + p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } +func (p *Peer) FindCommonParentBlock() { + if p.catchingUp { + return + } + + p.catchingUp = true + if p.blocksRequested == 0 { + p.blocksRequested = 20 + } + blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested) + + var hashes []interface{} + for _, block := range blocks { + hashes = append(hashes, block.Hash()) + } + + msgInfo := append(hashes, uint64(len(hashes))) + + ethutil.Config.Log.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) + + msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) + p.QueueMessage(msg) +} func (p *Peer) CatchupWithPeer(blockHash []byte) { if !p.catchingUp { + // Make sure nobody else is catching up when you want to do this p.catchingUp = true msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) + ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) - msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) - p.QueueMessage(msg) - ethutil.Config.Log.Debugln("Requested transactions") + /* + msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) + p.QueueMessage(msg) + */ } } From 2450398862e8ac55b39dd88a3af169985e1727f3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 12:19:21 +0200 Subject: [PATCH 0327/1237] Added Maran to premine --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 99e17727c3..9926354bde 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -260,9 +260,8 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - //"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran } { - //log.Println("2^200 Wei to", addr) codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) account.Amount = ethutil.BigPow(2, 200) From fafdd21e4fb18c9714c4f784d443e9592ec3ff69 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 12:23:49 +0200 Subject: [PATCH 0328/1237] unused --- ethpub/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethpub/types.go b/ethpub/types.go index 75115f4e87..5d3bfcaaad 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -2,7 +2,6 @@ package ethpub import ( "encoding/hex" - "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" ) From 530ab6b8fc9e7ea2b784dbd3f16d0272d227f6d6 Mon Sep 17 00:00:00 2001 From: Nick Savers Date: Tue, 20 May 2014 13:02:37 +0200 Subject: [PATCH 0329/1237] Re-arranged transaction RLP encoding... According to latest Yellow Paper specs and conform other clients https://github.com/ethereum/latexpaper/commit/4794642e51ac1884e5e1af8a18ebc83aca115d64 --- ethchain/transaction.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 8ea4704cb6..c18ff7c53d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,10 +109,10 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] -// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] +// [ NONCE, GASPRICE, GAS, TO, VALUE, DATA, V, R, S ] +// [ NONCE, GASPRICE, GAS, 0, VALUE, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -135,10 +135,10 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Value = decoder.Get(1).BigInt() - tx.GasPrice = decoder.Get(2).BigInt() - tx.Gas = decoder.Get(3).BigInt() - tx.Recipient = decoder.Get(4).Bytes() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() // If the list is of length 10 it's a contract creation tx From 378815ee62b21cec60aceeafc7bc8a2a479290b5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:06:47 +0200 Subject: [PATCH 0330/1237] Rearranged according to YP --- ethchain/transaction.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 8ea4704cb6..bd7a0e424c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,10 +109,8 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ] -// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ] func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} if tx.contractCreation { data = append(data, tx.Init) @@ -135,10 +133,10 @@ func (tx *Transaction) RlpDecode(data []byte) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Nonce = decoder.Get(0).Uint() - tx.Value = decoder.Get(1).BigInt() - tx.GasPrice = decoder.Get(2).BigInt() - tx.Gas = decoder.Get(3).BigInt() - tx.Recipient = decoder.Get(4).Bytes() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() // If the list is of length 10 it's a contract creation tx From 45b810450fc75ef47964b1b53197114d1bf6db3d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:09:44 +0200 Subject: [PATCH 0331/1237] ... --- ethchain/transaction.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index a36286e86e..bd7a0e424c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -109,11 +109,6 @@ func (tx *Transaction) Sign(privk []byte) error { return nil } -<<<<<<< HEAD -======= -// [ NONCE, GASPRICE, GAS, TO, VALUE, DATA, V, R, S ] -// [ NONCE, GASPRICE, GAS, 0, VALUE, CODE, INIT, V, R, S ] ->>>>>>> 38b4dc2cdf23380532a25240760273dd07b9dff6 func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} From 6a31d55b2e2d95dd64e3d56b0c12e9ffb7c1c373 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:29:21 +0200 Subject: [PATCH 0332/1237] added roman --- ethchain/block_chain.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 457aed714f..eb25bd3f40 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -261,6 +261,7 @@ func AddTestNetFunds(block *Block) { "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman } { codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) From b4e156e1d723fe53eff238a634f6e83cb9d80492 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 13:29:46 +0200 Subject: [PATCH 0333/1237] Up protocol version --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 4a390f015c..993f48d20b 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 9 + ProtocolVersion = 10 ) type DiscReason byte From 7d3e99a2abcef6011714a7e6e515aa8e2bc738cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 14:29:52 +0200 Subject: [PATCH 0334/1237] Fixed genesis and block data --- ethchain/block.go | 69 ++++++++++++++++++++++++++++++++++++++++----- ethchain/genesis.go | 17 +++++++---- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index ca84dc19cf..beb2bc14ca 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -40,6 +40,14 @@ type Block struct { Difficulty *big.Int // Creation time Time int64 + // The block number + Number *big.Int + // Minimum Gas Price + MinGasPrice *big.Int + // Gas limit + GasLimit *big.Int + // Gas used + GasUsed *big.Int // Extra data Extra string // Block Nonce for verification @@ -233,9 +241,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() - block.Time = int64(header.Get(6).BigInt().Uint64()) - block.Extra = header.Get(7).Str() - block.Nonce = header.Get(8).Bytes() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).Bytes() block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their @@ -270,16 +282,51 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() - block.Time = int64(header.Get(6).BigInt().Uint64()) - block.Extra = header.Get(7).Str() - block.Nonce = header.Get(8).Bytes() + block.Number = header.Get(6).BigInt() + block.MinGasPrice = header.Get(7).BigInt() + block.GasLimit = header.Get(8).BigInt() + block.GasUsed = header.Get(9).BigInt() + block.Time = int64(header.Get(10).BigInt().Uint64()) + block.Extra = header.Get(11).Str() + block.Nonce = header.Get(12).Bytes() return block } func (block *Block) String() string { - return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) + //return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) + return fmt.Sprintf(` + Block(%x): + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, + block.Hash(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.trie.Root, + block.TxSha, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce) } + func (block *Block) GetRoot() interface{} { return block.state.trie.Root } @@ -299,6 +346,14 @@ func (block *Block) header() []interface{} { block.TxSha, // Current block Difficulty block.Difficulty, + // The block number + block.Number, + // Block minimum gas price + block.MinGasPrice, + // Block upper gas bound + block.GasLimit, + // Block gas used + block.GasUsed, // Time the block was found? block.Time, // Extra data diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 935978a69e..7e145ef533 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -15,7 +15,6 @@ var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) - //"", ZeroHash256, // Sha of uncles ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), @@ -23,15 +22,23 @@ var GenesisHeader = []interface{}{ ZeroHash160, // Root state "", - // Sha of transactions //EmptyShaList, - ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + ZeroHash256, + //ethutil.Sha3Bin(ethutil.Encode(ZeroHash256)), // Difficulty ethutil.BigPow(2, 22), + // Number + ethutil.Big0, + // Block minimum gas price + ethutil.Big0, + // Block upper gas bound + big.NewInt(1000000), + // Block gas used + ethutil.Big0, // Time - int64(0), + ethutil.Big0, // Extra - "", + nil, // Nonce ethutil.Sha3Bin(big.NewInt(42).Bytes()), } From f5d441473499428964b75924845cf0c7bcaaa5ca Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 14:41:35 +0200 Subject: [PATCH 0335/1237] Fix notification when processing block that didn't have this client as origin --- ethchain/state_manager.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 098263e8ad..c7c6857d83 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -180,6 +180,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) // Add the block to the chain sm.bc.Add(block) + sm.notifyChanges(state) ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { @@ -188,8 +189,6 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) state.manifest.Reset() } - sm.notifyChanges(state) - sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.TxPool().RemoveInvalid(state) From 31e44c2ab959124cbcf2de45385373b9898727bc Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 20 May 2014 14:53:34 +0200 Subject: [PATCH 0336/1237] Change shorthands --- ethutil/common.go | 26 +++++++++++++------------- ethutil/common_test.go | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ethutil/common.go b/ethutil/common.go index 983ea5d1bc..771dfc723c 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -7,13 +7,13 @@ import ( // The different number of units var ( - Ether = BigPow(10, 18) - Finney = BigPow(10, 15) - Szabo = BigPow(10, 12) - Vita = BigPow(10, 9) - Turing = BigPow(10, 6) - Eins = BigPow(10, 3) - Wei = big.NewInt(1) + Ether = BigPow(10, 18) + Finney = BigPow(10, 15) + Szabo = BigPow(10, 12) + Shannon = BigPow(10, 9) + Babbage = BigPow(10, 6) + Ada = BigPow(10, 3) + Wei = big.NewInt(1) ) // Currency to string @@ -27,12 +27,12 @@ func CurrencyToString(num *big.Int) string { return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) case num.Cmp(Szabo) >= 0: return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) - case num.Cmp(Vita) >= 0: - return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita)) - case num.Cmp(Turing) >= 0: - return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) - case num.Cmp(Eins) >= 0: - return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins)) + case num.Cmp(Shannon) >= 0: + return fmt.Sprintf("%v Shannon", new(big.Int).Div(num, Shannon)) + case num.Cmp(Babbage) >= 0: + return fmt.Sprintf("%v Babbage", new(big.Int).Div(num, Babbage)) + case num.Cmp(Ada) >= 0: + return fmt.Sprintf("%v Ada", new(big.Int).Div(num, Ada)) } return fmt.Sprintf("%v Wei", num) diff --git a/ethutil/common_test.go b/ethutil/common_test.go index 8031f08ab5..2667eaf3af 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -26,15 +26,15 @@ func TestCommon(t *testing.T) { t.Error("Got", szabo) } - if vito != "10 Vita" { + if vito != "10 Shannon" { t.Error("Got", vito) } - if turing != "10 Turing" { + if turing != "10 Babbage" { t.Error("Got", turing) } - if eins != "10 Eins" { + if eins != "10 Ada" { t.Error("Got", eins) } From 2bd377a3de54652923558b63cc8756531269e36e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 15:02:46 +0200 Subject: [PATCH 0337/1237] Changed transaction hash for poc 5 --- ethchain/block.go | 76 ++++++++++++++++++++++------------------- ethchain/block_chain.go | 16 +++++++++ ethchain/genesis.go | 3 +- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index beb2bc14ca..c6c2c1226c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" + "strconv" "time" ) @@ -214,7 +215,12 @@ func (block *Block) SetUncles(uncles []*Block) { func (block *Block) SetTransactions(txs []*Transaction) { block.transactions = txs - block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) + trie := ethutil.NewTrie(ethutil.Config.Db, "") + for i, tx := range txs { + trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) + } + + block.TxSha = trie.Root.([]byte) } func (block *Block) Value() *ethutil.Value { @@ -293,45 +299,10 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { return block } -func (block *Block) String() string { - //return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions)) - return fmt.Sprintf(` - Block(%x): - PrevHash: %x - UncleSha: %x - Coinbase: %x - Root: %x - TxSha: %x - Difficulty: %v - Number: %v - MinGas: %v - MaxLimit: %v - GasUsed: %v - Time: %v - Extra: %v - Nonce: %x -`, - block.Hash(), - block.PrevHash, - block.UncleSha, - block.Coinbase, - block.state.trie.Root, - block.TxSha, - block.Difficulty, - block.Number, - block.MinGasPrice, - block.GasLimit, - block.GasUsed, - block.Time, - block.Extra, - block.Nonce) -} - func (block *Block) GetRoot() interface{} { return block.state.trie.Root } -//////////// UNEXPORTED ///////////////// func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -362,3 +333,36 @@ func (block *Block) header() []interface{} { block.Nonce, } } + +func (block *Block) String() string { + return fmt.Sprintf(` + BLOCK(%x): + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x +`, + block.Hash(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.state.trie.Root, + block.TxSha, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce) +} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index eb25bd3f40..2865336fbc 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -70,6 +70,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { diff.Mul(diff, mul) diff.Add(diff, bc.CurrentBlock.Difficulty) block.Difficulty = diff + + block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) + + // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + + block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) } return block diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 7e145ef533..b8f9f865a3 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -22,9 +22,8 @@ var GenesisHeader = []interface{}{ ZeroHash160, // Root state "", - //EmptyShaList, + // tx sha ZeroHash256, - //ethutil.Sha3Bin(ethutil.Encode(ZeroHash256)), // Difficulty ethutil.BigPow(2, 22), // Number From c37b3cef7dc465832761b1da6761eeaa47e368d1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 17:08:53 +0200 Subject: [PATCH 0338/1237] Bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2627bc85e2..f6bcaad288 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC6". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC7". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index fd590fbdb8..abe86babe3 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -42,7 +42,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"} Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From ad51c85e5d67ca2e64e95786e79d062c4467b4c1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 19:19:53 +0200 Subject: [PATCH 0339/1237] Fixed crash --- ethchain/block.go | 5 ++++- peer.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index c6c2c1226c..bdb2432862 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -99,6 +99,9 @@ func CreateBlock(root interface{}, Time: time.Now().Unix(), Extra: extra, UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), contractStates: make(map[string]*ethutil.Trie), } block.SetTransactions(txes) @@ -220,7 +223,7 @@ func (block *Block) SetTransactions(txs []*Transaction) { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } - block.TxSha = trie.Root.([]byte) + block.TxSha = []byte(trie.Root.(string)) } func (block *Block) Value() *ethutil.Value { diff --git a/peer.go b/peer.go index 993f48d20b..b2e751b44a 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 10 + ProtocolVersion = 11 ) type DiscReason byte From 3b38df085ebebd68f1bf76c11c8b87ae75f29fe2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 22:04:47 +0200 Subject: [PATCH 0340/1237] Fixed casting issue --- ethchain/block.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ethchain/block.go b/ethchain/block.go index bdb2432862..24ff5a32f1 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -223,7 +223,15 @@ func (block *Block) SetTransactions(txs []*Transaction) { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } - block.TxSha = []byte(trie.Root.(string)) + switch trie.Root.(type) { + case string: + block.TxSha = []byte(trie.Root.(string)) + case []byte: + block.TxSha = trie.Root.([]byte) + default: + panic(fmt.Sprintf("invalid root type %T", trie.Root)) + } + } func (block *Block) Value() *ethutil.Value { From 64701e388c3f603a4fad5b6ff45ba2633b3f645e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 22:43:59 +0200 Subject: [PATCH 0341/1237] Fixed state issue --- ethchain/state.go | 3 --- ethpub/types.go | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 63c4a32a63..db715f1cb1 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -61,9 +61,6 @@ func (s *State) GetStateObject(addr []byte) *StateObject { cachedStateObject := s.states[string(addr)] if cachedStateObject != nil { stateObject.state = cachedStateObject - } else { - // If it isn't cached, cache the state - s.states[string(addr)] = stateObject.state } return stateObject diff --git a/ethpub/types.go b/ethpub/types.go index 5d3bfcaaad..77cca78b9b 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -104,6 +104,14 @@ func (c *PStateObject) Nonce() int { return 0 } +func (c *PStateObject) Root() string { + if c.object != nil { + return ethutil.Hex(ethutil.NewValue(c.object.State().Root()).Bytes()) + } + + return "" +} + func (c *PStateObject) IsContract() bool { if c.object != nil { return len(c.object.Script()) > 0 From 6ef2832083ad9d1e3cb1895f1aa836517dbf042d Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 20 May 2014 22:45:01 +0200 Subject: [PATCH 0342/1237] Upped prot --- peer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peer.go b/peer.go index b2e751b44a..690281da9f 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 11 + ProtocolVersion = 12 ) type DiscReason byte From 5ceb1620e93e1999c6f72e6164c7c65af63244ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 00:17:50 +0200 Subject: [PATCH 0343/1237] Fixed couple issues * (imp) Lock / RLock tries * (fix) stack --- ethchain/stack.go | 2 +- ethchain/state_manager.go | 46 +++++++++++++++++++---------------- ethchain/state_object_test.go | 29 +++++++++++++++++++++- ethchain/vm.go | 2 ++ ethchain/vm_test.go | 9 ++++--- ethminer/miner.go | 1 + ethutil/trie.go | 8 ++++++ 7 files changed, 71 insertions(+), 26 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index e9297b3246..bf34e6ea9f 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -65,7 +65,7 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { } func (st *Stack) Push(d *big.Int) { - st.data = append(st.data, d) + st.data = append(st.data, new(big.Int).Set(d)) } func (st *Stack) Get(amount *big.Int) []*big.Int { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c7c6857d83..27eaa5e601 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -100,30 +100,34 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - if err == nil { - contract := sm.MakeContract(state, tx) - if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) - } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") - } + sm.ApplyTransaction(state, block, tx) + } +} + +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) { + // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. + if tx.IsContract() { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + if err == nil { + contract := sm.MakeContract(state, tx) + if contract != nil { + sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - ethutil.Config.Log.Infoln("[STATE] contract create:", err) + ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetStateObject(tx.Recipient) - ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) - if err == nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) - } else if err != nil { - ethutil.Config.Log.Infoln("[STATE] process:", err) - } + ethutil.Config.Log.Infoln("[STATE] contract create:", err) + } + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + contract := state.GetStateObject(tx.Recipient) + ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) + if err == nil && len(contract.Script()) > 0 { + sm.EvalScript(state, contract.Script(), contract, tx, block) + } else if err != nil { + ethutil.Config.Log.Infoln("[STATE] process:", err) } } } diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index 1db01a5373..e955acc56b 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" + "math/big" "testing" ) @@ -21,5 +22,31 @@ func TestSync(t *testing.T) { state.Sync() object := state.GetStateObject([]byte("aa")) - fmt.Printf("%x\n", object.Script()) + if len(object.Script()) == 0 { + t.Fail() + } +} + +func TestObjectGet(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + ethutil.Config.Db = db + + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(contract) + + contract = state.GetStateObject([]byte("aa")) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello")) + o := contract.GetMem(big.NewInt(0)) + fmt.Println(o) + + state.UpdateStateObject(contract) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello00")) + + contract = state.GetStateObject([]byte("aa")) + o = contract.GetMem(big.NewInt(0)) + fmt.Println("after", o) } diff --git a/ethchain/vm.go b/ethchain/vm.go index e732d22a42..9be38fcc17 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -390,10 +390,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) case oSSTORE: require(2) val, loc := stack.Popn() + //fmt.Println("storing", val, "@", loc) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5d03ccf0cf..2ec70536aa 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,5 +1,6 @@ package ethchain +/* import ( _ "bytes" "fmt" @@ -23,10 +24,11 @@ func TestRun4(t *testing.T) { if a > b { int32 c = this.caller() } - Exit() + exit() `), false) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - addr := tx.Hash()[12:] + tx.Sign(ContractAddr) + addr := tx.CreationAddress() contract := MakeContract(tx, state) state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) @@ -34,7 +36,7 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store if this.store[1000] == 0 { - this.store[1000] = 10^20 + this.store[1000] = 10**20 } @@ -93,3 +95,4 @@ func TestRun4(t *testing.T) { } fmt.Println("account.Amount =", account.Amount) } +*/ diff --git a/ethminer/miner.go b/ethminer/miner.go index 294bc7b3d2..26b28d82ff 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -102,6 +102,7 @@ func (miner *Miner) listener() { } if found == false { + miner.block.Undo() //log.Infoln("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) diff --git a/ethutil/trie.go b/ethutil/trie.go index 4d088ccff2..1c7bd478d5 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -3,6 +3,7 @@ package ethutil import ( "fmt" "reflect" + "sync" ) // TODO @@ -113,6 +114,7 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { + mut sync.RWMutex prevRoot interface{} Root interface{} //db Database @@ -157,12 +159,18 @@ func (t *Trie) Cache() *Cache { * Public (query) interface functions */ func (t *Trie) Update(key string, value string) { + t.mut.Lock() + defer t.mut.Unlock() + k := CompactHexDecode(key) t.Root = t.UpdateState(t.Root, k, value) } func (t *Trie) Get(key string) string { + t.mut.RLock() + defer t.mut.RUnlock() + k := CompactHexDecode(key) c := NewValue(t.GetState(t.Root, k)) From 3c35ba7c31423da644c5fb73030af4673cff90ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 01:12:28 +0200 Subject: [PATCH 0344/1237] Fixed state overwriting issue --- ethchain/state.go | 10 +++------- ethchain/state_object.go | 1 + ethchain/vm.go | 6 +++--- ethpub/pub.go | 2 +- ethutil/trie.go | 12 ++++++++++++ 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index db715f1cb1..6ec6916f46 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -60,6 +60,7 @@ func (s *State) GetStateObject(addr []byte) *StateObject { // Check if there's a cached state for this contract cachedStateObject := s.states[string(addr)] if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) stateObject.state = cachedStateObject } @@ -70,8 +71,9 @@ func (s *State) GetStateObject(addr []byte) *StateObject { func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() - if object.state != nil { + if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state + //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -81,12 +83,6 @@ func (s *State) UpdateStateObject(object *StateObject) { s.manifest.AddObjectChange(object) } -func (s *State) SetStateObject(stateObject *StateObject) { - s.states[string(stateObject.address)] = stateObject.state - - s.UpdateStateObject(stateObject) -} - func (s *State) GetAccount(addr []byte) (account *StateObject) { data := s.trie.Get(string(addr)) if data == "" { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index cb6211ea61..8e059f3344 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -78,6 +78,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + //fmt.Println("storing", val.BigInt(), "@", num) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index e732d22a42..c4304e5ac1 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -448,7 +448,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigD(addr)) - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) } case oCALL: require(7) @@ -497,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigTrue) } - vm.state.SetStateObject(contract) + vm.state.UpdateStateObject(contract) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { @@ -515,7 +515,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - vm.state.SetStateObject(receiver) + vm.state.UpdateStateObject(receiver) closure.object.state.Purge() diff --git a/ethpub/pub.go b/ethpub/pub.go index fb1018d471..ec187e276a 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -162,7 +162,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) tx.Nonce = acc.Nonce acc.Nonce += 1 - lib.stateManager.TransState().SetStateObject(acc) + lib.stateManager.TransState().UpdateStateObject(acc) tx.Sign(keyPair.PrivateKey) lib.txPool.QueueTransaction(tx) diff --git a/ethutil/trie.go b/ethutil/trie.go index 4d088ccff2..c993e4d8f3 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -3,8 +3,13 @@ package ethutil import ( "fmt" "reflect" + "sync" ) +func (s *Cache) Len() int { + return len(s.nodes) +} + // TODO // A StateObject is an object that has a state root // This is goig to be the object for the second level caching (the caching of object which have a state such as contracts) @@ -113,6 +118,7 @@ func (cache *Cache) Undo() { // Please note that the data isn't persisted unless `Sync` is // explicitly called. type Trie struct { + mut sync.RWMutex prevRoot interface{} Root interface{} //db Database @@ -157,12 +163,18 @@ func (t *Trie) Cache() *Cache { * Public (query) interface functions */ func (t *Trie) Update(key string, value string) { + t.mut.Lock() + defer t.mut.Unlock() + k := CompactHexDecode(key) t.Root = t.UpdateState(t.Root, k, value) } func (t *Trie) Get(key string) string { + t.mut.RLock() + defer t.mut.RUnlock() + k := CompactHexDecode(key) c := NewValue(t.GetState(t.Root, k)) From cbf221f6b7a48ece543d6141d8a7e9dbf9b8d86d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 11:42:20 +0200 Subject: [PATCH 0345/1237] Fixed competing block method --- ethchain/state_manager.go | 15 +++++++++++++-- ethminer/miner.go | 2 +- peer.go | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 27eaa5e601..8c442cf449 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -132,8 +132,19 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } } +func (sm *StateManager) Process(block *Block, dontReact bool) error { + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + parent := sm.bc.GetBlock(block.PrevHash) + + return sm.ProcessBlock(parent.State(), parent, block, dontReact) + +} + // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -186,7 +197,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) diff --git a/ethminer/miner.go b/ethminer/miner.go index 26b28d82ff..e052d0207f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -126,7 +126,7 @@ func (miner *Miner) listener() { // Search the nonce miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) if miner.block.Nonce != nil { - err := miner.ethereum.StateManager().ProcessBlock(miner.ethereum.StateManager().CurrentState(), miner.block, true) + err := miner.ethereum.StateManager().Process(miner.block, true) if err != nil { ethutil.Config.Log.Infoln(err) miner.txs = []*ethchain.Transaction{} // Move this somewhere neat diff --git a/peer.go b/peer.go index 690281da9f..cd3cc7635d 100644 --- a/peer.go +++ b/peer.go @@ -335,8 +335,8 @@ func (p *Peer) HandleInbound() { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) //p.ethereum.StateManager().PrepareDefault(block) - state := p.ethereum.StateManager().CurrentState() - err = p.ethereum.StateManager().ProcessBlock(state, block, false) + //state := p.ethereum.StateManager().CurrentState() + err = p.ethereum.StateManager().Process(block, false) if err != nil { if ethutil.Config.Debug { From 07fe00c4661e3b96e1758598df881057c1f52b3a Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 11:42:31 +0200 Subject: [PATCH 0346/1237] Changed numbers --- ethchain/block_chain.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2865336fbc..b72c78cdb0 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -190,8 +190,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - info := bc.BlockInfo(returnTo) - bc.LastBlockNumber = info.Number + //info := bc.BlockInfo(returnTo) + bc.LastBlockNumber = returnTo.Number.Uint64() } // XXX Why are we resetting? This is the block chain, it has nothing to do with states @@ -228,9 +228,9 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { // Get the current hash to start with currentHash := bc.CurrentBlock.Hash() // Get the last number on the block chain - lastNumber := bc.BlockInfo(bc.CurrentBlock).Number + lastNumber := bc.CurrentBlock.Number.Uint64() // Get the parents number - parentNumber := bc.BlockInfoByHash(hash).Number + parentNumber := bc.GetBlock(hash).Number.Uint64() // Get the min amount. We might not have max amount of blocks count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) startNumber := parentNumber + count @@ -291,10 +291,10 @@ func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) - info := bc.BlockInfo(block) + //info := bc.BlockInfo(block) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = info.Number + bc.LastBlockNumber = block.Number.Uint64() ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { From 05e4e9727675f84c5768636070b6a79beea050aa Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:09:28 +0200 Subject: [PATCH 0347/1237] Fixed Public block creation. Added block logging --- ethpub/pub.go | 11 +---------- ethpub/types.go | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index ec187e276a..cd002b5004 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -24,18 +24,9 @@ func NewPEthereum(manager ethchain.EthManager) *PEthereum { func (lib *PEthereum) GetBlock(hexHash string) *PBlock { hash := ethutil.FromHex(hexHash) - block := lib.blockChain.GetBlock(hash) - var blockInfo *PBlock - - if block != nil { - blockInfo = &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} - } else { - blockInfo = &PBlock{Number: -1, Hash: ""} - } - - return blockInfo + return NewPBlock(block) } func (lib *PEthereum) GetKey() *PKey { diff --git a/ethpub/types.go b/ethpub/types.go index 77cca78b9b..afec47fdc3 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -8,16 +8,26 @@ import ( // Block interface exposed to QML type PBlock struct { + ref *ethchain.Block Number int `json:"number"` Hash string `json:"hash"` } // Creates a new QML Block from a chain block func NewPBlock(block *ethchain.Block) *PBlock { - info := block.BlockInfo() - hash := hex.EncodeToString(block.Hash()) + if block == nil { + return nil + } - return &PBlock{Number: int(info.Number), Hash: hash} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash())} +} + +func (self *PBlock) ToString() string { + if self.ref != nil { + return self.ref.String() + } + + return "" } type PTx struct { From 0c27c5eb7fd4cea3ccdf26096a47ed91b0e9b848 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:38:56 +0200 Subject: [PATCH 0348/1237] Proper log statement --- ethchain/transaction_pool.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 796ec7c9a6..dcf0c4c31b 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -81,8 +81,9 @@ func NewTxPool(ethereum EthManager) *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { pool.mutex.Lock() + defer pool.mutex.Unlock() + pool.pool.PushBack(tx) - pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) @@ -182,9 +183,7 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - if ethutil.Config.Debug { - log.Println("Validating Tx failed", err) - } + ethutil.Config.Log.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) From 2667cb3ab69271604262e809927f7ab25dafa93e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:39:07 +0200 Subject: [PATCH 0349/1237] Apply to parent --- ethchain/state_manager.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8c442cf449..9fe485b7a6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,8 +123,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) contract := state.GetStateObject(tx.Recipient) - ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) - if err == nil && len(contract.Script()) > 0 { + if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { ethutil.Config.Log.Infoln("[STATE] process:", err) @@ -168,7 +167,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } // Process the transactions on to current block - sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { From 0e9c8568fd689fdee0cce2584ad96ecce60c60d7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 12:39:15 +0200 Subject: [PATCH 0350/1237] Re broadcast transactions --- peer.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/peer.go b/peer.go index cd3cc7635d..5c46b73fbf 100644 --- a/peer.go +++ b/peer.go @@ -381,6 +381,7 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgTxTy: + fmt.Println("received tx") // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and // processing when a new block is found @@ -658,10 +659,8 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) - /* - msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) - p.QueueMessage(msg) - */ + msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) + p.QueueMessage(msg) } } From d658a7f4ab7691783157151912f43c177825b0e8 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 21 May 2014 12:46:24 +0200 Subject: [PATCH 0351/1237] Implemented missing EthPub calls in RPC server --- ethrpc/packages.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 4ec2b46028..87cfc99b2d 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -182,6 +182,66 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { return nil } +type GetTxCountArgs struct { + Address string `json:"address"` +} +type GetTxCountRes struct { + Nonce int `json:"nonce"` +} + +func (a *GetTxCountArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetTxCountAt requires an 'address' value as argument") + } + return nil +} + +type GetPeerCountRes struct { + PeerCount int `json:"peerCount"` +} + +func (p *EthereumApi) GetPeerCount(args *interface{}, reply *string) error { + *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.ethp.GetPeerCount()}) + return nil +} + +type GetListeningRes struct { + IsListening bool `json:"isListening"` +} + +func (p *EthereumApi) GetIsListening(args *interface{}, reply *string) error { + *reply = NewSuccessRes(GetListeningRes{IsListening: p.ethp.GetIsListening()}) + return nil +} + +type GetCoinbaseRes struct { + Coinbase string `json:"coinbase"` +} + +func (p *EthereumApi) GetCoinbase(args *interface{}, reply *string) error { + *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.ethp.GetCoinBase()}) + return nil +} + +type GetMiningRes struct { + IsMining bool `json:"isMining"` +} + +func (p *EthereumApi) GetIsMining(args *interface{}, reply *string) error { + *reply = NewSuccessRes(GetMiningRes{IsMining: p.ethp.GetIsMining()}) + return nil +} + +func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *string) error { + err := args.requirements() + if err != nil { + return err + } + state := p.ethp.GetTxCountAt(args.Address) + *reply = NewSuccessRes(GetTxCountRes{Nonce: state}) + return nil +} + type GetBalanceArgs struct { Address string } From 86cf69648efc5029abffbf39f1be7308acb1531e Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 13:04:40 +0200 Subject: [PATCH 0352/1237] Improved miner so it won't include invalid transactions --- ethchain/state_manager.go | 12 +++++++----- ethminer/miner.go | 21 ++++++++++++++++----- peer.go | 1 - 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9fe485b7a6..8b56d65bb9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -104,7 +104,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. @@ -115,10 +115,10 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac if contract != nil { sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") + return fmt.Errorf("[STATE] Unable to create contract") } } else { - ethutil.Config.Log.Infoln("[STATE] contract create:", err) + return fmt.Errorf("[STATE] contract create:", err) } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) @@ -126,9 +126,11 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { - ethutil.Config.Log.Infoln("[STATE] process:", err) + return fmt.Errorf("[STATE] process:", err) } } + + return nil } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -184,7 +186,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) + return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db diff --git a/ethminer/miner.go b/ethminer/miner.go index e052d0207f..8d6486e905 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -105,14 +105,14 @@ func (miner *Miner) listener() { miner.block.Undo() //log.Infoln("[MINER] We did not know about this transaction, adding") miner.txs = append(miner.txs, tx) - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - miner.block.SetTransactions(miner.txs) } else { //log.Infoln("[MINER] We already had this transaction, ignoring") } } default: - ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions") + stateManager := miner.ethereum.StateManager() + + miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) // Apply uncles if len(miner.uncles) > 0 { @@ -120,8 +120,19 @@ func (miner *Miner) listener() { } // Apply all transactions to the block - miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions()) - miner.ethereum.StateManager().AccumelateRewards(miner.block.State(), miner.block) + txs := miner.txs + miner.txs = nil + for _, tx := range txs { + if err := stateManager.ApplyTransaction(miner.block.State(), miner.block, tx); err == nil { + miner.txs = append(miner.txs, tx) + } + } + miner.block.SetTransactions(miner.txs) + stateManager.AccumelateRewards(miner.block.State(), miner.block) + + ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions") + + //miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions()) // Search the nonce miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) diff --git a/peer.go b/peer.go index 5c46b73fbf..7f81489b60 100644 --- a/peer.go +++ b/peer.go @@ -381,7 +381,6 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgTxTy: - fmt.Println("received tx") // If the message was a transaction queue the transaction // in the TxPool where it will undergo validation and // processing when a new block is found From f5852b47d1008e3b1752031900e8f4cdd982ee61 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 14:00:13 +0200 Subject: [PATCH 0353/1237] Removed some logging and refactored a bit --- ethchain/dagger.go | 2 +- ethminer/miner.go | 92 +++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 18e53d3a8c..565e1e4473 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,7 +29,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") + //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ diff --git a/ethminer/miner.go b/ethminer/miner.go index 8d6486e905..2e31dceadf 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -60,10 +60,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") + //ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") + //ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -87,13 +87,11 @@ func (miner *Miner) listener() { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { ethutil.Config.Log.Infoln("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) - //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } } } if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { - //log.Infoln("[MINER] Got new transaction from Reactor", tx) found := false for _, ctx := range miner.txs { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { @@ -102,54 +100,54 @@ func (miner *Miner) listener() { } if found == false { + // Undo all previous commits miner.block.Undo() - //log.Infoln("[MINER] We did not know about this transaction, adding") + // Apply new transactions miner.txs = append(miner.txs, tx) - } else { - //log.Infoln("[MINER] We already had this transaction, ignoring") } } default: - stateManager := miner.ethereum.StateManager() - - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - - // Apply uncles - if len(miner.uncles) > 0 { - miner.block.SetUncles(miner.uncles) - } - - // Apply all transactions to the block - txs := miner.txs - miner.txs = nil - for _, tx := range txs { - if err := stateManager.ApplyTransaction(miner.block.State(), miner.block, tx); err == nil { - miner.txs = append(miner.txs, tx) - } - } - miner.block.SetTransactions(miner.txs) - stateManager.AccumelateRewards(miner.block.State(), miner.block) - - ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions") - - //miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions()) - - // Search the nonce - miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) - if miner.block.Nonce != nil { - err := miner.ethereum.StateManager().Process(miner.block, true) - if err != nil { - ethutil.Config.Log.Infoln(err) - miner.txs = []*ethchain.Transaction{} // Move this somewhere neat - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - } else { - miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) - ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) - - miner.txs = []*ethchain.Transaction{} // Move this somewhere neat - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - } - } + miner.mineNewBlock() + } + } +} + +func (self *Miner) mineNewBlock() { + stateManager := self.ethereum.StateManager() + + self.block = self.ethereum.BlockChain().NewBlock(self.coinbase, self.txs) + + // Apply uncles + if len(self.uncles) > 0 { + self.block.SetUncles(self.uncles) + } + + // Accumulate all valid transaction and apply them to the new state + var txs []*ethchain.Transaction + for _, tx := range self.txs { + if err := stateManager.ApplyTransaction(self.block.State(), self.block, tx); err == nil { + txs = append(txs, tx) + } + } + self.txs = txs + // Set the transactions to the block so the new SHA3 can be calculated + self.block.SetTransactions(self.txs) + // Accumulate the rewards included for this block + stateManager.AccumelateRewards(self.block.State(), self.block) + + ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") + + // Find a valid nonce + self.block.Nonce = self.pow.Search(self.block, self.quitChan) + if self.block.Nonce != nil { + err := self.ethereum.StateManager().Process(self.block, true) + if err != nil { + ethutil.Config.Log.Infoln(err) + } else { + self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val}) + ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", self.block.Hash()) + // Gather the new batch of transactions currently in the tx pool + self.txs = self.ethereum.TxPool().CurrentTransactions() } } } From 8f5eddd0ba9287cfcdc0e1f114c3fb367e54c46c Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 14:04:19 +0200 Subject: [PATCH 0354/1237] Bumped --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6bcaad288..2b080273bb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC7". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC8". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index abe86babe3..1b41c46343 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -42,7 +42,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } From e1b7bd51ee5c1310259af450c6455603e5d19fd9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 21 May 2014 15:54:44 +0200 Subject: [PATCH 0355/1237] Return a disassembled script instead of the hex --- ethpub/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethpub/types.go b/ethpub/types.go index afec47fdc3..7194de372e 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "strings" ) // Block interface exposed to QML @@ -132,7 +133,7 @@ func (c *PStateObject) IsContract() bool { func (c *PStateObject) Script() string { if c.object != nil { - return ethutil.Hex(c.object.Script()) + return strings.Join(ethchain.Disassemble(c.object.Script()), " ") } return "" From f8f84ef0953534f44c3ce7c9630c569b1059e4bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 00:25:02 +0200 Subject: [PATCH 0356/1237] Removed old contract creation code --- ethchain/block.go | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 24ff5a32f1..3401632b19 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -56,8 +56,6 @@ type Block struct { // List of transactions and/or contracts transactions []*Transaction TxSha []byte - - contractStates map[string]*ethutil.Trie } // New block takes a raw encoded string @@ -91,28 +89,23 @@ func CreateBlock(root interface{}, block := &Block{ // Slice of transactions to include in this block - transactions: txes, - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: EmptyShaList, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), - contractStates: make(map[string]*ethutil.Trie), + transactions: txes, + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), } block.SetTransactions(txes) block.SetUncles([]*Block{}) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) - for _, tx := range txes { - block.MakeContract(tx) - } - return block } @@ -178,13 +171,6 @@ func (block *Block) Undo() { block.state.Reset() } -func (block *Block) MakeContract(tx *Transaction) { - contract := MakeContract(tx, block.state) - if contract != nil { - block.state.states[string(tx.Hash()[12:])] = contract.state - } -} - /////// Block Encoding func (block *Block) rlpTxs() interface{} { // Marshal the transactions of this block @@ -265,7 +251,6 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.Time = int64(header.Get(10).BigInt().Uint64()) block.Extra = header.Get(11).Str() block.Nonce = header.Get(12).Bytes() - block.contractStates = make(map[string]*ethutil.Trie) // Tx list might be empty if this is an uncle. Uncles only have their // header set. From 4e1c6a8a22924d06a2a972c024891cebcf8ea054 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 00:25:34 +0200 Subject: [PATCH 0357/1237] Added start / stopping methods --- ethminer/miner.go | 52 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 2e31dceadf..166f7bc2f8 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -8,21 +8,22 @@ import ( ) type Miner struct { - pow ethchain.PoW - ethereum ethchain.EthManager - coinbase []byte - reactChan chan ethutil.React - txs []*ethchain.Transaction - uncles []*ethchain.Block - block *ethchain.Block - powChan chan []byte - quitChan chan ethutil.React + pow ethchain.PoW + ethereum ethchain.EthManager + coinbase []byte + reactChan chan ethutil.React + txs []*ethchain.Transaction + uncles []*ethchain.Block + block *ethchain.Block + powChan chan []byte + powQuitChan chan ethutil.React + quitChan chan bool } func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { - 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 - quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread + 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 + powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread ethereum.Reactor().Subscribe("newBlock", reactChan) ethereum.Reactor().Subscribe("newTx:pre", reactChan) @@ -32,16 +33,17 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { // listen to the reactor events inside of the pow itself // The miner overseer will never get the reactor events themselves // Only after the miner will find the sha - ethereum.Reactor().Subscribe("newBlock", quitChan) - ethereum.Reactor().Subscribe("newTx:pre", quitChan) + ethereum.Reactor().Subscribe("newBlock", powQuitChan) + ethereum.Reactor().Subscribe("newTx:pre", powQuitChan) miner := Miner{ - pow: ðchain.EasyPow{}, - ethereum: ethereum, - coinbase: coinbase, - reactChan: reactChan, - powChan: powChan, - quitChan: quitChan, + pow: ðchain.EasyPow{}, + ethereum: ethereum, + coinbase: coinbase, + reactChan: reactChan, + powChan: powChan, + powQuitChan: powQuitChan, + quitChan: make(chan bool), } // Insert initial TXs in our little miner 'pool' @@ -56,8 +58,11 @@ func (miner *Miner) Start() { go miner.listener() } func (miner *Miner) listener() { +out: for { select { + case <-miner.quitChan: + break out case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { //ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") @@ -112,6 +117,11 @@ func (miner *Miner) listener() { } } +func (self *Miner) Stop() { + self.powQuitChan <- ethutil.React{} + self.quitChan <- true +} + func (self *Miner) mineNewBlock() { stateManager := self.ethereum.StateManager() @@ -138,7 +148,7 @@ func (self *Miner) mineNewBlock() { ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") // Find a valid nonce - self.block.Nonce = self.pow.Search(self.block, self.quitChan) + self.block.Nonce = self.pow.Search(self.block, self.powQuitChan) if self.block.Nonce != nil { err := self.ethereum.StateManager().Process(self.block, true) if err != nil { From 14787ac148274a84478aa06fd985407b9241cd50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:33:46 +0200 Subject: [PATCH 0358/1237] Fixed some issues connecting for interop --- peer.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/peer.go b/peer.go index 7f81489b60..7e505d6800 100644 --- a/peer.go +++ b/peer.go @@ -18,7 +18,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 12 + ProtocolVersion = 17 ) type DiscReason byte @@ -119,7 +119,7 @@ type Peer struct { // this to prevent receiving false peers. requestedPeerList bool - host []interface{} + host []byte port uint16 caps Caps @@ -134,8 +134,7 @@ type Peer struct { } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + pubkey := ethutil.GetKeyRing().Get(0).PublicKey[1:] return &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), @@ -342,6 +341,7 @@ func (p *Peer) HandleInbound() { if ethutil.Config.Debug { ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash()) ethutil.Config.Log.Infof("[PEER] %v\n", err) + ethutil.Config.Log.Debugln(block) } break } else { @@ -437,7 +437,7 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { - ethutil.Config.Log.Debugf("[PEER] Found conical block, returning chain from: %x ", parent.Hash()) + ethutil.Config.Log.Debugf("[PEER] Found canonical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) @@ -531,11 +531,10 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - pubkey := ethutil.NewValueFromBytes(data).Get(2).Bytes() + pubkey := ethutil.GetKeyRing().Get(0).PublicKey msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey, + uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:], }) p.QueueMessage(msg) @@ -667,23 +666,24 @@ func (p *Peer) RlpData() []interface{} { return []interface{}{p.host, p.port, p.pubkey} } -func packAddr(address, port string) ([]interface{}, uint16) { +func packAddr(address, port string) ([]byte, uint16) { addr := strings.Split(address, ".") a, _ := strconv.Atoi(addr[0]) b, _ := strconv.Atoi(addr[1]) c, _ := strconv.Atoi(addr[2]) d, _ := strconv.Atoi(addr[3]) - host := []interface{}{int32(a), int32(b), int32(c), int32(d)} + host := []byte{byte(a), byte(b), byte(c), byte(d)} prt, _ := strconv.Atoi(port) return host, uint16(prt) } func unpackAddr(value *ethutil.Value, p uint64) string { - a := strconv.Itoa(int(value.Get(0).Uint())) - b := strconv.Itoa(int(value.Get(1).Uint())) - c := strconv.Itoa(int(value.Get(2).Uint())) - d := strconv.Itoa(int(value.Get(3).Uint())) + byts := value.Bytes() + a := strconv.Itoa(int(byts[0])) + b := strconv.Itoa(int(byts[1])) + c := strconv.Itoa(int(byts[2])) + d := strconv.Itoa(int(byts[3])) host := strings.Join([]string{a, b, c, d}, ".") port := strconv.Itoa(int(p)) From 230aafbf66ba747fb3796810adf3b1680f368e73 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:35:26 +0200 Subject: [PATCH 0359/1237] Working on interop * Receipts after each transaction * Fee structure * Applying fees to miners --- ethchain/block.go | 74 +++++++++++++++---------- ethchain/block_chain.go | 21 +++---- ethchain/genesis.go | 2 +- ethchain/state_manager.go | 42 +++++++++++--- ethchain/state_object.go | 2 +- ethchain/transaction.go | 104 +++++++++++++++++++++++++++++------ ethchain/transaction_pool.go | 18 +++--- ethchain/vm.go | 1 + ethminer/miner.go | 15 ++--- ethutil/config.go | 10 +++- ethutil/value.go | 2 +- 11 files changed, 203 insertions(+), 88 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index 3401632b19..c846516f4e 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -55,6 +55,7 @@ type Block struct { Nonce []byte // List of transactions and/or contracts transactions []*Transaction + receipts []*Receipt TxSha []byte } @@ -84,24 +85,20 @@ func CreateBlock(root interface{}, base []byte, Difficulty *big.Int, Nonce []byte, - extra string, - txes []*Transaction) *Block { + extra string) *Block { block := &Block{ - // Slice of transactions to include in this block - transactions: txes, - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: EmptyShaList, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), } - block.SetTransactions(txes) block.SetUncles([]*Block{}) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) @@ -115,7 +112,10 @@ func (block *Block) Hash() []byte { } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + block.UncleSha, block.Coinbase, block.state.trie.Root, + block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, + block.GasLimit, block.GasUsed, block.Time, block.Extra})) } func (block *Block) State() *State { @@ -172,15 +172,15 @@ func (block *Block) Undo() { } /////// Block Encoding -func (block *Block) rlpTxs() interface{} { +func (block *Block) rlpReceipts() interface{} { // Marshal the transactions of this block - encTx := make([]interface{}, len(block.transactions)) - for i, tx := range block.transactions { + encR := make([]interface{}, len(block.receipts)) + for i, r := range block.receipts { // Cast it to a string (safe) - encTx[i] = tx.RlpData() + encR[i] = r.RlpData() } - return encTx + return encR } func (block *Block) rlpUncles() interface{} { @@ -201,7 +201,12 @@ func (block *Block) SetUncles(uncles []*Block) { block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) } -func (block *Block) SetTransactions(txs []*Transaction) { +func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { + self.receipts = receipts + self.setTransactions(txs) +} + +func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs trie := ethutil.NewTrie(ethutil.Config.Db, "") @@ -221,7 +226,7 @@ func (block *Block) SetTransactions(txs []*Transaction) { } func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) + return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()}) } func (block *Block) RlpEncode() []byte { @@ -245,6 +250,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() + //fmt.Printf("#%v : %x\n", block.Number, block.Coinbase) block.MinGasPrice = header.Get(7).BigInt() block.GasLimit = header.Get(8).BigInt() block.GasUsed = header.Get(9).BigInt() @@ -255,12 +261,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { // Tx list might be empty if this is an uncle. Uncles only have their // header set. if decoder.Get(1).IsNil() == false { // Yes explicitness - txes := decoder.Get(1) - block.transactions = make([]*Transaction, txes.Len()) - for i := 0; i < txes.Len(); i++ { - tx := NewTransactionFromValue(txes.Get(i)) - - block.transactions[i] = tx + receipts := decoder.Get(1) + block.transactions = make([]*Transaction, receipts.Len()) + block.receipts = make([]*Receipt, receipts.Len()) + for i := 0; i < receipts.Len(); i++ { + receipt := NewRecieptFromValue(receipts.Get(i)) + block.transactions[i] = receipt.Tx + block.receipts[i] = receipt } } @@ -299,6 +306,10 @@ func (block *Block) GetRoot() interface{} { return block.state.trie.Root } +func (self *Block) Receipts() []*Receipt { + return self.receipts +} + func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -346,6 +357,7 @@ func (block *Block) String() string { Time: %v Extra: %v Nonce: %x + NumTx: %v `, block.Hash(), block.PrevHash, @@ -360,5 +372,7 @@ func (block *Block) String() string { block.GasUsed, block.Time, block.Extra, - block.Nonce) + block.Nonce, + len(block.transactions), + ) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b72c78cdb0..b45d254b5c 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -36,7 +36,7 @@ func (bc *BlockChain) Genesis() *Block { return bc.genesisBlock } -func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { +func (bc *BlockChain) NewBlock(coinbase []byte) *Block { var root interface{} var lastBlockTime int64 hash := ZeroHash256 @@ -53,8 +53,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { coinbase, ethutil.BigPow(2, 32), nil, - "", - txs) + "") if bc.CurrentBlock != nil { var mul *big.Int @@ -272,16 +271,18 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman + "8a40bfaa73256b60764c1bf40675a99083efb075", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) - account.Amount = ethutil.BigPow(2, 200) + account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } log.Printf("%x\n", block.RlpEncode()) diff --git a/ethchain/genesis.go b/ethchain/genesis.go index b8f9f865a3..359c47c261 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -23,7 +23,7 @@ var GenesisHeader = []interface{}{ // Root state "", // tx sha - ZeroHash256, + "", // Difficulty ethutil.BigPow(2, 22), // Number diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8b56d65bb9..3b67381ea7 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,40 +97,56 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { +func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { // Process each transaction/contract + var receipts []*Receipt + var validTxs []*Transaction + totalUsedGas := big.NewInt(0) for _, tx := range txs { - sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(state, block, tx) + if err != nil { + ethutil.Config.Log.Infoln(err) + continue + } + + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + + receipts = append(receipts, receipt) + validTxs = append(validTxs, tx) } + + return receipts, txs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. + totalGasUsed := big.NewInt(0) if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) if err == nil { contract := sm.MakeContract(state, tx) if contract != nil { sm.EvalScript(state, contract.Init(), contract, tx, block) } else { - return fmt.Errorf("[STATE] Unable to create contract") + return nil, fmt.Errorf("[STATE] Unable to create contract") } } else { - return fmt.Errorf("[STATE] contract create:", err) + return nil, fmt.Errorf("[STATE] contract create:", err) } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) contract := state.GetStateObject(tx.Recipient) if err == nil && contract != nil && len(contract.Script()) > 0 { sm.EvalScript(state, contract.Script(), contract, tx, block) } else if err != nil { - return fmt.Errorf("[STATE] process:", err) + return nil, fmt.Errorf("[STATE] process:", err) } } - return nil + return totalGasUsed, nil } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -276,6 +292,14 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { for i := 0; i < uncleLength; i++ { base.Add(base, UncleInclusionReward) } + + lastCumulGasUsed := big.NewInt(0) + for _, r := range block.Receipts() { + usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed) + usedGas.Add(usedGas, r.Tx.GasPrice) + base.Add(base, usedGas) + } + return base.Add(base, BlockReward) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e059f3344..4046054db3 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -146,7 +146,7 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = ZeroHash256 + root = "" } return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index bd7a0e424c..16ea312c08 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -46,11 +47,13 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } + /* + if tx.contractCreation { + data = append(data, tx.Init) + } + */ return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } @@ -138,18 +141,87 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Recipient = decoder.Get(3).Bytes() tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() - // If the list is of length 10 it's a contract creation tx - if decoder.Len() == 10 { - tx.contractCreation = true - tx.Init = decoder.Get(6).Bytes() + /* + // If the list is of length 10 it's a contract creation tx + if decoder.Len() == 10 { + tx.contractCreation = true + tx.Init = decoder.Get(6).Bytes() - tx.v = byte(decoder.Get(7).Uint()) - tx.r = decoder.Get(8).Bytes() - tx.s = decoder.Get(9).Bytes() - } else { - tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - } + tx.v = byte(decoder.Get(7).Uint()) + tx.r = decoder.Get(8).Bytes() + tx.s = decoder.Get(9).Bytes() + } else { + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + } + */ +} + +func (tx *Transaction) String() string { + return fmt.Sprintf(` + TX(%x) + Contract: %v + From: %x + Nonce: %v + GasPrice: %v + Gas: %v + To: %x + Value: %v + Data: 0x%x + V: 0x%x + R: 0x%x + S: 0x%x + `, + tx.Hash(), + len(tx.Recipient) > 1, + tx.Sender(), + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.Recipient, + tx.Value, + tx.Data, + tx.v, + tx.r, + tx.s) +} + +type Receipt struct { + Tx *Transaction + PostState []byte + CumulativeGasUsed *big.Int +} + +func NewRecieptFromValue(val *ethutil.Value) *Receipt { + r := &Receipt{} + r.RlpValueDecode(val) + + return r +} + +func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { + self.Tx = NewTransactionFromValue(decoder.Get(0)) + self.PostState = decoder.Get(1).Bytes() + self.CumulativeGasUsed = decoder.Get(2).BigInt() +} + +func (self *Receipt) RlpData() interface{} { + return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed} +} + +func (self *Receipt) String() string { + return fmt.Sprintf(` + R + Tx:[ %v] + PostState: 0x%x + CumulativeGasUsed: %v + `, + self.Tx, + self.PostState, + self.CumulativeGasUsed) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index dcf0c4c31b..ee026ffdd9 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,15 +91,15 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { defer func() { if r := recover(); r != nil { - log.Println(r) + ethutil.Config.Log.Infoln(r) err = fmt.Errorf("%v", r) } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -107,19 +107,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) if sender.Amount.Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + //fmt.Println(tx) // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee - sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -127,10 +129,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) - block.state.UpdateStateObject(receiver) + state.UpdateStateObject(receiver) } - block.state.UpdateStateObject(sender) + state.UpdateStateObject(sender) ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) diff --git a/ethchain/vm.go b/ethchain/vm.go index d8254998e9..e067a9c96a 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -18,6 +18,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasTx = big.NewInt(500) ) func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { diff --git a/ethminer/miner.go b/ethminer/miner.go index 166f7bc2f8..00e04cde2e 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -48,7 +48,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { // Insert initial TXs in our little miner 'pool' miner.txs = ethereum.TxPool().Flush() - miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) + miner.block = ethereum.BlockChain().NewBlock(miner.coinbase) return miner } @@ -86,7 +86,7 @@ out: miner.txs = newtxs // Setup a fresh state to mine on - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) + //miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { @@ -125,7 +125,7 @@ func (self *Miner) Stop() { func (self *Miner) mineNewBlock() { stateManager := self.ethereum.StateManager() - self.block = self.ethereum.BlockChain().NewBlock(self.coinbase, self.txs) + self.block = self.ethereum.BlockChain().NewBlock(self.coinbase) // Apply uncles if len(self.uncles) > 0 { @@ -133,15 +133,10 @@ func (self *Miner) mineNewBlock() { } // Accumulate all valid transaction and apply them to the new state - var txs []*ethchain.Transaction - for _, tx := range self.txs { - if err := stateManager.ApplyTransaction(self.block.State(), self.block, tx); err == nil { - txs = append(txs, tx) - } - } + receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs) self.txs = txs // Set the transactions to the block so the new SHA3 can be calculated - self.block.SetTransactions(self.txs) + self.block.SetReceipts(receipts, txs) // Accumulate the rewards included for this block stateManager.AccumelateRewards(self.block.State(), self.block) diff --git a/ethutil/config.go b/ethutil/config.go index 1b41c46343..e6cbde4b6b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -19,6 +19,7 @@ type config struct { Ver string ClientString string Pubkey []byte + Identifier string } var Config *config @@ -26,7 +27,7 @@ var Config *config // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType) *config { +func ReadConfig(base string, logTypes LoggerType, id string) *config { if Config == nil { usr, _ := user.Current() path := path.Join(usr.HomeDir, base) @@ -43,6 +44,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} + Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } @@ -53,7 +55,11 @@ func ReadConfig(base string, logTypes LoggerType) *config { // Set client string // func (c *config) SetClientString(str string) { - Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, runtime.GOOS) + id := runtime.GOOS + if len(c.Identifier) > 0 { + id = c.Identifier + } + Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) } type LoggerType byte diff --git a/ethutil/value.go b/ethutil/value.go index b7756f9b16..83600abc2c 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -16,7 +16,7 @@ type Value struct { } func (val *Value) String() string { - return fmt.Sprintf("%q", val.Val) + return fmt.Sprintf("%x", val.Val) } func NewValue(val interface{}) *Value { From cc8464ce805279735f637ac710b25e2fb264f9aa Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 17:56:33 +0200 Subject: [PATCH 0360/1237] Transaction querying --- ethchain/block.go | 11 +++++++++++ ethchain/transaction.go | 6 +++--- ethpub/types.go | 17 ++++++++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index c846516f4e..73e29f8783 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -161,6 +162,16 @@ func (block *Block) BlockInfo() BlockInfo { return bi } +func (self *Block) GetTransaction(hash []byte) *Transaction { + for _, receipt := range self.receipts { + if bytes.Compare(receipt.Tx.Hash(), hash) == 0 { + return receipt.Tx + } + } + + return nil +} + // Sync the block's state and contract respectively func (block *Block) Sync() { block.state.Sync() diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 16ea312c08..6ae7e77e1c 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -167,10 +167,10 @@ func (tx *Transaction) String() string { TX(%x) Contract: %v From: %x + To: %x Nonce: %v GasPrice: %v Gas: %v - To: %x Value: %v Data: 0x%x V: 0x%x @@ -178,12 +178,12 @@ func (tx *Transaction) String() string { S: 0x%x `, tx.Hash(), - len(tx.Recipient) > 1, + len(tx.Recipient) == 1, tx.Sender(), + tx.Recipient, tx.Nonce, tx.GasPrice, tx.Gas, - tx.Recipient, tx.Value, tx.Data, tx.v, diff --git a/ethpub/types.go b/ethpub/types.go index 7194de372e..e8a2164a78 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -31,7 +31,18 @@ func (self *PBlock) ToString() string { return "" } +func (self *PBlock) GetTransaction(hash string) *PTx { + tx := self.ref.GetTransaction(ethutil.FromHex(hash)) + if tx == nil { + return nil + } + + return NewPTx(tx) +} + type PTx struct { + ref *ethchain.Transaction + Value, Hash, Address string Contract bool } @@ -41,7 +52,11 @@ func NewPTx(tx *ethchain.Transaction) *PTx { sender := hex.EncodeToString(tx.Recipient) isContract := len(tx.Data) > 0 - return &PTx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract} +} + +func (self *PTx) ToString() string { + return self.ref.String() } type PKey struct { From 281559d42712c2b2ae903cb893b2ddc82318307d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 22 May 2014 18:24:04 +0200 Subject: [PATCH 0361/1237] Canonical contract creation --- ethchain/state_manager.go | 22 +++++++++++++++------- ethchain/state_object.go | 3 +-- ethchain/transaction.go | 9 ++------- ethchain/types.go | 7 +++++++ ethpub/pub.go | 4 +++- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 3b67381ea7..4f009b6d34 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -84,7 +84,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { state.states[string(tx.CreationAddress())] = contract.state @@ -123,18 +123,24 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. + // TODO COMMENT THIS SECTION totalGasUsed := big.NewInt(0) if tx.IsContract() { err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) if err == nil { - contract := sm.MakeContract(state, tx) + contract := sm.MakeStateObject(state, tx) if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) + script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) + if err != nil { + return nil, fmt.Errorf("[STATE] Error during init script run %v", err) + } + contract.script = script + state.UpdateStateObject(contract) } else { return nil, fmt.Errorf("[STATE] Unable to create contract") } } else { - return nil, fmt.Errorf("[STATE] contract create:", err) + return nil, fmt.Errorf("[STATE] contract creation tx:", err) } } else { err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) @@ -331,10 +337,10 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { account := state.GetAccount(tx.Sender()) - err := account.ConvertGas(tx.Gas, tx.GasPrice) + err = account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { ethutil.Config.Log.Debugln(err) return @@ -351,11 +357,13 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj Value: tx.Value, //Price: tx.GasPrice, }) - closure.Call(vm, tx.Data, nil) + ret, err = closure.Call(vm, tx.Data, nil) // Update the account (refunds) state.UpdateStateObject(account) state.UpdateStateObject(object) + + return } func (sm *StateManager) notifyChanges(state *State) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4046054db3..4d615e2fef 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -28,8 +28,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { value := tx.Value contract := NewContract(addr, value, ZeroHash256) - contract.script = tx.Data - contract.initScript = tx.Init + contract.initScript = tx.Data state.UpdateStateObject(contract) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 6ae7e77e1c..25d63879bd 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -16,7 +16,6 @@ type Transaction struct { Gas *big.Int GasPrice *big.Int Data []byte - Init []byte v byte r, s []byte @@ -24,8 +23,8 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true} +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { + return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { @@ -115,10 +114,6 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } - return append(data, tx.v, tx.r, tx.s) } diff --git a/ethchain/types.go b/ethchain/types.go index 9964bbe3bf..e0fdd5191c 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -322,3 +322,10 @@ func IsOpCode(s string) bool { } return false } + +func AppendScript(init, script []byte) []byte { + s := append(init, byte(oRETURN)) + s = append(s, script...) + + return s +} diff --git a/ethpub/pub.go b/ethpub/pub.go index cd002b5004..e726c66f36 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -141,7 +141,9 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in } } - tx = ethchain.NewContractCreationTx(value, gas, gasPrice, mainScript, initScript) + script := ethchain.AppendScript(initScript, mainScript) + + tx = ethchain.NewContractCreationTx(value, gas, gasPrice, script) } else { // Just in case it was submitted as a 0x prefixed string if len(initStr) > 0 && initStr[0:2] == "0x" { From 99fa9afaf15ceecffcc5b7051ffe9c7f0d179dec Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 25 May 2014 14:13:07 +0100 Subject: [PATCH 0362/1237] Updated to work with the new config --- ethchain/block_chain_test.go | 4 ++-- ethchain/state_object_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 4e4bb9dd40..ecaf8ca894 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -50,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", ethutil.LogStd) + ethutil.ReadConfig(".ethtest", ethutil.LogStd, "") db, err := ethdb.NewMemDatabase() if err != nil { @@ -74,7 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) + err := tm.StateManager().Process(block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index e955acc56b..91ed7c0ddf 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -9,7 +9,7 @@ import ( ) func TestSync(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) @@ -28,7 +28,7 @@ func TestSync(t *testing.T) { } func TestObjectGet(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db From 81ef40010f6f31bc94f654048b41fa3a9f9e07eb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 25 May 2014 14:13:54 +0100 Subject: [PATCH 0363/1237] The body of contracts are now returned instead --- ethchain/state_manager.go | 32 ++++++++++++------ ethchain/transaction.go | 12 +++++-- ethchain/vm_test.go | 68 ++++++++++++--------------------------- ethpub/pub.go | 54 +++++++++++++++++++------------ ethrpc/packages.go | 2 +- 5 files changed, 86 insertions(+), 82 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4f009b6d34..2d2a32e2fe 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -120,16 +120,27 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra } func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - // TODO COMMENT THIS SECTION + /* + Applies transactions to the given state and creates new + state objects where needed. + + If said objects needs to be created + run the initialization script provided by the transaction and + assume there's a return value. The return value will be set to + the script section of the state object. + */ totalGasUsed := big.NewInt(0) - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + // Apply the transaction to the current state + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + if tx.CreatesContract() { if err == nil { + // Create a new state object and the transaction + // as it's data provider. contract := sm.MakeStateObject(state, tx) if contract != nil { + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) if err != nil { return nil, fmt.Errorf("[STATE] Error during init script run %v", err) @@ -143,10 +154,11 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac return nil, fmt.Errorf("[STATE] contract creation tx:", err) } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) - contract := state.GetStateObject(tx.Recipient) - if err == nil && contract != nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) + // Find the state object at the "recipient" address. If + // there's an object attempt to run the script. + stateObject := state.GetStateObject(tx.Recipient) + if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { + sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) } else if err != nil { return nil, fmt.Errorf("[STATE] process:", err) } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 25d63879bd..2c5615f991 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -57,10 +57,15 @@ func (tx *Transaction) Hash() []byte { return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } -func (tx *Transaction) IsContract() bool { +func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } +/* Depricated */ +func (tx *Transaction) IsContract() bool { + return tx.CreatesContract() +} + func (tx *Transaction) CreationAddress() []byte { return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } @@ -139,6 +144,9 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() + if len(tx.Recipient) == 0 { + tx.contractCreation = true + } /* // If the list is of length 10 it's a contract creation tx @@ -173,7 +181,7 @@ func (tx *Transaction) String() string { S: 0x%x `, tx.Hash(), - len(tx.Recipient) == 1, + len(tx.Recipient) == 0, tx.Sender(), tx.Recipient, tx.Nonce, diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 2ec70536aa..520f9a2ed7 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,6 +1,5 @@ package ethchain -/* import ( _ "bytes" "fmt" @@ -13,60 +12,33 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - script, err := mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 20 - if a > b { - int32 c = this.caller() - } - exit() - `), false) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - tx.Sign(ContractAddr) - addr := tx.CreationAddress() - contract := MakeContract(tx, state) - state.UpdateStateObject(contract) - fmt.Printf("%x\n", addr) - callerScript, err := mutan.Compile(strings.NewReader(` - // Check if there's any cash in the initial store - if this.store[1000] == 0 { - this.store[1000] = 10**20 - } - - - this.store[1001] = this.value() * 20 - this.store[this.origin()] = this.store[this.origin()] + 1000 - - if this.store[1001] > 20 { - this.store[1001] = 10^50 - } - - int8 ret = 0 - int8 arg = 10 - call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) - - big t - for int8 i = 0; i < 10; i++ { - t = i - } - - if 10 > 20 { - int8 shouldnt = 2 - } else { - int8 should = 1 + this.store[this.origin()] = 10**20 + hello := "world" + + return lambda { + big to = this.data[0] + big from = this.origin() + big value = this.data[1] + + if this.store[from] >= value { + this.store[from] = this.store[from] - value + this.store[to] = this.store[to] + value } + } `), false) if err != nil { fmt.Println(err) } + fmt.Println(Disassemble(callerScript)) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript) + callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) // Contract addr as test address gas := big.NewInt(1000) @@ -79,7 +51,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) + callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), @@ -89,10 +61,10 @@ func TestRun4(t *testing.T) { Time: 1, Diff: big.NewInt(256), }) - _, e = callerClosure.Call(vm, nil, nil) + var ret []byte + ret, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } - fmt.Println("account.Amount =", account.Amount) + fmt.Println(ret) } -*/ diff --git a/ethpub/pub.go b/ethpub/pub.go index e726c66f36..b75d3abc85 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -87,14 +87,14 @@ func (lib *PEthereum) SecretToAddress(key string) string { } func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { - return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr, "") + return lib.createTx(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) } -func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) (*PReceipt, error) { - return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, initStr, bodyStr) +func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) (*PReceipt, error) { + return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) } -func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, initStr, scriptStr string) (*PReceipt, error) { +func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool if len(recipient) == 0 { @@ -121,35 +121,47 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in var tx *ethchain.Transaction // Compile and assemble the given data if contractCreation { - var initScript, mainScript []byte + /* + var initScript, mainScript []byte + var err error + if ethutil.IsHex(initStr) { + initScript = ethutil.FromHex(initStr[2:]) + } else { + initScript, err = ethutil.Compile(initStr) + if err != nil { + return nil, err + } + } + + if ethutil.IsHex(scriptStr) { + mainScript = ethutil.FromHex(scriptStr[2:]) + } else { + mainScript, err = ethutil.Compile(scriptStr) + if err != nil { + return nil, err + } + } + + script := ethchain.AppendScript(initScript, mainScript) + */ + var script []byte var err error - if ethutil.IsHex(initStr) { - initScript = ethutil.FromHex(initStr[2:]) - } else { - initScript, err = ethutil.Compile(initStr) - if err != nil { - return nil, err - } - } - if ethutil.IsHex(scriptStr) { - mainScript = ethutil.FromHex(scriptStr[2:]) + script = ethutil.FromHex(scriptStr) } else { - mainScript, err = ethutil.Compile(scriptStr) + script, err = ethutil.Compile(scriptStr) if err != nil { return nil, err } } - script := ethchain.AppendScript(initScript, mainScript) - tx = ethchain.NewContractCreationTx(value, gas, gasPrice, script) } else { // Just in case it was submitted as a 0x prefixed string - if len(initStr) > 0 && initStr[0:2] == "0x" { - initStr = initStr[2:len(initStr)] + if len(scriptStr) > 0 && scriptStr[0:2] == "0x" { + scriptStr = scriptStr[2:len(scriptStr)] } - tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) + tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(scriptStr)) } acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 87cfc99b2d..1c4fb99f6f 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -137,7 +137,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { if err != nil { return err } - result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Init, args.Body) + result, _ := p.ethp.Create(p.ethp.GetKey().PrivateKey, args.Value, args.Gas, args.GasPrice, args.Body) *reply = NewSuccessRes(result) return nil } From 3ebd7f1166f03f94117651d8e74b9603ee7d6966 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 26 May 2014 00:09:38 +0200 Subject: [PATCH 0364/1237] State snapshotting --- ethchain/state.go | 16 +++++++++++++++- ethchain/state_object.go | 7 ++++++- ethchain/state_test.go | 31 +++++++++++++++++++++++++++++++ ethchain/vm.go | 19 ++++++++++++++----- ethutil/trie_test.go | 17 +++++++++++++++-- 5 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 ethchain/state_test.go diff --git a/ethchain/state.go b/ethchain/state.go index 6ec6916f46..e209e0e2ff 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -99,7 +99,21 @@ func (s *State) Cmp(other *State) bool { } func (s *State) Copy() *State { - return NewState(s.trie.Copy()) + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} + +func (s *State) Snapshot() *State { + return s.Copy() +} + +func (s *State) Revert(snapshot *State) { + s.trie = snapshot.trie + s.states = snapshot.states } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 4d615e2fef..3e9c6df40b 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -81,12 +81,17 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { c.SetAddr(addr, val) } -func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { +func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { nb := ethutil.BigToBytes(num, 256) return c.Addr(nb) } +/* DEPRECATED */ +func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { + return c.GetStorage(num) +} + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) diff --git a/ethchain/state_test.go b/ethchain/state_test.go new file mode 100644 index 0000000000..4cc3fdf75f --- /dev/null +++ b/ethchain/state_test.go @@ -0,0 +1,31 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSnapshot(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd, "") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(stateObject) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) + + snapshot := state.Snapshot() + + stateObject = state.GetStateObject([]byte("aa")) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) + + state.Revert(snapshot) + + stateObject = state.GetStateObject([]byte("aa")) + if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { + t.Error("Expected storage 0 to be 42") + } +} diff --git a/ethchain/vm.go b/ethchain/vm.go index e067a9c96a..e025920f30 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -426,6 +426,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro value := stack.Pop() size, offset := stack.Popn() + // Snapshot the current stack so we are able to + // revert back to it later. + snapshot := vm.state.Snapshot() + // Generate a new address addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) // Create a new contract @@ -448,6 +452,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Script, err = closure.Call(vm, nil, hook) if err != nil { stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigD(addr)) @@ -473,6 +480,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + snapshot := vm.state.Snapshot() + // Fetch the contract which will serve as the closure body contract := vm.state.GetStateObject(addr.Bytes()) @@ -495,14 +504,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) // Reset the changes applied this object - //contract.State().Reset() + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigTrue) + + vm.state.UpdateStateObject(contract) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } - - vm.state.UpdateStateObject(contract) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 0be512d9fc..d74d129ac3 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,7 @@ package ethutil import ( - _ "fmt" + "fmt" "reflect" "testing" ) @@ -26,7 +26,6 @@ func (db *MemDatabase) Delete(key []byte) error { delete(db.db, string(key)) return nil } -func (db *MemDatabase) GetKeys() []*Key { return nil } func (db *MemDatabase) Print() {} func (db *MemDatabase) Close() {} func (db *MemDatabase) LastKnownTD() []byte { return nil } @@ -171,3 +170,17 @@ func TestTrieIterator(t *testing.T) { t.Errorf("Expected cached nodes to be deleted") } } + +func TestHashes(t *testing.T) { + _, trie := New() + trie.Update("cat", "dog") + trie.Update("ca", "dude") + trie.Update("doge", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") + trie.Update("dog", "test") + trie.Update("test", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") + fmt.Printf("%x\n", trie.Root) + trie.Delete("dog") + fmt.Printf("%x\n", trie.Root) + trie.Delete("test") + fmt.Printf("%x\n", trie.Root) +} From 1f3f76cb092e84bd2e90950f0d43d7657eae878e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 26 May 2014 00:38:53 +0200 Subject: [PATCH 0365/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b080273bb..081d9481e6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC8". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC9". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index e6cbde4b6b..40ab3aa696 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC9"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") From 24a6d87c3f4bc69fdd1c619b36f8b74a61fd8bae Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 26 May 2014 11:47:47 +0200 Subject: [PATCH 0366/1237] Don't handshake if there is no key yet; first start on Ethereal --- peer.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/peer.go b/peer.go index 7e505d6800..d613bf6ff0 100644 --- a/peer.go +++ b/peer.go @@ -531,13 +531,16 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { - pubkey := ethutil.GetKeyRing().Get(0).PublicKey + keyRing := ethutil.GetKeyRing().Get(0) + if keyRing != nil { + pubkey := keyRing.PublicKey - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:], - }) + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ + uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:], + }) - p.QueueMessage(msg) + p.QueueMessage(msg) + } return nil } From aefcb834199a64ff62daf7e685bbe5088c08a11e Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 26 May 2014 17:07:04 +0200 Subject: [PATCH 0367/1237] Updated Public Block and Transaction objects with more information --- ethpub/types.go | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index e8a2164a78..edef7d50ec 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -2,16 +2,20 @@ package ethpub import ( "encoding/hex" + "encoding/json" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + _ "log" "strings" ) // Block interface exposed to QML type PBlock struct { - ref *ethchain.Block - Number int `json:"number"` - Hash string `json:"hash"` + ref *ethchain.Block + Number int `json:"number"` + Hash string `json:"hash"` + Transactions string `json:"transactions"` + Time int64 `json:"time"` } // Creates a new QML Block from a chain block @@ -19,8 +23,17 @@ func NewPBlock(block *ethchain.Block) *PBlock { if block == nil { return nil } + var ptxs []PTx + for _, tx := range block.Transactions() { + ptxs = append(ptxs, *NewPTx(tx)) + } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash())} + b, err := json.Marshal(ptxs) + if err != nil { + return nil + } + + return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(b), Time: block.Time} } func (self *PBlock) ToString() string { @@ -43,16 +56,23 @@ func (self *PBlock) GetTransaction(hash string) *PTx { type PTx struct { ref *ethchain.Transaction - Value, Hash, Address string - Contract bool + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Address string `json:"address"` + Sender string `json:"sender"` + Data string `json:"data"` + Contract bool `json:"isContract"` } func NewPTx(tx *ethchain.Transaction) *PTx { hash := hex.EncodeToString(tx.Hash()) - sender := hex.EncodeToString(tx.Recipient) + receiver := hex.EncodeToString(tx.Recipient) + sender := hex.EncodeToString(tx.Sender()) isContract := len(tx.Data) > 0 - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender, Contract: isContract} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: hex.EncodeToString(tx.Data), Sender: sender} } func (self *PTx) ToString() string { From 2232974cda9ed73c62a370545742ef88332c5f1e Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 26 May 2014 17:18:51 +0200 Subject: [PATCH 0368/1237] Changed var names around --- ethpub/types.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index edef7d50ec..af3cfe2cd8 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -23,17 +23,18 @@ func NewPBlock(block *ethchain.Block) *PBlock { if block == nil { return nil } + var ptxs []PTx for _, tx := range block.Transactions() { ptxs = append(ptxs, *NewPTx(tx)) } - b, err := json.Marshal(ptxs) + txJson, err := json.Marshal(ptxs) if err != nil { return nil } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(b), Time: block.Time} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time} } func (self *PBlock) ToString() string { From 5cdfee51437532ccfb49e874fdbbea2702c3d13f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 01:08:51 +0200 Subject: [PATCH 0369/1237] New Trie iterator --- ethutil/encoding.go | 15 +++++++++++++++ ethutil/trie.go | 46 ++++++++++++++++++++++++++++++++++++++++++++ ethutil/trie_test.go | 22 ++++++++++----------- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/ethutil/encoding.go b/ethutil/encoding.go index 1f661947a7..9fcdf3edfc 100644 --- a/ethutil/encoding.go +++ b/ethutil/encoding.go @@ -59,3 +59,18 @@ func CompactHexDecode(str string) []int { return hexSlice } + +func DecodeCompact(key []int) string { + base := "0123456789abcdef" + var str string + + for _, v := range key { + if v < 16 { + str += string(base[v]) + } + } + + res, _ := hex.DecodeString(str) + + return string(res) +} diff --git a/ethutil/trie.go b/ethutil/trie.go index c993e4d8f3..18d0a5f0ae 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -442,6 +442,8 @@ type TrieIterator struct { shas [][]byte values []string + + lastNode []byte } func (t *Trie) NewIterator() *TrieIterator { @@ -513,3 +515,47 @@ func (it *TrieIterator) Key() string { func (it *TrieIterator) Value() string { return "" } + +type EachCallback func(key string, node *Value) + +func (it *TrieIterator) Each(cb EachCallback) { + it.fetchNode(nil, NewValue(it.trie.Root).Bytes(), cb) +} + +func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { + it.iterateNode(key, it.trie.cache.Get(node), cb) +} + +func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { + if currentNode.Len() == 2 { + k := CompactDecode(currentNode.Get(0).Str()) + + if currentNode.Get(1).Str() == "" { + it.iterateNode(key, currentNode.Get(1), cb) + } else { + pk := append(key, k...) + + if k[len(k)-1] == 16 { + cb(DecodeCompact(pk), currentNode.Get(1)) + } else { + it.fetchNode(pk, currentNode.Get(1).Bytes(), cb) + } + } + } else { + for i := 0; i < currentNode.Len(); i++ { + pk := append(key, i) + if i == 16 && currentNode.Get(i).Len() != 0 { + cb(DecodeCompact(pk), currentNode.Get(i)) + } else { + if currentNode.Get(i).Str() == "" { + it.iterateNode(pk, currentNode.Get(i), cb) + } else { + val := currentNode.Get(i).Str() + if val != "" { + it.fetchNode(pk, []byte(val), cb) + } + } + } + } + } +} diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index d74d129ac3..c89f2fbb7b 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -154,7 +154,7 @@ func TestTrieDeleteWithValue(t *testing.T) { } -func TestTrieIterator(t *testing.T) { +func TestTriePurge(t *testing.T) { _, trie := New() trie.Update("c", LONG_WORD) trie.Update("ca", LONG_WORD) @@ -171,16 +171,14 @@ func TestTrieIterator(t *testing.T) { } } -func TestHashes(t *testing.T) { +func TestTrieIt(t *testing.T) { _, trie := New() - trie.Update("cat", "dog") - trie.Update("ca", "dude") - trie.Update("doge", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") - trie.Update("dog", "test") - trie.Update("test", "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ") - fmt.Printf("%x\n", trie.Root) - trie.Delete("dog") - fmt.Printf("%x\n", trie.Root) - trie.Delete("test") - fmt.Printf("%x\n", trie.Root) + trie.Update("c", LONG_WORD) + trie.Update("ca", LONG_WORD) + trie.Update("cat", LONG_WORD) + + it := trie.NewIterator() + it.Each(func(key string, node *Value) { + fmt.Println(key, ":", node.Str()) + }) } From c1b09d639cc922c7aa322ac56cc4f400d76431b4 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 27 May 2014 10:38:31 +0200 Subject: [PATCH 0370/1237] Disamble tx data before adding it to PTx object --- ethpub/types.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethpub/types.go b/ethpub/types.go index af3cfe2cd8..348ae3f259 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -71,9 +71,11 @@ func NewPTx(tx *ethchain.Transaction) *PTx { hash := hex.EncodeToString(tx.Hash()) receiver := hex.EncodeToString(tx.Recipient) sender := hex.EncodeToString(tx.Sender()) + data := strings.Join(ethchain.Disassemble(tx.Data), "\n") + isContract := len(tx.Data) > 0 - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: hex.EncodeToString(tx.Data), Sender: sender} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender} } func (self *PTx) ToString() string { From aba3066658a32723543f9e4eda74a14ef140fc0e Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 13:10:18 +0200 Subject: [PATCH 0371/1237] Changed debug hook and added state iterator --- ethchain/closure.go | 2 +- ethchain/state.go | 5 +++++ ethchain/vm.go | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 59194e4e82..e65cfd2525 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -72,7 +72,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args diff --git a/ethchain/state.go b/ethchain/state.go index e209e0e2ff..5af748e00e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -49,6 +49,11 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } +func (s *State) EachStorage(cb ethutil.EachCallback) { + it := s.trie.NewIterator() + it.Each(cb) +} + func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { diff --git a/ethchain/vm.go b/ethchain/vm.go index e025920f30..0d9e8599e6 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -543,7 +543,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - hook(step-1, op, mem, stack) + hook(step-1, op, mem, stack, closure.Object()) } } } From 4eb1771e67ee2c66d5fb86c2b5961d84e40f7dd0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 13:32:31 +0200 Subject: [PATCH 0372/1237] Hooks can now quit the vm --- ethchain/closure.go | 2 +- ethchain/vm.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index e65cfd2525..c935ed50a6 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -72,7 +72,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } -type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) +type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { c.Args = args diff --git a/ethchain/vm.go b/ethchain/vm.go index 0d9e8599e6..9821a839a7 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -543,7 +543,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - hook(step-1, op, mem, stack, closure.Object()) + if !hook(step-1, op, mem, stack, closure.Object()) { + return nil, nil + } } } } From a4285331601d9d77458d0d714dd110144c796023 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 27 May 2014 16:10:18 +0200 Subject: [PATCH 0373/1237] bump --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 40ab3aa696..a7c318e52c 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC9"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC10"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") From 98d4b511207404a133ceca37467f9a1c32c20bc5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:03:12 +0200 Subject: [PATCH 0374/1237] Changed opcode names --- ethchain/asm.go | 4 +- ethchain/types.go | 333 +++++++++++++++++++++++----------------------- 2 files changed, 165 insertions(+), 172 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index 492be09991..430a894506 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,9 +21,9 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: + 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) - a := int64(op) - int64(oPUSH1) + 1 + a := int64(op) - int64(PUSH1) + 1 data := script[pc.Int64() : pc.Int64()+a] val := ethutil.BigD(data) diff --git a/ethchain/types.go b/ethchain/types.go index e0fdd5191c..2938711432 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -5,206 +5,206 @@ type OpCode int // Op codes const ( // 0x0 range - arithmetic ops - oSTOP = 0x00 - oADD = 0x01 - oMUL = 0x02 - oSUB = 0x03 - oDIV = 0x04 - oSDIV = 0x05 - oMOD = 0x06 - oSMOD = 0x07 - oEXP = 0x08 - oNEG = 0x09 - oLT = 0x0a - oGT = 0x0b - oEQ = 0x0c - oNOT = 0x0d + STOP = 0x00 + ADD = 0x01 + MUL = 0x02 + SUB = 0x03 + DIV = 0x04 + SDIV = 0x05 + MOD = 0x06 + SMOD = 0x07 + EXP = 0x08 + NEG = 0x09 + LT = 0x0a + GT = 0x0b + EQ = 0x0c + NOT = 0x0d // 0x10 range - bit ops - oAND = 0x10 - oOR = 0x11 - oXOR = 0x12 - oBYTE = 0x13 + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 // 0x20 range - crypto - oSHA3 = 0x20 + SHA3 = 0x20 // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATALOAD = 0x35 - oCALLDATASIZE = 0x36 - oGASPRICE = 0x37 + ADDRESS = 0x30 + BALANCE = 0x31 + ORIGIN = 0x32 + CALLER = 0x33 + CALLVALUE = 0x34 + CALLDATALOAD = 0x35 + CALLDATASIZE = 0x36 + GASPRICE = 0x37 // 0x40 range - block operations - oPREVHASH = 0x40 - oCOINBASE = 0x41 - oTIMESTAMP = 0x42 - oNUMBER = 0x43 - oDIFFICULTY = 0x44 - oGASLIMIT = 0x45 + PREVHASH = 0x40 + COINBASE = 0x41 + TIMESTAMP = 0x42 + NUMBER = 0x43 + DIFFICULTY = 0x44 + GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - oPOP = 0x51 - oDUP = 0x52 - oSWAP = 0x53 - oMLOAD = 0x54 - oMSTORE = 0x55 - oMSTORE8 = 0x56 - oSLOAD = 0x57 - oSSTORE = 0x58 - oJUMP = 0x59 - oJUMPI = 0x5a - oPC = 0x5b - oMSIZE = 0x5c + POP = 0x51 + DUP = 0x52 + SWAP = 0x53 + MLOAD = 0x54 + MSTORE = 0x55 + MSTORE8 = 0x56 + SLOAD = 0x57 + SSTORE = 0x58 + JUMP = 0x59 + JUMPI = 0x5a + PC = 0x5b + MSIZE = 0x5c // 0x60 range - oPUSH1 = 0x60 - oPUSH2 = 0x61 - oPUSH3 = 0x62 - oPUSH4 = 0x63 - oPUSH5 = 0x64 - oPUSH6 = 0x65 - oPUSH7 = 0x66 - oPUSH8 = 0x67 - oPUSH9 = 0x68 - oPUSH10 = 0x69 - oPUSH11 = 0x6a - oPUSH12 = 0x6b - oPUSH13 = 0x6c - oPUSH14 = 0x6d - oPUSH15 = 0x6e - oPUSH16 = 0x6f - oPUSH17 = 0x70 - oPUSH18 = 0x71 - oPUSH19 = 0x72 - oPUSH20 = 0x73 - oPUSH21 = 0x74 - oPUSH22 = 0x75 - oPUSH23 = 0x76 - oPUSH24 = 0x77 - oPUSH25 = 0x78 - oPUSH26 = 0x79 - oPUSH27 = 0x7a - oPUSH28 = 0x7b - oPUSH29 = 0x7c - oPUSH30 = 0x7d - oPUSH31 = 0x7e - oPUSH32 = 0x7f + PUSH1 = 0x60 + PUSH2 = 0x61 + PUSH3 = 0x62 + PUSH4 = 0x63 + PUSH5 = 0x64 + PUSH6 = 0x65 + PUSH7 = 0x66 + PUSH8 = 0x67 + PUSH9 = 0x68 + PUSH10 = 0x69 + PUSH11 = 0x6a + PUSH12 = 0x6b + PUSH13 = 0x6c + PUSH14 = 0x6d + PUSH15 = 0x6e + PUSH16 = 0x6f + PUSH17 = 0x70 + PUSH18 = 0x71 + PUSH19 = 0x72 + PUSH20 = 0x73 + PUSH21 = 0x74 + PUSH22 = 0x75 + PUSH23 = 0x76 + PUSH24 = 0x77 + PUSH25 = 0x78 + PUSH26 = 0x79 + PUSH27 = 0x7a + PUSH28 = 0x7b + PUSH29 = 0x7c + PUSH30 = 0x7d + PUSH31 = 0x7e + PUSH32 = 0x7f // 0xf0 range - closures - oCREATE = 0xf0 - oCALL = 0xf1 - oRETURN = 0xf2 + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 // 0x70 range - other - oLOG = 0xfe // XXX Unofficial - oSUICIDE = 0xff + LOG = 0xfe // XXX Unofficial + SUICIDE = 0xff ) // Since the opcodes aren't all in order we can't use a regular slice var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops - oSTOP: "STOP", - oADD: "ADD", - oMUL: "MUL", - oSUB: "SUB", - oDIV: "DIV", - oSDIV: "SDIV", - oMOD: "MOD", - oSMOD: "SMOD", - oEXP: "EXP", - oNEG: "NEG", - oLT: "LT", - oGT: "GT", - oEQ: "EQ", - oNOT: "NOT", + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NEG: "NEG", + LT: "LT", + GT: "GT", + EQ: "EQ", + NOT: "NOT", // 0x10 range - bit ops - oAND: "AND", - oOR: "OR", - oXOR: "XOR", - oBYTE: "BYTE", + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", // 0x20 range - crypto - oSHA3: "SHA3", + SHA3: "SHA3", // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATALOAD: "CALLDATALOAD", - oCALLDATASIZE: "CALLDATASIZE", - oGASPRICE: "TXGASPRICE", + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + GASPRICE: "TXGASPRICE", // 0x40 range - block operations - oPREVHASH: "PREVHASH", - oCOINBASE: "COINBASE", - oTIMESTAMP: "TIMESTAMP", - oNUMBER: "NUMBER", - oDIFFICULTY: "DIFFICULTY", - oGASLIMIT: "GASLIMIT", + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution - oDUP: "DUP", - oSWAP: "SWAP", - oMLOAD: "MLOAD", - oMSTORE: "MSTORE", - oMSTORE8: "MSTORE8", - oSLOAD: "SLOAD", - oSSTORE: "SSTORE", - oJUMP: "JUMP", - oJUMPI: "JUMPI", - oPC: "PC", - oMSIZE: "MSIZE", + DUP: "DUP", + SWAP: "SWAP", + MLOAD: "MLOAD", + MSTORE: "MSTORE", + MSTORE8: "MSTORE8", + SLOAD: "SLOAD", + SSTORE: "SSTORE", + JUMP: "JUMP", + JUMPI: "JUMPI", + PC: "PC", + MSIZE: "MSIZE", // 0x60 range - push - oPUSH1: "PUSH1", - oPUSH2: "PUSH2", - oPUSH3: "PUSH3", - oPUSH4: "PUSH4", - oPUSH5: "PUSH5", - oPUSH6: "PUSH6", - oPUSH7: "PUSH7", - oPUSH8: "PUSH8", - oPUSH9: "PUSH9", - oPUSH10: "PUSH10", - oPUSH11: "PUSH11", - oPUSH12: "PUSH12", - oPUSH13: "PUSH13", - oPUSH14: "PUSH14", - oPUSH15: "PUSH15", - oPUSH16: "PUSH16", - oPUSH17: "PUSH17", - oPUSH18: "PUSH18", - oPUSH19: "PUSH19", - oPUSH20: "PUSH20", - oPUSH21: "PUSH21", - oPUSH22: "PUSH22", - oPUSH23: "PUSH23", - oPUSH24: "PUSH24", - oPUSH25: "PUSH25", - oPUSH26: "PUSH26", - oPUSH27: "PUSH27", - oPUSH28: "PUSH28", - oPUSH29: "PUSH29", - oPUSH30: "PUSH30", - oPUSH31: "PUSH31", - oPUSH32: "PUSH32", + PUSH1: "PUSH1", + PUSH2: "PUSH2", + PUSH3: "PUSH3", + PUSH4: "PUSH4", + PUSH5: "PUSH5", + PUSH6: "PUSH6", + PUSH7: "PUSH7", + PUSH8: "PUSH8", + PUSH9: "PUSH9", + PUSH10: "PUSH10", + PUSH11: "PUSH11", + PUSH12: "PUSH12", + PUSH13: "PUSH13", + PUSH14: "PUSH14", + PUSH15: "PUSH15", + PUSH16: "PUSH16", + PUSH17: "PUSH17", + PUSH18: "PUSH18", + PUSH19: "PUSH19", + PUSH20: "PUSH20", + PUSH21: "PUSH21", + PUSH22: "PUSH22", + PUSH23: "PUSH23", + PUSH24: "PUSH24", + PUSH25: "PUSH25", + PUSH26: "PUSH26", + PUSH27: "PUSH27", + PUSH28: "PUSH28", + PUSH29: "PUSH29", + PUSH30: "PUSH30", + PUSH31: "PUSH31", + PUSH32: "PUSH32", // 0xf0 range - oCREATE: "CREATE", - oCALL: "CALL", - oRETURN: "RETURN", + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", // 0x70 range - other - oLOG: "LOG", - oSUICIDE: "SUICIDE", + LOG: "LOG", + SUICIDE: "SUICIDE", } func (o OpCode) String() string { @@ -322,10 +322,3 @@ func IsOpCode(s string) bool { } return false } - -func AppendScript(init, script []byte) []byte { - s := append(init, byte(oRETURN)) - s = append(s, script...) - - return s -} From 1c01e9c0958d2706c522602663da7cfc40a88600 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:03:40 +0200 Subject: [PATCH 0375/1237] 10 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 081d9481e6..017b770388 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC9". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC10". 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. From 73761f7af64432b6946934c3b1db646d8e99ef07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:05:46 +0200 Subject: [PATCH 0376/1237] Closure call now returns the total usage as well * Return the used gas value based on the UseGas and ReturnGas --- ethchain/closure.go | 22 ++++- ethchain/state_manager.go | 38 +++++--- ethchain/transaction_pool.go | 18 +++- ethchain/vm.go | 164 +++++++++++++++++------------------ 4 files changed, 138 insertions(+), 104 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index c935ed50a6..f2b46e461b 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -22,8 +22,7 @@ type Closure struct { Script []byte State *State - Gas *big.Int - Price *big.Int + Gas, UsedGas, Price *big.Int Args []byte } @@ -74,10 +73,12 @@ func (c *Closure) Address() []byte { type DebugHook func(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool -func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, error) { +func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, error) { c.Args = args - return vm.RunClosure(c, hook) + ret, err := vm.RunClosure(c, hook) + + return ret, c.UsedGas, err } func (c *Closure) Return(ret []byte) []byte { @@ -93,10 +94,23 @@ func (c *Closure) Return(ret []byte) []byte { return ret } +func (c *Closure) UseGas(gas *big.Int) bool { + if c.Gas.Cmp(gas) < 0 { + return false + } + + // Sub the amount of gas from the remaining + c.Gas.Sub(c.Gas, gas) + c.UsedGas.Add(c.UsedGas, gas) + + return true +} + // Implement the Callee interface func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) + c.UsedGas.Sub(c.UsedGas, gas) } func (c *Closure) Object() *StateObject { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 2d2a32e2fe..1a9e9f6010 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -106,7 +106,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra usedGas, err := sm.ApplyTransaction(state, block, tx) if err != nil { ethutil.Config.Log.Infoln(err) - continue + //continue } accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) @@ -119,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra return receipts, txs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, error) { +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { /* Applies transactions to the given state and creates new state objects where needed. @@ -129,9 +129,17 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac assume there's a return value. The return value will be set to the script section of the state object. */ - totalGasUsed := big.NewInt(0) + var ( + addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } + gas = new(big.Int) + script []byte + ) + totalGasUsed = big.NewInt(0) + // Apply the transaction to the current state - err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + addTotalGas(gas) + if tx.CreatesContract() { if err == nil { // Create a new state object and the transaction @@ -141,30 +149,32 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac // Evaluate the initialization script // and use the return value as the // script section for the state object. - script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) + script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) + addTotalGas(gas) + if err != nil { - return nil, fmt.Errorf("[STATE] Error during init script run %v", err) + err = fmt.Errorf("[STATE] Error during init script run %v", err) + return } contract.script = script state.UpdateStateObject(contract) } else { - return nil, fmt.Errorf("[STATE] Unable to create contract") + err = fmt.Errorf("[STATE] Unable to create contract") } } else { - return nil, fmt.Errorf("[STATE] contract creation tx:", err) + err = fmt.Errorf("[STATE] contract creation tx: %v", err) } } else { // Find the state object at the "recipient" address. If // there's an object attempt to run the script. stateObject := state.GetStateObject(tx.Recipient) if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - } else if err != nil { - return nil, fmt.Errorf("[STATE] process:", err) + _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) + addTotalGas(gas) } } - return totalGasUsed, nil + return } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -349,7 +359,7 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { account := state.GetAccount(tx.Sender()) err = account.ConvertGas(tx.Gas, tx.GasPrice) @@ -369,7 +379,7 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj Value: tx.Value, //Price: tx.GasPrice, }) - ret, err = closure.Call(vm, tx.Data, nil) + ret, gas, err = closure.Call(vm, tx.Data, nil) // Update the account (refunds) state.UpdateStateObject(account) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ee026ffdd9..7198026a8e 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,28 +91,37 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) { defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) err = fmt.Errorf("%v", r) } }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + // Get the sender sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { - return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + err = fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + return } + txTotalBytes := big.NewInt(int64(len(tx.Data))) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) if sender.Amount.Cmp(totAmount) < 0 { - return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return } - //fmt.Println(tx) // Get the receiver receiver := state.GetAccount(tx.Recipient) @@ -120,6 +129,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + addGas(GasTx) // Subtract the fee sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) } else { diff --git a/ethchain/vm.go b/ethchain/vm.go index 9821a839a7..29eb4aaf58 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -21,11 +21,10 @@ var ( GasTx = big.NewInt(500) ) -func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { +func CalculateTxGas(initSize *big.Int) *big.Int { totalGas := new(big.Int) - totalGas.Add(totalGas, GasCreate) - txTotalBytes := new(big.Int).Add(initSize, scriptSize) + txTotalBytes := new(big.Int).Set(initSize) txTotalBytes.Div(txTotalBytes, ethutil.Big32) totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore)) @@ -92,12 +91,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc := big.NewInt(0) // Current step count step := 0 + prevStep := 0 if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } for { + prevStep = step // The base for all big integer arithmetic base := new(big.Int) @@ -111,16 +112,16 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } gas := new(big.Int) - useGas := func(amount *big.Int) { + setStepGasUsage := func(amount *big.Int) { gas.Add(gas, amount) } switch op { - case oSHA3: - useGas(GasSha) - case oSLOAD: - useGas(GasSLoad) - case oSSTORE: + case SHA3: + setStepGasUsage(GasSha) + case SLOAD: + setStepGasUsage(GasSLoad) + case SSTORE: var mult *big.Int y, x := stack.Peekn() val := closure.GetMem(x) @@ -131,67 +132,64 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - useGas(new(big.Int).Mul(mult, GasSStore)) - case oBALANCE: - useGas(GasBalance) - case oCREATE: + setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) + case BALANCE: + setStepGasUsage(GasBalance) + case CREATE: require(3) args := stack.Get(big.NewInt(3)) initSize := new(big.Int).Add(args[1], args[0]) - useGas(CalculateTxGas(initSize, ethutil.Big0)) - case oCALL: - useGas(GasCall) - case oMLOAD, oMSIZE, oMSTORE8, oMSTORE: - useGas(GasMemory) + setStepGasUsage(CalculateTxGas(initSize)) + case CALL: + setStepGasUsage(GasCall) + case MLOAD, MSIZE, MSTORE8, MSTORE: + setStepGasUsage(GasMemory) default: - useGas(GasStep) + setStepGasUsage(GasStep) } - if closure.Gas.Cmp(gas) < 0 { + if !closure.UseGas(gas) { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } - // Sub the amount of gas from the remaining - closure.Gas.Sub(closure.Gas, gas) - switch op { - case oLOG: + case LOG: stack.Print() mem.Print() // 0x20 range - case oADD: + case ADD: require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 base.Add(x, y) // Pop result back on the stack stack.Push(base) - case oSUB: + case SUB: require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 base.Sub(x, y) // Pop result back on the stack stack.Push(base) - case oMUL: + case MUL: require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 base.Mul(x, y) // Pop result back on the stack stack.Push(base) - case oDIV: + case DIV: require(2) x, y := stack.Popn() // floor(x / y) base.Div(x, y) // Pop result back on the stack stack.Push(base) - case oSDIV: + case SDIV: require(2) x, y := stack.Popn() // n > 2**255 @@ -208,12 +206,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // Push result on to the stack stack.Push(z) - case oMOD: + case MOD: require(2) x, y := stack.Popn() base.Mod(x, y) stack.Push(base) - case oSMOD: + case SMOD: require(2) x, y := stack.Popn() // n > 2**255 @@ -230,17 +228,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // Push result on to the stack stack.Push(z) - case oEXP: + case EXP: require(2) x, y := stack.Popn() base.Exp(x, y, Pow256) stack.Push(base) - case oNEG: + case NEG: require(1) base.Sub(Pow256, stack.Pop()) stack.Push(base) - case oLT: + case LT: require(2) x, y := stack.Popn() // x < y @@ -249,7 +247,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oGT: + case GT: require(2) x, y := stack.Popn() // x > y @@ -258,7 +256,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oEQ: + case EQ: require(2) x, y := stack.Popn() // x == y @@ -267,7 +265,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oNOT: + case NOT: require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) == 0 { @@ -277,7 +275,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // 0x10 range - case oAND: + case AND: require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { @@ -286,7 +284,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigFalse) } - case oOR: + case OR: require(2) x, y := stack.Popn() if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { @@ -294,11 +292,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } - case oXOR: + case XOR: require(2) x, y := stack.Popn() stack.Push(base.Xor(x, y)) - case oBYTE: + case BYTE: require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { @@ -308,92 +306,92 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } // 0x20 range - case oSHA3: + case SHA3: require(2) size, offset := stack.Popn() data := mem.Get(offset.Int64(), size.Int64()) stack.Push(ethutil.BigD(data)) // 0x30 range - case oADDRESS: + case ADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) - case oBALANCE: + case BALANCE: stack.Push(closure.object.Amount) - case oORIGIN: + case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) - case oCALLER: + case CALLER: stack.Push(ethutil.BigD(closure.Callee().Address())) - case oCALLVALUE: + case CALLVALUE: stack.Push(vm.vars.Value) - case oCALLDATALOAD: + case CALLDATALOAD: require(1) offset := stack.Pop().Int64() val := closure.Args[offset : offset+32] stack.Push(ethutil.BigD(val)) - case oCALLDATASIZE: + case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) - case oGASPRICE: + case GASPRICE: stack.Push(closure.Price) // 0x40 range - case oPREVHASH: + case PREVHASH: stack.Push(ethutil.BigD(vm.vars.PrevHash)) - case oCOINBASE: + case COINBASE: stack.Push(ethutil.BigD(vm.vars.Coinbase)) - case oTIMESTAMP: + case TIMESTAMP: stack.Push(big.NewInt(vm.vars.Time)) - case oNUMBER: + case NUMBER: stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) - case oDIFFICULTY: + case DIFFICULTY: stack.Push(vm.vars.Diff) - case oGASLIMIT: + case GASLIMIT: // TODO stack.Push(big.NewInt(0)) // 0x50 range - case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: - a := big.NewInt(int64(op) - int64(oPUSH1) + 1) + 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: + a := big.NewInt(int64(op) - int64(PUSH1) + 1) pc.Add(pc, ethutil.Big1) data := closure.Gets(pc, a) val := ethutil.BigD(data.Bytes()) // Push value to stack stack.Push(val) pc.Add(pc, a.Sub(a, big.NewInt(1))) - step++ - case oPOP: + step += int(op) - int(PUSH1) + 1 + case POP: require(1) stack.Pop() - case oDUP: + case DUP: require(1) stack.Push(stack.Peek()) - case oSWAP: + case SWAP: require(2) x, y := stack.Popn() stack.Push(y) stack.Push(x) - case oMLOAD: + case MLOAD: require(1) offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) - case oMSTORE: // Store the value at stack top-1 in to memory at location stack top + case MSTORE: // Store the value at stack top-1 in to memory at location stack top require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - case oMSTORE8: + case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - case oSLOAD: + case SLOAD: require(1) loc := stack.Pop() val := closure.GetMem(loc) //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) - case oSSTORE: + case SSTORE: require(2) val, loc := stack.Popn() //fmt.Println("storing", val, "@", loc) @@ -401,13 +399,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - case oJUMP: + case JUMP: require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop //pc.Sub(pc, ethutil.Big1) continue - case oJUMPI: + case JUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { @@ -415,12 +413,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //pc.Sub(pc, ethutil.Big1) continue } - case oPC: + case PC: stack.Push(pc) - case oMSIZE: + case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) // 0x60 range - case oCREATE: + case CREATE: require(3) value := stack.Pop() @@ -439,9 +437,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - closure.Gas.Sub(closure.Gas, gas) + closure.UseGas(gas) + // Create the closure - closure := NewClosure(closure.callee, + c := NewClosure(closure.callee, closure.Object(), contract.initScript, vm.state, @@ -449,7 +448,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. - closure.Script, err = closure.Call(vm, nil, hook) + c.Script, _, err = c.Call(vm, nil, hook) + if err != nil { stack.Push(ethutil.BigFalse) @@ -460,7 +460,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.UpdateStateObject(contract) } - case oCALL: + case CALL: require(7) // Closure addr addr := stack.Pop() @@ -492,7 +492,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Copy gas = new(big.Int).Set(closure.Gas) } - closure.Gas.Sub(closure.Gas, gas) + closure.UseGas(gas) // Add the value to the state object contract.AddAmount(value) @@ -500,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Create a new callable closure closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, err := closure.Call(vm, args, hook) + ret, _, err := closure.Call(vm, args, hook) if err != nil { stack.Push(ethutil.BigFalse) // Reset the changes applied this object @@ -516,13 +516,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) } - case oRETURN: + case RETURN: require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) return closure.Return(ret), nil - case oSUICIDE: + case SUICIDE: require(1) receiver := vm.state.GetAccount(stack.Pop().Bytes()) @@ -532,7 +532,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.object.state.Purge() fallthrough - case oSTOP: // Stop the closure + case STOP: // Stop the closure return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) @@ -543,7 +543,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) if hook != nil { - if !hook(step-1, op, mem, stack, closure.Object()) { + if !hook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } } From 9988b1a04710e03ce7ed4b23393e2e90f06889f9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:06:09 +0200 Subject: [PATCH 0377/1237] Sort transactions based on the nonce * Added a transaction sorter --- ethchain/transaction.go | 28 ++++++++++++---------------- ethminer/miner.go | 5 ++++- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2c5615f991..2cb946b3bf 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -147,22 +147,6 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { if len(tx.Recipient) == 0 { tx.contractCreation = true } - - /* - // If the list is of length 10 it's a contract creation tx - if decoder.Len() == 10 { - tx.contractCreation = true - tx.Init = decoder.Get(6).Bytes() - - tx.v = byte(decoder.Get(7).Uint()) - tx.r = decoder.Get(8).Bytes() - tx.s = decoder.Get(9).Bytes() - } else { - tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - } - */ } func (tx *Transaction) String() string { @@ -228,3 +212,15 @@ func (self *Receipt) String() string { self.PostState, self.CumulativeGasUsed) } + +// Transaction slice type for basic sorting +type Transactions []*Transaction + +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +type TxByNonce struct{ Transactions } + +func (s TxByNonce) Less(i, j int) bool { + return s.Transactions[i].Nonce < s.Transactions[j].Nonce +} diff --git a/ethminer/miner.go b/ethminer/miner.go index 00e04cde2e..9396d33f99 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "sort" ) type Miner struct { @@ -12,7 +13,7 @@ type Miner struct { ethereum ethchain.EthManager coinbase []byte reactChan chan ethutil.React - txs []*ethchain.Transaction + txs ethchain.Transactions uncles []*ethchain.Block block *ethchain.Block powChan chan []byte @@ -132,6 +133,8 @@ func (self *Miner) mineNewBlock() { self.block.SetUncles(self.uncles) } + // Sort the transactions by nonce in case of odd network propagation + sort.Sort(ethchain.TxByNonce{self.txs}) // Accumulate all valid transaction and apply them to the new state receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs) self.txs = txs From cfb979b5e3274a14319bce14ee0481a4cfaa5f41 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 28 May 2014 12:15:43 +0200 Subject: [PATCH 0378/1237] Add contract addr if it's a contract creation tx --- ethpub/types.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethpub/types.go b/ethpub/types.go index 348ae3f259..87d4ef1126 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -70,6 +70,10 @@ type PTx struct { func NewPTx(tx *ethchain.Transaction) *PTx { hash := hex.EncodeToString(tx.Hash()) receiver := hex.EncodeToString(tx.Recipient) + + if receiver == "" { + receiver = hex.EncodeToString(tx.CreationAddress()) + } sender := hex.EncodeToString(tx.Sender()) data := strings.Join(ethchain.Disassemble(tx.Data), "\n") From 6e98e5709a68b1a84e9c3b391eab4a3546c4225d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 12:39:34 +0200 Subject: [PATCH 0379/1237] Set initial used gas --- ethchain/closure.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethchain/closure.go b/ethchain/closure.go index f2b46e461b..01fd5d7945 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -35,6 +35,7 @@ func NewClosure(callee, object *StateObject, script []byte, state *State, gas, p // and we don't want the transaction's values to change. c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) + c.UsedGas = new(big.Int) return c } From 65722aeeca0fed685a00d660ddd7bb667ac3be9b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 13:14:56 +0200 Subject: [PATCH 0380/1237] Added StringToBytesFunc --- ethchain/vm.go | 2 +- ethutil/bytes.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 29eb4aaf58..85136e4355 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -448,7 +448,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. - c.Script, _, err = c.Call(vm, nil, hook) + c.Script, gas, err = c.Call(vm, nil, hook) if err != nil { stack.Push(ethutil.BigFalse) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index b298675a29..075e40b4c4 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -88,3 +88,13 @@ func IsHex(str string) bool { l := len(str) return l >= 4 && l%2 == 0 && str[0:2] == "0x" } + +func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { + if str[0:2] == "0x" { + ret = FromHex(str[2:]) + } else { + ret = cb(str) + } + + return +} From a98e35d7a048850fb77fad49fff7364cf77a9bae Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 13:55:32 +0200 Subject: [PATCH 0381/1237] Length checking --- ethutil/bytes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 075e40b4c4..1c7a43af8f 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -90,7 +90,7 @@ func IsHex(str string) bool { } func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { - if str[0:2] == "0x" { + if len(str) > 1 && str[0:2] == "0x" { ret = FromHex(str[2:]) } else { ret = cb(str) From b695c82520548f62f65937731def1224c72dce48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 15:07:11 +0200 Subject: [PATCH 0382/1237] Fixes #60 --- ethchain/state_manager.go | 7 +++++-- ethchain/transaction_pool.go | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1a9e9f6010..a57377bee6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -105,8 +105,11 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra for _, tx := range txs { usedGas, err := sm.ApplyTransaction(state, block, tx) if err != nil { + if IsNonceErr(err) { + continue + } + ethutil.Config.Log.Infoln(err) - //continue } accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) @@ -116,7 +119,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra validTxs = append(validTxs, tx) } - return receipts, txs + return receipts, validTxs } func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 7198026a8e..ba2ffcef55 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -106,7 +106,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { - err = fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) + err = NonceError(tx.Nonce, sender.Nonce) return } @@ -235,7 +235,7 @@ func (pool *TxPool) RemoveInvalid(state *State) { tx := e.Value.(*Transaction) sender := state.GetAccount(tx.Sender()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce != tx.Nonce { + if err != nil || sender.Nonce >= tx.Nonce { pool.pool.Remove(e) } } From 8601604a09a5995525ea5604bfbb1f15b0d09c59 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 28 May 2014 15:48:23 +0200 Subject: [PATCH 0383/1237] Hooked up the Block Explorer to the Debugger so we can instantly debug made transactions --- ethpub/types.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index 87d4ef1126..de1149a26f 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -57,14 +57,16 @@ func (self *PBlock) GetTransaction(hash string) *PTx { type PTx struct { ref *ethchain.Transaction - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasPrice"` - Hash string `json:"hash"` - Address string `json:"address"` - Sender string `json:"sender"` - Data string `json:"data"` - Contract bool `json:"isContract"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Address string `json:"address"` + Sender string `json:"sender"` + RawData string `json:"rawData"` + Data string `json:"data"` + Contract bool `json:"isContract"` + CreatesContract bool `json:"createsContract"` } func NewPTx(tx *ethchain.Transaction) *PTx { @@ -75,11 +77,13 @@ func NewPTx(tx *ethchain.Transaction) *PTx { receiver = hex.EncodeToString(tx.CreationAddress()) } sender := hex.EncodeToString(tx.Sender()) + createsContract := tx.CreatesContract() + data := strings.Join(ethchain.Disassemble(tx.Data), "\n") isContract := len(tx.Data) > 0 - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)} } func (self *PTx) ToString() string { From 76a59274bfce73ec988131804c643be743d2b4d2 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 28 May 2014 16:19:25 +0200 Subject: [PATCH 0384/1237] Bump to RC11 --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 017b770388..8190c5f2d3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC10". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC11". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index a7c318e52c..fb270ce720 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -43,7 +43,7 @@ func ReadConfig(base string, logTypes LoggerType, id string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC10"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") From 4d987624867fc02a079d8355c28bad620db85f06 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 May 2014 23:16:54 +0200 Subject: [PATCH 0385/1237] Fixed state object gas return --- ethchain/closure.go | 8 ++++---- ethchain/vm.go | 12 +++++++++--- ethpub/pub.go | 13 ++++++++++++- ethutil/bytes.go | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 01fd5d7945..5c9c3e47c0 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -11,13 +11,13 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte GetMem(*big.Int) *ethutil.Value - SetStore(*big.Int, *ethutil.Value) + SetStorage(*big.Int, *ethutil.Value) N() *big.Int } // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee *StateObject + callee ClosureRef object *StateObject Script []byte State *State @@ -28,7 +28,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { +func NewClosure(callee ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -118,7 +118,7 @@ func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() *StateObject { +func (c *Closure) Callee() ClosureRef { return c.callee } diff --git a/ethchain/vm.go b/ethchain/vm.go index 85136e4355..9720d8be1d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -326,9 +326,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALLDATALOAD: require(1) offset := stack.Pop().Int64() - val := closure.Args[offset : offset+32] - stack.Push(ethutil.BigD(val)) + var data []byte + if len(closure.Args) >= int(offset+32) { + data = closure.Args[offset : offset+32] + } else { + data = []byte{0} + } + + stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) case GASPRICE: @@ -498,7 +504,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro contract.AddAmount(value) // Create a new callable closure - closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) ret, _, err := closure.Call(vm, args, hook) if err != nil { diff --git a/ethpub/pub.go b/ethpub/pub.go index b75d3abc85..5a9401d0d7 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "strings" ) type PEthereum struct { @@ -161,7 +162,17 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc if len(scriptStr) > 0 && scriptStr[0:2] == "0x" { scriptStr = scriptStr[2:len(scriptStr)] } - tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(scriptStr)) + + data := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) { + slice := strings.Split(s, "\n") + for _, dataItem := range slice { + d := ethutil.FormatData(dataItem) + ret = append(ret, d...) + } + return + }) + + tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) } acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 1c7a43af8f..bd0df68ecd 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "fmt" + "math/big" ) // Number to bytes @@ -98,3 +99,20 @@ func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { return } + +func FormatData(data string) []byte { + if len(data) == 0 { + return nil + } + // Simple stupid + d := new(big.Int) + if data[0:1] == "\"" && data[len(data)-1:] == "\"" { + d.SetBytes([]byte(data[1 : len(data)-1])) + } else if len(data) > 1 && data[:2] == "0x" { + d.SetBytes(FromHex(data[2:])) + } else { + d.SetString(data, 0) + } + + return BigToBytes(d, 256) +} From a2d01d6af8cace4ea0ef87662727659eaa1ff791 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 May 2014 02:05:57 +0200 Subject: [PATCH 0386/1237] Removed comments --- ethpub/pub.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 5a9401d0d7..6dd7798ae5 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -122,29 +122,6 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc var tx *ethchain.Transaction // Compile and assemble the given data if contractCreation { - /* - var initScript, mainScript []byte - var err error - if ethutil.IsHex(initStr) { - initScript = ethutil.FromHex(initStr[2:]) - } else { - initScript, err = ethutil.Compile(initStr) - if err != nil { - return nil, err - } - } - - if ethutil.IsHex(scriptStr) { - mainScript = ethutil.FromHex(scriptStr[2:]) - } else { - mainScript, err = ethutil.Compile(scriptStr) - if err != nil { - return nil, err - } - } - - script := ethchain.AppendScript(initScript, mainScript) - */ var script []byte var err error if ethutil.IsHex(scriptStr) { From e7097641e3987420429fe47efdb678c9e4cd9ba9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 May 2014 11:49:41 +0200 Subject: [PATCH 0387/1237] Support for namereg --- ethpub/pub.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 6dd7798ae5..6beab5cf9c 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -2,8 +2,10 @@ package ethpub import ( "encoding/hex" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "math/big" "strings" ) @@ -95,13 +97,29 @@ func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) } +var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010") + +func GetAddressFromNameReg(stateManager *ethchain.StateManager, name string) []byte { + recp := new(big.Int).SetBytes([]byte(name)) + object := stateManager.CurrentState().GetStateObject(namereg) + reg := object.GetStorage(recp) + + return reg.Bytes() +} + func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool if len(recipient) == 0 { contractCreation = true } else { - hash = ethutil.FromHex(recipient) + // Check if an address is stored by this address + addr := GetAddressFromNameReg(lib.stateManager, recipient) + if len(addr) > 0 { + hash = addr + } else { + hash = ethutil.FromHex(recipient) + } } var keyPair *ethutil.KeyPair From 9bb7633254f5ded891f1162783bc06c1b4d131a0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 May 2014 11:50:36 +0200 Subject: [PATCH 0388/1237] Removed fmt --- ethpub/pub.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 6beab5cf9c..a9a962f14e 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -2,7 +2,6 @@ package ethpub import ( "encoding/hex" - "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "math/big" From 8fcba0eb1e947061aadeea1059830dbcdfd2ef44 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 May 2014 23:54:48 +0200 Subject: [PATCH 0389/1237] fixed test --- ethchain/state_test.go | 1 - ethchain/vm_test.go | 2 +- peer.go | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 4cc3fdf75f..2921299536 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -1,7 +1,6 @@ package ethchain import ( - "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" "testing" diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 520f9a2ed7..518a88766d 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -62,7 +62,7 @@ func TestRun4(t *testing.T) { Diff: big.NewInt(256), }) var ret []byte - ret, e = callerClosure.Call(vm, nil, nil) + ret, _, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } diff --git a/peer.go b/peer.go index d613bf6ff0..3d140608b5 100644 --- a/peer.go +++ b/peer.go @@ -440,7 +440,7 @@ func (p *Peer) HandleInbound() { ethutil.Config.Log.Debugf("[PEER] Found canonical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { - ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) + //ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{}{})) From 99797858a692520b47c2ca767b433ca425637d2a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 11:47:23 +0200 Subject: [PATCH 0390/1237] Added coin base to pub block --- ethpub/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethpub/types.go b/ethpub/types.go index de1149a26f..4e7c44ed4a 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -16,6 +16,7 @@ type PBlock struct { Hash string `json:"hash"` Transactions string `json:"transactions"` Time int64 `json:"time"` + Coinbase string `json:"coinbase"` } // Creates a new QML Block from a chain block @@ -34,7 +35,7 @@ func NewPBlock(block *ethchain.Block) *PBlock { return nil } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} } func (self *PBlock) ToString() string { From 15e0093e13dde98fb9ff3251203313ab4f0eacd4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 11:48:23 +0200 Subject: [PATCH 0391/1237] Fixed issue where the client could crash when sending malformed data --- peer.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/peer.go b/peer.go index 3d140608b5..60f2de7114 100644 --- a/peer.go +++ b/peer.go @@ -450,9 +450,11 @@ func (p *Peer) HandleInbound() { //ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain - lastHash := msg.Data.Get(l - 1) - //log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) - p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) + if l > 0 { + lastHash := msg.Data.Get(l - 1) + //log.Printf("Sending not in chain with hash %x\n", lastHash.AsRaw()) + p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) + } } case ethwire.MsgNotInChainTy: ethutil.Config.Log.Debugf("Not in chain: %x\n", msg.Data.Get(0).Bytes()) From 6c91ffcfbe1a7b469dc6a8a2676959f0000c925a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 11:48:37 +0200 Subject: [PATCH 0392/1237] Do not panic, but return nil instead --- ethutil/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/value.go b/ethutil/value.go index 83600abc2c..c86c24a7a7 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -176,7 +176,7 @@ func (val *Value) Get(idx int) *Value { } if idx < 0 { - panic("negative idx for Value Get") + return NewValue(nil) } return NewValue(d[idx]) From f382221b28ab9e886263e37b1eab9c7924a6a0dc Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 13:04:08 +0200 Subject: [PATCH 0393/1237] Broadcast "peerList" event upon removing or adding peers --- ethereum.go | 22 +++++++++++++++++++--- peer.go | 9 +-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ethereum.go b/ethereum.go index 3a7202d535..6be989a10e 100644 --- a/ethereum.go +++ b/ethereum.go @@ -165,6 +165,8 @@ func (s *Ethereum) AddPeer(conn net.Conn) { ethutil.Config.Log.Debugf("[SERV] Max connected peers reached. Not adding incoming peer.") } } + + s.reactor.Post("peerList", s.peers) } func (s *Ethereum) ProcessPeerList(addrs []string) { @@ -303,12 +305,26 @@ func (s *Ethereum) Peers() *list.List { } func (s *Ethereum) reapPeers() { + eachPeer(s.peers, func(p *Peer, e *list.Element) { + if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { + s.removePeerElement(e) + } + }) +} + +func (s *Ethereum) removePeerElement(e *list.Element) { s.peerMut.Lock() defer s.peerMut.Unlock() - eachPeer(s.peers, func(p *Peer, e *list.Element) { - if atomic.LoadInt32(&p.disconnect) == 1 || (p.inbound && (time.Now().Unix()-p.lastPong) > int64(5*time.Minute)) { - s.peers.Remove(e) + s.peers.Remove(e) + + s.reactor.Post("peerList", s.peers) +} + +func (s *Ethereum) RemovePeer(p *Peer) { + eachPeer(s.peers, func(peer *Peer, e *list.Element) { + if peer == p { + s.removePeerElement(e) } }) } diff --git a/peer.go b/peer.go index 60f2de7114..6853a949d1 100644 --- a/peer.go +++ b/peer.go @@ -2,7 +2,6 @@ package eth import ( "bytes" - "container/list" "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" @@ -523,13 +522,7 @@ func (p *Peer) Stop() { } // Pre-emptively remove the peer; don't wait for reaping. We already know it's dead if we are here - p.ethereum.peerMut.Lock() - defer p.ethereum.peerMut.Unlock() - eachPeer(p.ethereum.peers, func(peer *Peer, e *list.Element) { - if peer == p { - p.ethereum.peers.Remove(e) - } - }) + p.ethereum.RemovePeer(p) } func (p *Peer) pushHandshake() error { From e0b6a31613bc48bc5785f2bea655f832848392d8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 13:27:56 +0200 Subject: [PATCH 0394/1237] Buffered channel to fix not ready (blocking) --- ethminer/miner.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 9396d33f99..e7237bae2f 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -25,6 +25,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { 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 powQuitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread + quitChan := make(chan bool, 1) ethereum.Reactor().Subscribe("newBlock", reactChan) ethereum.Reactor().Subscribe("newTx:pre", reactChan) @@ -44,7 +45,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { reactChan: reactChan, powChan: powChan, powQuitChan: powQuitChan, - quitChan: make(chan bool), + quitChan: quitChan, } // Insert initial TXs in our little miner 'pool' From b15e03acd7d6184ad920292a10d9a2bbf2b59f00 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 16:57:40 +0200 Subject: [PATCH 0395/1237] Fixed issue with casting to smaller byte array --- ethutil/big.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethutil/big.go b/ethutil/big.go index 891d476ad8..1c25a4784a 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -49,6 +49,10 @@ func BigD(data []byte) *big.Int { func BigToBytes(num *big.Int, base int) []byte { ret := make([]byte, base/8) + if len(num.Bytes()) > base/8 { + return num.Bytes() + } + return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) } From 17c825f53a2676ffe17fd7731f8f550aebcb56b0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 16:57:58 +0200 Subject: [PATCH 0396/1237] Peer changes broadcasting and minor miner fix --- ethereum.go | 1 + ethminer/miner.go | 2 +- ethutil/config.go | 54 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/ethereum.go b/ethereum.go index 6be989a10e..d9281cd574 100644 --- a/ethereum.go +++ b/ethereum.go @@ -238,6 +238,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { s.peers.PushBack(peer) ethutil.Config.Log.Infof("[SERV] Adding peer (%s) %d / %d\n", addr, s.peers.Len(), s.MaxPeers) + s.reactor.Post("peerList", s.peers) } return nil diff --git a/ethminer/miner.go b/ethminer/miner.go index e7237bae2f..19ff5dd9ef 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -149,7 +149,7 @@ func (self *Miner) mineNewBlock() { // Find a valid nonce self.block.Nonce = self.pow.Search(self.block, self.powQuitChan) if self.block.Nonce != nil { - err := self.ethereum.StateManager().Process(self.block, true) + err := self.ethereum.StateManager().Process(self.block, false) if err != nil { ethutil.Config.Log.Infoln(err) } else { diff --git a/ethutil/config.go b/ethutil/config.go index fb270ce720..916b0d1862 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -22,26 +22,54 @@ type config struct { Identifier string } +const defaultConf = ` +id = "" +port = 30303 +upnp = true +maxpeer = 10 +rpc = false +rpcport = 8080 +` + var Config *config +func ApplicationFolder(base string) string { + usr, _ := user.Current() + p := path.Join(usr.HomeDir, base) + + if len(base) > 0 { + //Check if the logging directory already exists, create it if not + _, err := os.Stat(p) + if err != nil { + if os.IsNotExist(err) { + log.Printf("Debug logging directory %s doesn't exist, creating it\n", p) + os.Mkdir(p, 0777) + + } + } + + iniFilePath := path.Join(p, "conf.ini") + _, err = os.Stat(iniFilePath) + if err != nil && os.IsNotExist(err) { + file, err := os.Create(iniFilePath) + if err != nil { + fmt.Println(err) + } else { + assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets") + file.Write([]byte(defaultConf + "\nasset_path = " + assetPath)) + } + } + } + + return p +} + // Read config // // Initialize the global Config variable with default settings func ReadConfig(base string, logTypes LoggerType, id string) *config { if Config == nil { - usr, _ := user.Current() - path := path.Join(usr.HomeDir, base) - - if len(base) > 0 { - //Check if the logging directory already exists, create it if not - _, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it\n", path) - os.Mkdir(path, 0777) - } - } - } + path := ApplicationFolder(base) Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} Config.Identifier = id From 9e8127accba0d926436d3c0adf65b91149a94783 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 May 2014 19:51:19 +0200 Subject: [PATCH 0397/1237] woops --- ethutil/config.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index 916b0d1862..4f7820eed5 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -1,7 +1,9 @@ package ethutil import ( + "flag" "fmt" + "github.com/rakyll/globalconf" "log" "os" "os/user" @@ -20,6 +22,8 @@ type config struct { ClientString string Pubkey []byte Identifier string + + conf *globalconf.GlobalConf } const defaultConf = ` @@ -67,11 +71,12 @@ func ApplicationFolder(base string) string { // Read config // // Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType, id string) *config { +func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id string) *config { if Config == nil { path := ApplicationFolder(base) Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} + Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") @@ -90,6 +95,16 @@ func (c *config) SetClientString(str string) { Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) } +func (c *config) SetIdentifier(id string) { + c.Identifier = id + c.Set("id", id) +} + +func (c *config) Set(key, value string) { + f := &flag.Flag{Name: key, Value: &confValue{value}} + c.conf.Set("", f) +} + type LoggerType byte const ( @@ -190,3 +205,10 @@ func (log *Logger) Fatal(v ...interface{}) { os.Exit(1) } + +type confValue struct { + value string +} + +func (self confValue) String() string { return self.value } +func (self confValue) Set(s string) error { self.value = s; return nil } From fb6ff61730ed92ada68c9c5a5b3a6f9976a78161 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 2 Jun 2014 15:20:27 +0200 Subject: [PATCH 0398/1237] Implemented Public Peer interface --- ethchain/state_manager.go | 12 +++++++++++ ethpub/pub.go | 13 ++++++++++++ ethpub/types.go | 30 +++++++++++++++++++++++++++- peer.go | 42 ++++++++++++++++++++++++++++++++++----- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a57377bee6..8479e9f446 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -2,6 +2,7 @@ package ethchain import ( "bytes" + "container/list" "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -14,6 +15,16 @@ type BlockProcessor interface { ProcessBlock(block *Block) } +type Peer interface { + Inbound() bool + LastSend() time.Time + LastPong() int64 + Host() []byte + Port() uint16 + Version() string + Connected() *int32 +} + type EthManager interface { StateManager() *StateManager BlockChain() *BlockChain @@ -23,6 +34,7 @@ type EthManager interface { PeerCount() int IsMining() bool IsListening() bool + Peers() *list.List } type StateManager struct { diff --git a/ethpub/pub.go b/ethpub/pub.go index a9a962f14e..6d4c230add 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/eth-go/ethutil" "math/big" "strings" + "sync/atomic" ) type PEthereum struct { @@ -51,6 +52,18 @@ func (lib *PEthereum) GetPeerCount() int { return lib.manager.PeerCount() } +func (lib *PEthereum) GetPeers() []PPeer { + var peers []PPeer + for peer := lib.manager.Peers().Front(); peer != nil; peer = peer.Next() { + p := peer.Value.(ethchain.Peer) + if atomic.LoadInt32(p.Connected()) != 0 { + peers = append(peers, *NewPPeer(p)) + } + } + + return peers +} + func (lib *PEthereum) GetIsMining() bool { return lib.manager.IsMining() } diff --git a/ethpub/types.go b/ethpub/types.go index 4e7c44ed4a..1079f09b4f 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -3,12 +3,40 @@ package ethpub import ( "encoding/hex" "encoding/json" + "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" - _ "log" "strings" ) +// Peer interface exposed to QML + +type PPeer struct { + ref *ethchain.Peer + Inbound bool `json:"isInbound"` + LastSend int64 `json:"lastSend"` + LastPong int64 `json:"lastPong"` + Ip string `json:"ip"` + Port int `json:"port"` + Version string `json:"version"` + LastResponse string `json:"lastResponse"` +} + +func NewPPeer(peer ethchain.Peer) *PPeer { + if peer == nil { + return nil + } + + // TODO: There must be something build in to do this? + var ip []string + for _, i := range peer.Host() { + ip = append(ip, fmt.Sprintf("%d", i)) + } + ipAddress := strings.Join(ip, ".") + + return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port())} +} + // Block interface exposed to QML type PBlock struct { ref *ethchain.Block diff --git a/peer.go b/peer.go index 6853a949d1..71ad914614 100644 --- a/peer.go +++ b/peer.go @@ -129,7 +129,7 @@ type Peer struct { diverted bool blocksRequested int - Version string + version string } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -160,7 +160,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, - Version: ethutil.Config.ClientString, + version: ethutil.Config.ClientString, } // Set up the connection in another goroutine so we don't block the main thread @@ -184,6 +184,34 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { return p } +// Getters +func (p *Peer) Inbound() bool { + return p.inbound +} +func (p *Peer) LastSend() time.Time { + return p.lastSend +} +func (p *Peer) LastPong() int64 { + return p.lastPong +} +func (p *Peer) Host() []byte { + return p.host +} +func (p *Peer) Port() uint16 { + return p.port +} +func (p *Peer) Version() string { + return p.version +} +func (p *Peer) Connected() *int32 { + return &p.connected +} + +// Setters +func (p *Peer) SetVersion(version string) { + p.version = version +} + // Outputs any RLP encoded data to the peer func (p *Peer) QueueMessage(msg *ethwire.Msg) { if atomic.LoadInt32(&p.connected) != 1 { @@ -531,7 +559,7 @@ func (p *Peer) pushHandshake() error { pubkey := keyRing.PublicKey msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), p.Version, byte(p.caps), p.port, pubkey[1:], + uint32(ProtocolVersion), uint32(0), p.version, byte(p.caps), p.port, pubkey[1:], }) p.QueueMessage(msg) @@ -588,8 +616,12 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { // Set the peer's caps p.caps = Caps(c.Get(3).Byte()) + // Get a reference to the peers version - p.Version = c.Get(2).Str() + versionString := c.Get(2).Str() + if len(versionString) > 0 { + p.SetVersion(c.Get(2).Str()) + } // Catch up with the connected peer if !p.ethereum.IsUpToDate() { @@ -615,7 +647,7 @@ func (p *Peer) String() string { strConnectType = "disconnected" } - return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) + return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.version, p.caps) } func (p *Peer) SyncWithPeerToLastKnown() { From 2010fea0888991e978e715477516bc374bb29f01 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 3 Jun 2014 10:42:55 +0200 Subject: [PATCH 0399/1237] Added faux latency for peeroverview --- ethchain/state_manager.go | 1 + ethpub/pub.go | 1 + ethpub/types.go | 3 ++- peer.go | 20 ++++++++++++++++---- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8479e9f446..8e5ca1b834 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -22,6 +22,7 @@ type Peer interface { Host() []byte Port() uint16 Version() string + PingTime() string Connected() *int32 } diff --git a/ethpub/pub.go b/ethpub/pub.go index 6d4c230add..e00bd0dbef 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -56,6 +56,7 @@ func (lib *PEthereum) GetPeers() []PPeer { var peers []PPeer for peer := lib.manager.Peers().Front(); peer != nil; peer = peer.Next() { p := peer.Value.(ethchain.Peer) + // we only want connected peers if atomic.LoadInt32(p.Connected()) != 0 { peers = append(peers, *NewPPeer(p)) } diff --git a/ethpub/types.go b/ethpub/types.go index 1079f09b4f..4967eda492 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -20,6 +20,7 @@ type PPeer struct { Port int `json:"port"` Version string `json:"version"` LastResponse string `json:"lastResponse"` + Latency string `json:"latency"` } func NewPPeer(peer ethchain.Peer) *PPeer { @@ -34,7 +35,7 @@ func NewPPeer(peer ethchain.Peer) *PPeer { } ipAddress := strings.Join(ip, ".") - return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port())} + return &PPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime()} } // Block interface exposed to QML diff --git a/peer.go b/peer.go index 71ad914614..eed5bec308 100644 --- a/peer.go +++ b/peer.go @@ -130,6 +130,10 @@ type Peer struct { blocksRequested int version string + + // We use this to give some kind of pingtime to a node, not very accurate, could be improved. + pingTime time.Duration + pingStartTime time.Time } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -185,6 +189,9 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { } // Getters +func (p *Peer) PingTime() string { + return p.pingTime.String() +} func (p *Peer) Inbound() bool { return p.inbound } @@ -246,7 +253,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { // Outbound message handler. Outbound messages are handled here func (p *Peer) HandleOutbound() { // The ping timer. Makes sure that every 2 minutes a ping is send to the peer - pingTimer := time.NewTicker(2 * time.Minute) + pingTimer := time.NewTicker(30 * time.Second) serviceTimer := time.NewTicker(5 * time.Minute) out: @@ -255,12 +262,12 @@ out: // Main message queue. All outbound messages are processed through here case msg := <-p.outputQueue: p.writeMessage(msg) - p.lastSend = time.Now() // Ping timer sends a ping to the peer each 2 minutes case <-pingTimer.C: p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) + p.pingStartTime = time.Now() // Service timer takes care of peer broadcasting, transaction // posting or block posting @@ -290,8 +297,8 @@ clean: // Inbound handler. Inbound messages are received here and passed to the appropriate methods func (p *Peer) HandleInbound() { - for atomic.LoadInt32(&p.disconnect) == 0 { + // HMM? time.Sleep(500 * time.Millisecond) // Wait for a message from the peer @@ -319,6 +326,7 @@ func (p *Peer) HandleInbound() { // last pong so the peer handler knows this peer is still // active. p.lastPong = time.Now().Unix() + p.pingTime = time.Now().Sub(p.pingStartTime) case ethwire.MsgBlockTy: // Get all blocks and process them var block, lastBlock *ethchain.Block @@ -531,11 +539,15 @@ func (p *Peer) Start() { return } - // Run the outbound handler in a new goroutine go p.HandleOutbound() // Run the inbound handler in a new goroutine go p.HandleInbound() + // Wait a few seconds for startup and then ask for an initial ping + time.Sleep(2 * time.Second) + p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) + p.pingStartTime = time.Now() + } func (p *Peer) Stop() { From d7b882977c4289bc2aabb51e1cf6b3577bc02aca Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 3 Jun 2014 11:56:19 +0200 Subject: [PATCH 0400/1237] Make contract creation error more explicit by mentioning the sneder --- ethchain/state_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8e5ca1b834..f1c09b8192 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -178,7 +178,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac err = fmt.Errorf("[STATE] Unable to create contract") } } else { - err = fmt.Errorf("[STATE] contract creation tx: %v", err) + err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) } } else { // Find the state object at the "recipient" address. If From a56f78af67ba2b515f396d7a150ac86f6a75335f Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 4 Jun 2014 15:54:39 +0200 Subject: [PATCH 0401/1237] Implement getStateKeyVal for JS bindings. Gives JS the option to 'loop' over contract key/val storage --- ethpub/types.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/ethpub/types.go b/ethpub/types.go index 4967eda492..6893c7e09b 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -207,6 +207,31 @@ func (c *PStateObject) IsContract() bool { return false } +type KeyVal struct { + Key string + Value string +} + +func (c *PStateObject) StateKeyVal(asJson bool) interface{} { + var values []KeyVal + if c.object != nil { + c.object.State().EachStorage(func(name string, value *ethutil.Value) { + values = append(values, KeyVal{name, ethutil.Hex(value.Bytes())}) + }) + } + + if asJson { + valuesJson, err := json.Marshal(values) + if err != nil { + return nil + } + fmt.Println(string(valuesJson)) + return string(valuesJson) + } + + return values +} + func (c *PStateObject) Script() string { if c.object != nil { return strings.Join(ethchain.Disassemble(c.object.Script()), " ") From 1153fd9a0c9310ab70f9b20914071e0184e8020a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 6 Jun 2014 12:12:27 +0200 Subject: [PATCH 0402/1237] Added Douglas and Einstan --- ethutil/common.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ethutil/common.go b/ethutil/common.go index 771dfc723c..c7973eb929 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -7,13 +7,15 @@ import ( // The different number of units var ( - Ether = BigPow(10, 18) - Finney = BigPow(10, 15) - Szabo = BigPow(10, 12) - Shannon = BigPow(10, 9) - Babbage = BigPow(10, 6) - Ada = BigPow(10, 3) - Wei = big.NewInt(1) + Douglas = BigPow(10, 42) + Einstein = BigPow(10, 21) + Ether = BigPow(10, 18) + Finney = BigPow(10, 15) + Szabo = BigPow(10, 12) + Shannon = BigPow(10, 9) + Babbage = BigPow(10, 6) + Ada = BigPow(10, 3) + Wei = big.NewInt(1) ) // Currency to string @@ -21,6 +23,10 @@ var ( // Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { + case num.Cmp(Douglas) >= 0: + return fmt.Sprintf("%v Douglas", new(big.Int).Div(num, Douglas)) + case num.Cmp(Einstein) >= 0: + return fmt.Sprintf("%v Einstein", new(big.Int).Div(num, Einstein)) case num.Cmp(Ether) >= 0: return fmt.Sprintf("%v Ether", new(big.Int).Div(num, Ether)) case num.Cmp(Finney) >= 0: From c7d1924c344535c2d54265728bc2aa429215e595 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 9 Jun 2014 21:35:56 +0200 Subject: [PATCH 0403/1237] sha --- ethchain/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 9720d8be1d..955be847f0 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -309,7 +309,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) size, offset := stack.Popn() - data := mem.Get(offset.Int64(), size.Int64()) + data := ethutil.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) // 0x30 range From a51dfe89c05cc12b4a8483f683ff9f49b3a8f1bd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 9 Jun 2014 22:23:30 +0200 Subject: [PATCH 0404/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8190c5f2d3..b10a04c259 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC11". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC12". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index 4f7820eed5..e992bda12b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC11"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC12"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) From 771f64397fd8638e9a40a4b9ecc64a9b70d6f2e4 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 13:51:34 +0200 Subject: [PATCH 0405/1237] Stop peers when they don't respond to ping/pong. Might fix ethereum/go-ethereum#78 --- peer.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/peer.go b/peer.go index eed5bec308..9cc892d8ba 100644 --- a/peer.go +++ b/peer.go @@ -18,6 +18,8 @@ const ( outputBufferSize = 50 // Current protocol version ProtocolVersion = 17 + // Interval for ping/pong message + pingPongTimer = 30 * time.Second ) type DiscReason byte @@ -243,7 +245,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { err := ethwire.WriteMessage(p.conn, msg) if err != nil { - ethutil.Config.Log.Debugln("Can't send message:", err) + ethutil.Config.Log.Debugln("[PEER] Can't send message:", err) // Stop the client if there was an error writing to it p.Stop() return @@ -253,7 +255,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { // Outbound message handler. Outbound messages are handled here func (p *Peer) HandleOutbound() { // The ping timer. Makes sure that every 2 minutes a ping is send to the peer - pingTimer := time.NewTicker(30 * time.Second) + pingTimer := time.NewTicker(pingPongTimer) serviceTimer := time.NewTicker(5 * time.Minute) out: @@ -264,8 +266,14 @@ out: p.writeMessage(msg) p.lastSend = time.Now() - // Ping timer sends a ping to the peer each 2 minutes + // Ping timer case <-pingTimer.C: + timeSince := time.Since(time.Unix(p.lastPong, 0)) + if p.pingStartTime.IsZero() == false && timeSince > (pingPongTimer+10*time.Second) { + ethutil.Config.Log.Infof("[PEER] Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) + p.Stop() + return + } p.writeMessage(ethwire.NewMessage(ethwire.MsgPingTy, "")) p.pingStartTime = time.Now() @@ -563,6 +571,7 @@ func (p *Peer) Stop() { // Pre-emptively remove the peer; don't wait for reaping. We already know it's dead if we are here p.ethereum.RemovePeer(p) + ethutil.Config.Log.Debugln("[PEER] Stopped peer:", p.conn.RemoteAddr()) } func (p *Peer) pushHandshake() error { From 1b40f69ce5166fbe8a13709caf31f50107fa3bdf Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 14:59:38 +0200 Subject: [PATCH 0406/1237] Prevent peer stop crash by removing logging --- peer.go | 1 - 1 file changed, 1 deletion(-) diff --git a/peer.go b/peer.go index 9cc892d8ba..80975ff814 100644 --- a/peer.go +++ b/peer.go @@ -571,7 +571,6 @@ func (p *Peer) Stop() { // Pre-emptively remove the peer; don't wait for reaping. We already know it's dead if we are here p.ethereum.RemovePeer(p) - ethutil.Config.Log.Debugln("[PEER] Stopped peer:", p.conn.RemoteAddr()) } func (p *Peer) pushHandshake() error { From 2995d6c281b83f5bb055a22093b2b94e64c477d3 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 15:02:41 +0200 Subject: [PATCH 0407/1237] Validate minimum gasPrice and reject if not met --- ethchain/transaction_pool.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef55..d4175d9735 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -22,6 +22,7 @@ type TxMsgTy byte const ( TxPre = iota TxPost + minGasPrice = 1000000 ) type TxMsg struct { @@ -172,6 +173,12 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + if tx.IsContract() { + if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { + return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + } + } + // Increment the nonce making each tx valid only once to prevent replay // attacks From 2e6cf42011a4176a01f3e3f777cc1ddc4125511f Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:15:18 +0200 Subject: [PATCH 0408/1237] Fix BigMax to return the biggest number, not the smallest --- ethutil/big.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethutil/big.go b/ethutil/big.go index 1c25a4784a..7af6f74145 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -68,8 +68,8 @@ func BigCopy(src *big.Int) *big.Int { // Returns the maximum size big integer func BigMax(x, y *big.Int) *big.Int { if x.Cmp(y) <= 0 { - return x + return y } - return y + return x } From 753f749423df7d5fba55a4080383d215db8e0fc7 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:06 +0200 Subject: [PATCH 0409/1237] Implement CalcGasPrice for ethereum/go-ethereum#77 --- ethchain/block.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ethchain/block.go b/ethchain/block.go index 73e29f8783..780c608695 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -154,6 +154,35 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { return true } +func (block *Block) CalcGasLimit(parent *Block) *big.Int { + if block.Number == big.NewInt(0) { + return ethutil.BigPow(10, 6) + } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) + curInt := new(big.Int).Div(current.Num(), current.Denom()) + + result := new(big.Int).Add(previous, curInt) + result.Div(result, big.NewInt(1024)) + + min := ethutil.BigPow(10, 4) + + return ethutil.BigMax(min, result) + /* + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + */ + +} + func (block *Block) BlockInfo() BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) From 69044fe5774840a49de3f881a490db52e907affb Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:43 +0200 Subject: [PATCH 0410/1237] Refactor to use new method --- ethchain/block_chain.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5c..5e6ce46e1d 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -72,19 +72,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) - base := new(big.Int) - base2 := new(big.Int) - parentGL := bc.CurrentBlock.GasLimit - parentUsed := bc.CurrentBlock.GasUsed - - base.Mul(parentGL, big.NewInt(1024-1)) - base2.Mul(parentUsed, big.NewInt(6)) - base2.Div(base2, big.NewInt(5)) - base.Add(base, base2) - base.Div(base, big.NewInt(1024)) - - block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) + block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) } return block From bdc206885a1d9c730464f60ec65557403720be1e Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:23:32 +0200 Subject: [PATCH 0411/1237] Don't mine transactions if they would go over the GasLimit implements ethereum/go-ethereum#77 further. --- ethchain/error.go | 18 ++++++++++++++++++ ethchain/state_manager.go | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/ethchain/error.go b/ethchain/error.go index 8d37b0208a..29896bc592 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "math/big" ) // Parent error. In case a parent is unknown this error will be thrown @@ -43,6 +44,23 @@ func IsValidationErr(err error) bool { return ok } +type GasLimitErr struct { + Message string + Is, Max *big.Int +} + +func IsGasLimitErr(err error) bool { + _, ok := err.(*GasLimitErr) + + return ok +} +func (err *GasLimitErr) Error() string { + return err.Message +} +func GasLimitError(is, max *big.Int) *GasLimitErr { + return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} +} + type NonceErr struct { Message string Is, Exp uint64 diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b8192..aea5433ffd 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,6 +114,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + totalUsedGas := big.NewInt(0) for _, tx := range txs { usedGas, err := sm.ApplyTransaction(state, block, tx) @@ -121,6 +123,12 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra if IsNonceErr(err) { continue } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } ethutil.Config.Log.Infoln(err) } @@ -151,6 +159,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac script []byte ) totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() // Apply the transaction to the current state gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) @@ -190,6 +199,14 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } } + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + return } From 97cc76214350b3ef9b0c15f53d06c684e01ede37 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 10:28:18 +0200 Subject: [PATCH 0412/1237] Expose GasLimit to ethPub --- ethpub/types.go | 3 ++- ethutil/common.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index 6893c7e09b..40ac32a27a 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -46,6 +46,7 @@ type PBlock struct { Transactions string `json:"transactions"` Time int64 `json:"time"` Coinbase string `json:"coinbase"` + GasLimit string `json:"gasLimit"` } // Creates a new QML Block from a chain block @@ -64,7 +65,7 @@ func NewPBlock(block *ethchain.Block) *PBlock { return nil } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasLimit: block.GasLimit.String(), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} } func (self *PBlock) ToString() string { diff --git a/ethutil/common.go b/ethutil/common.go index c7973eb929..ddaf78f885 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -18,8 +18,8 @@ var ( Wei = big.NewInt(1) ) -// Currency to string // +// Currency to string // Returns a string representing a human readable format func CurrencyToString(num *big.Int) string { switch { From e090d131c38bef3c5f2d0f5e9fa28f5d0ed06659 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 11:40:40 +0200 Subject: [PATCH 0413/1237] Implemented counting of usedGas --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index aea5433ffd..6fb664e3d0 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -140,6 +140,9 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra validTxs = append(validTxs, tx) } + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + return receipts, validTxs } From 71ab5d52b692a42cc3af034e5ff1aab5b4b6477d Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 11:40:50 +0200 Subject: [PATCH 0414/1237] Exposed usedGas through ethPub --- ethpub/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethpub/types.go b/ethpub/types.go index 40ac32a27a..868fd2713f 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -47,6 +47,7 @@ type PBlock struct { Time int64 `json:"time"` Coinbase string `json:"coinbase"` GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` } // Creates a new QML Block from a chain block @@ -65,7 +66,7 @@ func NewPBlock(block *ethchain.Block) *PBlock { return nil } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasLimit: block.GasLimit.String(), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} } func (self *PBlock) ToString() string { From 1938bfcddfd2722880a692c59cad344b611711c8 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 16:16:57 +0200 Subject: [PATCH 0415/1237] Fix compare --- ethchain/block.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/block.go b/ethchain/block.go index 780c608695..fee4a2d59c 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -155,9 +155,10 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { } func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number == big.NewInt(0) { + if block.Number.Cmp(big.NewInt(0)) == 0 { return ethutil.BigPow(10, 6) } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) curInt := new(big.Int).Div(current.Num(), current.Denom()) From 9ff97a98a7449f10db71be88146c5a03d932c373 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:51:21 +0200 Subject: [PATCH 0416/1237] Namereg lookup fix --- ethpub/pub.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index e00bd0dbef..51426adc58 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -115,9 +115,13 @@ var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010") func GetAddressFromNameReg(stateManager *ethchain.StateManager, name string) []byte { recp := new(big.Int).SetBytes([]byte(name)) object := stateManager.CurrentState().GetStateObject(namereg) - reg := object.GetStorage(recp) + if object != nil { + reg := object.GetStorage(recp) - return reg.Bytes() + return reg.Bytes() + } + + return nil } func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { From 4d3209ad1d6ea6f7e4fc311c387392f23ebc7dde Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:23 +0200 Subject: [PATCH 0417/1237] Moved process transaction to state manager * Buy gas of the coinbase address --- ethchain/state_manager.go | 93 +++++++++++++++++++++++++++++++----- ethchain/transaction_pool.go | 29 +++++++---- 2 files changed, 100 insertions(+), 22 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b8192..e783ffdd82 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,15 +108,90 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + + fmt.Printf("state root after sender update %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + + fmt.Printf("state root after receiver update %x\n", state.Root()) + } + + state.UpdateStateObject(sender) + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction totalUsedGas := big.NewInt(0) + for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) if err != nil { if IsNonceErr(err) { continue @@ -135,7 +210,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra return receipts, validTxs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { /* Applies transactions to the given state and creates new state objects where needed. @@ -152,8 +227,9 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac ) totalGasUsed = big.NewInt(0) + ca := state.GetAccount(coinbase) // Apply the transaction to the current state - gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + gas, err = sm.ProcessTransaction(tx, ca, state, false) addTotalGas(gas) if tx.CreatesContract() { @@ -229,7 +305,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } // Process the transactions on to current block - sm.ApplyTransactions(state, parent, block.Transactions()) + sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -337,13 +413,6 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { base.Add(base, UncleInclusionReward) } - lastCumulGasUsed := big.NewInt(0) - for _, r := range block.Receipts() { - usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed) - usedGas.Add(usedGas, r.Tx.GasPrice) - base.Add(base, usedGas) - } - return base.Add(base, BlockReward) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef55..bc7bde7976 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -89,9 +89,11 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) } +/* // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -101,6 +103,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract gas = new(big.Int) addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) // Get the sender sender := state.GetAccount(tx.Sender()) @@ -110,28 +113,37 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract return } + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) + }() + txTotalBytes := big.NewInt(int64(len(tx.Data))) txTotalBytes.Div(txTotalBytes, ethutil.Big32) addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. - //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) + totAmount := new(big.Int).Add(tx.Value, rGas) if sender.Amount.Cmp(totAmount) < 0 { err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) return } + state.UpdateStateObject(sender) + fmt.Printf("state root after sender update %x\n", state.Root()) // Get the receiver receiver := state.GetAccount(tx.Recipient) - sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - addGas(GasTx) // Subtract the fee - sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) + sender.SubAmount(rGas) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -140,17 +152,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) + fmt.Printf("state root after receiver update %x\n", state.Root()) } - state.UpdateStateObject(sender) - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - // Notify all subscribers - pool.Ethereum.Reactor().Post("newTx:post", tx) - return } +*/ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from From 1bf6f8b4a6936d8ad14b345b2cfa4dc9d1f8a360 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:34 +0200 Subject: [PATCH 0418/1237] Added a buy gas method --- ethchain/state_object.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3e9c6df40b..a1dd531de9 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -108,10 +108,14 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -129,6 +133,17 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) BuyGas(gas, price *big.Int) error { + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, price) + + self.AddAmount(rGas) + + // TODO Do sub from TotalGasPool + // and check if enough left + return nil +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address @@ -153,14 +168,14 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() + c.Nonce = decoder.Get(0).Uint() + c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.ScriptHash = decoder.Get(3).Bytes() From 9ee6295c752a518603de01e4feaec787c61a5dcf Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:45 +0200 Subject: [PATCH 0419/1237] Minor changes --- ethchain/block_chain.go | 3 +-- ethminer/miner.go | 3 ++- peer.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5c..68ef9d47ed 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -271,7 +271,7 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", + "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", "6c386a4b26f73c802f34673f7248bb118f97424a", @@ -285,7 +285,6 @@ func AddTestNetFunds(block *Block) { account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } - log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { diff --git a/ethminer/miner.go b/ethminer/miner.go index 19ff5dd9ef..d054053914 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -137,7 +137,7 @@ func (self *Miner) mineNewBlock() { // Sort the transactions by nonce in case of odd network propagation sort.Sort(ethchain.TxByNonce{self.txs}) // Accumulate all valid transaction and apply them to the new state - receipts, txs := stateManager.ApplyTransactions(self.block.State(), self.block, self.txs) + receipts, txs := stateManager.ApplyTransactions(self.block.Coinbase, self.block.State(), self.block, self.txs) self.txs = txs // Set the transactions to the block so the new SHA3 can be calculated self.block.SetReceipts(receipts, txs) @@ -155,6 +155,7 @@ func (self *Miner) mineNewBlock() { } else { self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val}) ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", self.block.Hash()) + ethutil.Config.Log.Infoln(self.block) // Gather the new batch of transactions currently in the tx pool self.txs = self.ethereum.TxPool().CurrentTransactions() } diff --git a/peer.go b/peer.go index eed5bec308..acebd27565 100644 --- a/peer.go +++ b/peer.go @@ -17,7 +17,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 17 + ProtocolVersion = 20 ) type DiscReason byte @@ -603,7 +603,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data if c.Get(0).Uint() != ProtocolVersion { - ethutil.Config.Log.Debugln("Invalid peer version. Require protocol:", ProtocolVersion) + ethutil.Config.Log.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint()) p.Stop() return } From 3a9d7d318abb3cd01ecd012ae85da5e586436d65 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 10:07:27 +0200 Subject: [PATCH 0420/1237] log changes --- ethchain/transaction_pool.go | 6 ++++++ ethpub/pub.go | 2 -- ethutil/config.go | 12 +++++------- peer.go | 3 ++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index d4175d9735..103c305fea 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -162,6 +162,10 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return errors.New("[TXPL] No last block on the block chain") } + if len(tx.Recipient) != 20 { + return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) + } + // Get the sender //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) @@ -207,6 +211,8 @@ out: // Call blocking version. pool.addTransaction(tx) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) } diff --git a/ethpub/pub.go b/ethpub/pub.go index e00bd0dbef..5c636f7a2d 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -193,8 +193,6 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc if contractCreation { ethutil.Config.Log.Infof("Contract addr %x", tx.CreationAddress()) - } else { - ethutil.Config.Log.Infof("Tx hash %x", tx.Hash()) } return NewPReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil diff --git a/ethutil/config.go b/ethutil/config.go index e992bda12b..f935e8f75c 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,11 +75,11 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC12"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.12"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) - Config.SetClientString("/Ethereum(G)") + Config.SetClientString("Ethereum(G)") } return Config @@ -88,11 +88,9 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s // Set client string // func (c *config) SetClientString(str string) { - id := runtime.GOOS - if len(c.Identifier) > 0 { - id = c.Identifier - } - Config.ClientString = fmt.Sprintf("%s nv%s/%s", str, c.Ver, id) + os := runtime.GOOS + cust := c.Identifier + Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os) } func (c *config) SetIdentifier(id string) { diff --git a/peer.go b/peer.go index 80975ff814..c7591ac31a 100644 --- a/peer.go +++ b/peer.go @@ -153,6 +153,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { pubkey: pubkey, blocksRequested: 10, caps: ethereum.ServerCaps(), + version: ethutil.Config.ClientString, } } @@ -579,7 +580,7 @@ func (p *Peer) pushHandshake() error { pubkey := keyRing.PublicKey msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), p.version, byte(p.caps), p.port, pubkey[1:], + uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], }) p.QueueMessage(msg) From b855e5f7df194c84651d7cc7ee32d307a2fa0a2e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 11:19:32 +0200 Subject: [PATCH 0421/1237] Changed opcode numbers and added missing opcodes --- ethchain/state_manager.go | 8 +++---- ethchain/transaction.go | 4 +++- ethchain/types.go | 45 +++++++++++++++++++++++++++------------ ethchain/vm.go | 5 +++++ 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9631b55fe0..7b44ba3b89 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -166,13 +166,9 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj // Subtract the amount from the senders account sender.SubAmount(totAmount) - fmt.Printf("state root after sender update %x\n", state.Root()) - // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) - - fmt.Printf("state root after receiver update %x\n", state.Root()) } state.UpdateStateObject(sender) @@ -215,6 +211,8 @@ func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block * validTxs = append(validTxs, tx) } + fmt.Println("################# MADE\n", receipts, "\n############################") + // Update the total gas used for the block (to be mined) block.GasUsed = totalUsedGas @@ -250,6 +248,7 @@ func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *B // as it's data provider. contract := sm.MakeStateObject(state, tx) if contract != nil { + fmt.Println(Disassemble(contract.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -323,6 +322,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } + fmt.Println(block.Receipts()) // Process the transactions on to current block sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2cb946b3bf..32dbd83884 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" @@ -144,7 +145,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if len(tx.Recipient) == 0 { + + if bytes.Compare(tx.Recipient, ContractAddr) == 0 { tx.contractCreation = true } } diff --git a/ethchain/types.go b/ethchain/types.go index 2938711432..fdfd5792be 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -1,5 +1,9 @@ package ethchain +import ( + "fmt" +) + type OpCode int // Op codes @@ -37,7 +41,10 @@ const ( CALLVALUE = 0x34 CALLDATALOAD = 0x35 CALLDATASIZE = 0x36 - GASPRICE = 0x37 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3a // 0x40 range - block operations PREVHASH = 0x40 @@ -48,18 +55,19 @@ const ( GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - POP = 0x51 - DUP = 0x52 - SWAP = 0x53 - MLOAD = 0x54 - MSTORE = 0x55 - MSTORE8 = 0x56 - SLOAD = 0x57 - SSTORE = 0x58 - JUMP = 0x59 - JUMPI = 0x5a - PC = 0x5b - MSIZE = 0x5c + POP = 0x50 + DUP = 0x51 + SWAP = 0x52 + MLOAD = 0x53 + MSTORE = 0x54 + MSTORE8 = 0x55 + SLOAD = 0x56 + SSTORE = 0x57 + JUMP = 0x58 + JUMPI = 0x59 + PC = 0x5a + MSIZE = 0x5b + GAS = 0x5c // 0x60 range PUSH1 = 0x60 @@ -140,6 +148,9 @@ var opCodeToString = map[OpCode]string{ CALLVALUE: "CALLVALUE", CALLDATALOAD: "CALLDATALOAD", CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", GASPRICE: "TXGASPRICE", // 0x40 range - block operations @@ -162,6 +173,7 @@ var opCodeToString = map[OpCode]string{ JUMPI: "JUMPI", PC: "PC", MSIZE: "MSIZE", + GAS: "GAS", // 0x60 range - push PUSH1: "PUSH1", @@ -208,7 +220,12 @@ var opCodeToString = map[OpCode]string{ } func (o OpCode) String() string { - return opCodeToString[o] + str := opCodeToString[o] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(o)) + } + + return str } // Op codes for assembling diff --git a/ethchain/vm.go b/ethchain/vm.go index 955be847f0..ebdc58659e 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -337,6 +337,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) + case CALLDATACOPY: + case CODESIZE: + case CODECOPY: case GASPRICE: stack.Push(closure.Price) @@ -423,6 +426,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(pc) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) + case GAS: + stack.Push(closure.Gas) // 0x60 range case CREATE: require(3) From d078e9b8c92fb3bd5789a8e39c169b19864e0a04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:45:11 +0200 Subject: [PATCH 0422/1237] Refactoring state transitioning --- ethchain/asm.go | 12 +- ethchain/deprecated.go | 225 ++++++++++++++++++++++ ethchain/error.go | 17 ++ ethchain/stack.go | 6 + ethchain/state_manager.go | 351 +++++++++++++++++++---------------- ethchain/state_object.go | 2 +- ethchain/transaction.go | 16 +- ethchain/transaction_pool.go | 2 +- ethchain/types.go | 8 +- ethchain/vm.go | 77 ++++++-- 10 files changed, 517 insertions(+), 199 deletions(-) create mode 100644 ethchain/deprecated.go diff --git a/ethchain/asm.go b/ethchain/asm.go index 430a894506..277326ff93 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -25,16 +25,10 @@ func Disassemble(script []byte) (asm []string) { pc.Add(pc, ethutil.Big1) a := int64(op) - int64(PUSH1) + 1 data := script[pc.Int64() : pc.Int64()+a] - val := ethutil.BigD(data) - - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() + if len(data) == 0 { + data = []byte{0} } - - asm = append(asm, fmt.Sprintf("0x%x", b)) + asm = append(asm, fmt.Sprintf("0x%x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go new file mode 100644 index 0000000000..ed2697e2a2 --- /dev/null +++ b/ethchain/deprecated.go @@ -0,0 +1,225 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { + account := state.GetAccount(tx.Sender()) + + err = account.ConvertGas(tx.Gas, tx.GasPrice) + if err != nil { + ethutil.Config.Log.Debugln(err) + return + } + + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ + Origin: account.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + //Price: tx.GasPrice, + }) + ret, gas, err = closure.Call(vm, tx.Data, nil) + + // Update the account (refunds) + state.UpdateStateObject(account) + state.UpdateStateObject(object) + + return +} + +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + //fmt.Println("txTotalBytes", txTotalBytes) + //txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasData)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + fmt.Printf("1. root %x\n", state.Root()) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + state.UpdateStateObject(sender) + fmt.Printf("3. root %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + fmt.Printf("2. root %x\n", state.Root()) + } + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { + /* + Applies transactions to the given state and creates new + state objects where needed. + + If said objects needs to be created + run the initialization script provided by the transaction and + assume there's a return value. The return value will be set to + the script section of the state object. + */ + var ( + addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } + gas = new(big.Int) + script []byte + ) + totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() + + ca := state.GetAccount(coinbase) + // Apply the transaction to the current state + gas, err = sm.ProcessTransaction(tx, ca, state, false) + addTotalGas(gas) + fmt.Println("gas used by tx", gas) + + if tx.CreatesContract() { + if err == nil { + // Create a new state object and the transaction + // as it's data provider. + contract := sm.MakeStateObject(state, tx) + if contract != nil { + fmt.Println(Disassemble(contract.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) + fmt.Println("gas used by eval", gas) + addTotalGas(gas) + fmt.Println("total =", totalGasUsed) + + fmt.Println("script len =", len(script)) + + if err != nil { + err = fmt.Errorf("[STATE] Error during init script run %v", err) + return + } + contract.script = script + state.UpdateStateObject(contract) + } else { + err = fmt.Errorf("[STATE] Unable to create contract") + } + } else { + err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) + } + } else { + // Find the state object at the "recipient" address. If + // there's an object attempt to run the script. + stateObject := state.GetStateObject(tx.Recipient) + if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { + _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) + addTotalGas(gas) + } + } + + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + + return +} + +// Apply transactions uses the transaction passed to it and applies them onto +// the current processing state. +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { + // Process each transaction/contract + var receipts []*Receipt + var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + + totalUsedGas := big.NewInt(0) + + for _, tx := range txs { + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + if err != nil { + if IsNonceErr(err) { + continue + } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } + + ethutil.Config.Log.Infoln(err) + } + + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + + receipts = append(receipts, receipt) + validTxs = append(validTxs, tx) + } + + fmt.Println("################# MADE\n", receipts, "\n############################") + + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + + return receipts, validTxs +} diff --git a/ethchain/error.go b/ethchain/error.go index 29896bc592..2cf09a1ec2 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -79,3 +79,20 @@ func IsNonceErr(err error) bool { return ok } + +type OutOfGasErr struct { + Message string +} + +func OutOfGasError() *OutOfGasErr { + return &OutOfGasErr{Message: "Out of gas"} +} +func (self *OutOfGasErr) Error() string { + return self.Message +} + +func IsOutOfGasErr(err error) bool { + _, ok := err.(*OutOfGasErr) + + return ok +} diff --git a/ethchain/stack.go b/ethchain/stack.go index bf34e6ea9f..37d1f84b9f 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -111,6 +111,12 @@ func (m *Memory) Set(offset, size int64, value []byte) { copy(m.store[offset:offset+size], value) } +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7b44ba3b89..f44afecac1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,8 +108,86 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } -func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateManager) TransitionState(st *StateTransition) (err error) { + //snapshot := st.state.Snapshot() + defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -117,173 +195,144 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj } }() - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) + var ( + tx = st.tx + sender = st.Sender() + receiver *StateObject + ) if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return + return NonceError(tx.Nonce, sender.Nonce) } sender.Nonce += 1 defer func() { - //state.UpdateStateObject(sender) // Notify all subscribers self.Ethereum.Reactor().Post("newTx:post", tx) }() - txTotalBytes := big.NewInt(int64(len(tx.Data))) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) - - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) - - // Make sure there's enough in the sender's account. Having insufficient - // funds won't invalidate this transaction but simple ignores it. - totAmount := new(big.Int).Add(tx.Value, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - state.UpdateStateObject(sender) - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return + if err = st.BuyGas(); err != nil { + return err } - coinbase.BuyGas(gas, tx.GasPrice) - state.UpdateStateObject(coinbase) + receiver = st.Receiver() - // Get the receiver - receiver := state.GetAccount(tx.Recipient) - - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - state.UpdateStateObject(receiver) + if err = st.UseGas(GasTx); err != nil { + return err } - state.UpdateStateObject(sender) + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = st.UseGas(dataPrice); err != nil { + return err + } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + if receiver == nil { // Contract + receiver = self.MakeStateObject(st.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } - return -} + if err = self.transferValue(st, sender, receiver); err != nil { + return err + } -// Apply transactions uses the transaction passed to it and applies them onto -// the current processing state. -func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { - // Process each transaction/contract - var receipts []*Receipt - var validTxs []*Transaction - var ignoredTxs []*Transaction // Transactions which go over the gasLimit - - totalUsedGas := big.NewInt(0) - - for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(st, receiver.Init(), receiver) if err != nil { - if IsNonceErr(err) { - continue - } - if IsGasLimitErr(err) { - ignoredTxs = append(ignoredTxs, tx) - // We need to figure out if we want to do something with thse txes - ethutil.Config.Log.Debugln("Gastlimit:", err) - continue - } - - ethutil.Config.Log.Infoln(err) + return fmt.Errorf("Error during init script run %v", err) } - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receiver.script = code + } + + st.state.UpdateStateObject(sender) + st.state.UpdateStateObject(receiver) + + return nil +} + +func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { + if sender.Amount.Cmp(st.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(st.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(st.tx.Value) + + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) + + return nil +} + +func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { + var ( + receipts Receipts + handled, unhandled Transactions + totalUsedGas = big.NewInt(0) + err error + ) + +done: + for i, tx := range txs { + txGas := new(big.Int).Set(tx.Gas) + st := NewStateTransition(coinbase, tx.Gas, tx, state, block) + err = self.TransitionState(st) + if err != nil { + switch { + case IsNonceErr(err): + err = nil // ignore error + continue + case IsGasLimitErr(err): + unhandled = txs[i:] + + break done + default: + ethutil.Config.Log.Infoln(err) + } + } + + txGas.Sub(txGas, st.gas) + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} receipts = append(receipts, receipt) - validTxs = append(validTxs, tx) + handled = append(handled, tx) } fmt.Println("################# MADE\n", receipts, "\n############################") - // Update the total gas used for the block (to be mined) - block.GasUsed = totalUsedGas + parent.GasUsed = totalUsedGas - return receipts, validTxs + return receipts, handled, unhandled, err } -func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { - /* - Applies transactions to the given state and creates new - state objects where needed. - - If said objects needs to be created - run the initialization script provided by the transaction and - assume there's a return value. The return value will be set to - the script section of the state object. - */ +func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { var ( - addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } - gas = new(big.Int) - script []byte + tx = st.tx + block = st.block + initiator = st.Sender() ) - totalGasUsed = big.NewInt(0) - snapshot := state.Snapshot() - ca := state.GetAccount(coinbase) - // Apply the transaction to the current state - gas, err = sm.ProcessTransaction(tx, ca, state, false) - addTotalGas(gas) - - if tx.CreatesContract() { - if err == nil { - // Create a new state object and the transaction - // as it's data provider. - contract := sm.MakeStateObject(state, tx) - if contract != nil { - fmt.Println(Disassemble(contract.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) - addTotalGas(gas) - - if err != nil { - err = fmt.Errorf("[STATE] Error during init script run %v", err) - return - } - contract.script = script - state.UpdateStateObject(contract) - } else { - err = fmt.Errorf("[STATE] Unable to create contract") - } - } else { - err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) - } - } else { - // Find the state object at the "recipient" address. If - // there's an object attempt to run the script. - stateObject := state.GetStateObject(tx.Recipient) - if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - addTotalGas(gas) - } - } - - parent := sm.bc.GetBlock(block.PrevHash) - total := new(big.Int).Add(block.GasUsed, totalGasUsed) - limit := block.CalcGasLimit(parent) - if total.Cmp(limit) > 0 { - state.Revert(snapshot) - err = GasLimitError(total, limit) - } + closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) + vm := NewVm(st.state, self, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) return } @@ -325,7 +374,8 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) // Process the transactions on to current block - sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -464,35 +514,6 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { - account := state.GetAccount(tx.Sender()) - - err = account.ConvertGas(tx.Gas, tx.GasPrice) - if err != nil { - ethutil.Config.Log.Debugln(err) - return - } - - closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) - vm := NewVm(state, sm, RuntimeVars{ - Origin: account.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - //Price: tx.GasPrice, - }) - ret, gas, err = closure.Call(vm, tx.Data, nil) - - // Update the account (refunds) - state.UpdateStateObject(account) - state.UpdateStateObject(object) - - return -} - func (sm *StateManager) notifyChanges(state *State) { for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index a1dd531de9..b923748824 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -135,7 +135,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) BuyGas(gas, price *big.Int) error { rGas := new(big.Int).Set(gas) - rGas.Mul(gas, price) + rGas.Mul(rGas, price) self.AddAmount(rGas) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 32dbd83884..7aaab2fd10 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -46,15 +46,18 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { return tx } +func (self *Transaction) GasValue() *big.Int { + return new(big.Int).Mul(self.Gas, self.GasPrice) +} + +func (self *Transaction) TotalValue() *big.Int { + v := self.GasValue() + return v.Add(v, self.Value) +} + func (tx *Transaction) Hash() []byte { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - /* - if tx.contractCreation { - data = append(data, tx.Init) - } - */ - return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } @@ -185,6 +188,7 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int } +type Receipts []*Receipt func NewRecieptFromValue(val *ethutil.Value) *Receipt { r := &Receipt{} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 52c850ba34..6538b00296 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -220,7 +220,7 @@ out: // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) diff --git a/ethchain/types.go b/ethchain/types.go index fdfd5792be..ee70a8d281 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -21,8 +21,10 @@ const ( NEG = 0x09 LT = 0x0a GT = 0x0b - EQ = 0x0c - NOT = 0x0d + SLT = 0x0c + SGT = 0x0d + EQ = 0x0e + NOT = 0x0f // 0x10 range - bit ops AND = 0x10 @@ -128,6 +130,8 @@ var opCodeToString = map[OpCode]string{ NEG: "NEG", LT: "LT", GT: "GT", + SLT: "SLT", + SGT: "SGT", EQ: "EQ", NOT: "NOT", diff --git a/ethchain/vm.go b/ethchain/vm.go index ebdc58659e..e17264697b 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" + "math" _ "math" "math/big" ) @@ -18,6 +19,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasData = big.NewInt(5) GasTx = big.NewInt(500) ) @@ -116,9 +118,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas.Add(gas, amount) } + var newMemSize uint64 = 0 switch op { - case SHA3: - setStepGasUsage(GasSha) case SLOAD: setStepGasUsage(GasSLoad) case SSTORE: @@ -135,27 +136,61 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) case BALANCE: setStepGasUsage(GasBalance) - case CREATE: + case MSTORE: + require(2) + newMemSize = stack.Peek().Uint64() + 32 + case MSTORE8: + require(2) + newMemSize = stack.Peek().Uint64() + 1 + case RETURN: + require(2) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case SHA3: + require(2) + + setStepGasUsage(GasSha) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case CALLDATACOPY: require(3) - args := stack.Get(big.NewInt(3)) - initSize := new(big.Int).Add(args[1], args[0]) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + case CODECOPY: + require(3) - setStepGasUsage(CalculateTxGas(initSize)) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: + require(7) setStepGasUsage(GasCall) - case MLOAD, MSIZE, MSTORE8, MSTORE: - setStepGasUsage(GasMemory) + + x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() + y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() + + newMemSize = uint64(math.Max(float64(x), float64(y))) + case CREATE: + require(3) + setStepGasUsage(GasCreate) + + newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() default: setStepGasUsage(GasStep) } + newMemSize = (newMemSize + 31) / 32 * 32 + if newMemSize > uint64(mem.Len()) { + m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 + setStepGasUsage(big.NewInt(int64(m))) + } + if !closure.UseGas(gas) { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + mem.Resize(newMemSize) + switch op { case LOG: stack.Print() @@ -340,6 +375,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALLDATACOPY: case CODESIZE: case CODECOPY: + var ( + size = int64(len(closure.Script)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Script[cOff : cOff+l] + + mem.Set(mOff, l, code) case GASPRICE: stack.Push(closure.Price) @@ -448,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - closure.UseGas(gas) + //closure.UseGas(gas) // Create the closure c := NewClosure(closure.callee, @@ -498,12 +550,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if contract != nil { // Prepay for the gas - // If gas is set to 0 use all remaining gas for the next call - if gas.Cmp(big.NewInt(0)) == 0 { - // Copy - gas = new(big.Int).Set(closure.Gas) - } - closure.UseGas(gas) + //closure.UseGas(gas) // Add the value to the state object contract.AddAmount(value) From 5e2bf12a31e3e3a026d0f8d28c2d5bba919fc224 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:57:52 +0200 Subject: [PATCH 0423/1237] Refactored state transitioning to its own model --- ethchain/deprecated.go | 11 +++ ethchain/state_manager.go | 202 +------------------------------------- 2 files changed, 13 insertions(+), 200 deletions(-) diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go index ed2697e2a2..0985fa25d0 100644 --- a/ethchain/deprecated.go +++ b/ethchain/deprecated.go @@ -7,6 +7,17 @@ import ( "math/big" ) +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { account := state.GetAccount(tx.Sender()) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f44afecac1..576afa8d36 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,182 +97,6 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { - contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - - return contract - } - - return nil -} - -type StateTransition struct { - coinbase []byte - tx *Transaction - gas *big.Int - state *State - block *Block - - cb, rec, sen *StateObject -} - -func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} -} - -func (self *StateTransition) Coinbase() *StateObject { - if self.cb != nil { - return self.cb - } - - self.cb = self.state.GetAccount(self.coinbase) - return self.cb -} -func (self *StateTransition) Sender() *StateObject { - if self.sen != nil { - return self.sen - } - - self.sen = self.state.GetAccount(self.tx.Sender()) - return self.sen -} -func (self *StateTransition) Receiver() *StateObject { - if self.tx.CreatesContract() { - return nil - } - - if self.rec != nil { - return self.rec - } - - self.rec = self.state.GetAccount(self.tx.Recipient) - return self.rec -} - -func (self *StateTransition) UseGas(amount *big.Int) error { - if self.gas.Cmp(amount) < 0 { - return OutOfGasError() - } - self.gas.Sub(self.gas, amount) - - return nil -} - -func (self *StateTransition) AddGas(amount *big.Int) { - self.gas.Add(self.gas, amount) -} - -func (self *StateTransition) BuyGas() error { - var err error - - sender := self.Sender() - if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) - } - - coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) - if err != nil { - return err - } - self.state.UpdateStateObject(coinbase) - - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) - - return nil -} - -func (self *StateManager) TransitionState(st *StateTransition) (err error) { - //snapshot := st.state.Snapshot() - - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - var ( - tx = st.tx - sender = st.Sender() - receiver *StateObject - ) - - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) - } - - sender.Nonce += 1 - defer func() { - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - }() - - if err = st.BuyGas(); err != nil { - return err - } - - receiver = st.Receiver() - - if err = st.UseGas(GasTx); err != nil { - return err - } - - dataPrice := big.NewInt(int64(len(tx.Data))) - dataPrice.Mul(dataPrice, GasData) - if err = st.UseGas(dataPrice); err != nil { - return err - } - - if receiver == nil { // Contract - receiver = self.MakeStateObject(st.state, tx) - if receiver == nil { - return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) - } - } - - if err = self.transferValue(st, sender, receiver); err != nil { - return err - } - - if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) - code, err := self.Eval(st, receiver.Init(), receiver) - if err != nil { - return fmt.Errorf("Error during init script run %v", err) - } - - receiver.script = code - } - - st.state.UpdateStateObject(sender) - st.state.UpdateStateObject(receiver) - - return nil -} - -func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { - if sender.Amount.Cmp(st.tx.Value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) - } - - // Subtract the amount from the senders account - sender.SubAmount(st.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(st.tx.Value) - - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) - - return nil -} - func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts @@ -284,8 +108,8 @@ func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, blo done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx.Gas, tx, state, block) - err = self.TransitionState(st) + st := NewStateTransition(coinbase, tx, state, block) + err = st.TransitionState() if err != nil { switch { case IsNonceErr(err): @@ -315,28 +139,6 @@ done: return receipts, handled, unhandled, err } -func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { - var ( - tx = st.tx - block = st.block - initiator = st.Sender() - ) - - closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) - vm := NewVm(st.state, self, RuntimeVars{ - Origin: initiator.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - }) - ret, _, err = closure.Call(vm, tx.Data, nil) - - return -} - func (sm *StateManager) Process(block *Block, dontReact bool) error { if !sm.bc.HasBlock(block.PrevHash) { return ParentError(block.PrevHash) From cebf4e3697dcd20e290ff56ad6e5dfca2059c063 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:58:01 +0200 Subject: [PATCH 0424/1237] Refactored state transitioning to its own model --- ethchain/state_transition.go | 206 +++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 ethchain/state_transition.go diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go new file mode 100644 index 0000000000..6ec9205e90 --- /dev/null +++ b/ethchain/state_transition.go @@ -0,0 +1,206 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateTransition) TransitionState() (err error) { + //snapshot := st.state.Snapshot() + + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + var ( + tx = self.tx + sender = self.Sender() + receiver *StateObject + ) + + if sender.Nonce != tx.Nonce { + return NonceError(tx.Nonce, sender.Nonce) + } + + sender.Nonce += 1 + defer func() { + // Notify all subscribers + //self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + if err = self.BuyGas(); err != nil { + return err + } + + receiver = self.Receiver() + + if err = self.UseGas(GasTx); err != nil { + return err + } + + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = self.UseGas(dataPrice); err != nil { + return err + } + + if receiver == nil { // Contract + receiver = self.MakeStateObject(self.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } + + if err = self.transferValue(sender, receiver); err != nil { + return err + } + + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(receiver.Init(), receiver) + if err != nil { + return fmt.Errorf("Error during init script run %v", err) + } + + receiver.script = code + } + + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + + return nil +} + +func (self *StateTransition) transferValue(sender, receiver *StateObject) error { + if sender.Amount.Cmp(self.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) + + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + + return nil +} + +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { + var ( + tx = self.tx + block = self.block + initiator = self.Sender() + state = self.state + ) + + closure := NewClosure(initiator, context, script, state, self.gas, tx.GasPrice) + vm := NewVm(state, nil, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) + + return +} From c734dde982c4ce778afa074e94efb09e552dbd84 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 13:06:27 +0200 Subject: [PATCH 0425/1237] comments & refactor --- ethchain/state_manager.go | 4 +++- ethchain/state_transition.go | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 576afa8d36..c68d5e001d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -124,6 +124,9 @@ done: } } + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + txGas.Sub(txGas, st.gas) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} @@ -158,7 +161,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea hash := block.Hash() if sm.bc.HasBlock(hash) { - //fmt.Println("[STATE] We already have this block, ignoring") return nil } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ec9205e90..1256d019ca 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -6,6 +6,22 @@ import ( "math/big" ) +/* + * The State transitioning model + * + * A state transition is a change made when a transaction is applied to the current world state + * The state transitioning model does all all the necessary work to work out a valid new state root. + * 1) Nonce handling + * 2) Pre pay / buy gas of the coinbase (miner) + * 3) Create a new state object if the recipient is \0*32 + * 4) Value transfer + * == If contract creation == + * 4a) Attempt to run transaction data + * 4b) If valid, use result as code for the new state object + * == end == + * 5) Run Script section + * 6) Derive new state root + */ type StateTransition struct { coinbase []byte tx *Transaction @@ -115,10 +131,6 @@ func (self *StateTransition) TransitionState() (err error) { } sender.Nonce += 1 - defer func() { - // Notify all subscribers - //self.Ethereum.Reactor().Post("newTx:post", tx) - }() if err = self.BuyGas(); err != nil { return err From 81245473486dd680b7121d4b227ca8a57d07b4b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 16:06:27 +0200 Subject: [PATCH 0426/1237] Moving a head closer to interop --- ethchain/closure.go | 26 ++++++++++++++------------ ethchain/state_object.go | 8 +++++--- ethchain/state_transition.go | 32 ++++++++++++++++++++++++-------- ethchain/vm.go | 31 ++++++++++++++++++------------- ethutil/common.go | 2 +- peer.go | 4 ++-- 6 files changed, 64 insertions(+), 39 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 5c9c3e47c0..32b297e903 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -17,7 +17,7 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef + caller ClosureRef object *StateObject Script []byte State *State @@ -28,12 +28,14 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { - c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} +func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { + c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil} - // In most cases gas, price and value are pointers to transaction objects + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas //new(big.Int).Set(gas) + // In most cases price and value are pointers to transaction objects // and we don't want the transaction's values to change. - c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) c.UsedGas = new(big.Int) @@ -83,11 +85,11 @@ func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, e } func (c *Closure) Return(ret []byte) []byte { - // Return the remaining gas to the callee - // If no callee is present return it to + // Return the remaining gas to the caller + // If no caller is present return it to // the origin (i.e. contract or tx) - if c.callee != nil { - c.callee.ReturnGas(c.Gas, c.Price, c.State) + if c.caller != nil { + c.caller.ReturnGas(c.Gas, c.Price, c.State) } else { c.object.ReturnGas(c.Gas, c.Price, c.State) } @@ -107,7 +109,7 @@ func (c *Closure) UseGas(gas *big.Int) bool { return true } -// Implement the Callee interface +// Implement the caller interface func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) @@ -118,8 +120,8 @@ func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { - return c.callee +func (c *Closure) Caller() ClosureRef { + return c.caller } func (c *Closure) N() *big.Int { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index b923748824..12ebf8e9b7 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - //fmt.Println("storing", val.BigInt(), "@", num) + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } @@ -102,8 +102,10 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { - remainder := new(big.Int).Mul(gas, price) - c.AddAmount(remainder) + /* + remainder := new(big.Int).Mul(gas, price) + c.AddAmount(remainder) + */ } func (c *StateObject) AddAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1256d019ca..a080c56025 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -116,7 +116,7 @@ func (self *StateTransition) TransitionState() (err error) { defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) + err = fmt.Errorf("state transition err %v", r) } }() @@ -126,41 +126,51 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) + // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) } + // Increment the nonce for the next transaction sender.Nonce += 1 + // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() + // Transaction gas if err = self.UseGas(GasTx); err != nil { return err } + // Pay data gas dataPrice := big.NewInt(int64(len(tx.Data))) dataPrice.Mul(dataPrice, GasData) if err = self.UseGas(dataPrice); err != nil { return err } - if receiver == nil { // Contract + // If the receiver is nil it's a contract (\0*32). + if receiver == nil { + // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) } } + // Transfer value from sender to receiver if err = self.transferValue(sender, receiver); err != nil { return err } + // Process the init code and create 'valid' contract if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) + //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -173,6 +183,10 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, tx.GasPrice) + sender.AddAmount(remaining) + self.state.UpdateStateObject(sender) self.state.UpdateStateObject(receiver) @@ -184,12 +198,14 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) } - // Subtract the amount from the senders account - sender.SubAmount(self.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.tx.Value) + if self.tx.Value.Cmp(ethutil.Big0) > 0 { + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + } return nil } diff --git a/ethchain/vm.go b/ethchain/vm.go index e17264697b..f0059f6aca 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -114,14 +114,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } gas := new(big.Int) - setStepGasUsage := func(amount *big.Int) { + addStepGasUsage := func(amount *big.Int) { gas.Add(gas, amount) } + addStepGasUsage(GasStep) + var newMemSize uint64 = 0 switch op { + case STOP: + case SUICIDE: case SLOAD: - setStepGasUsage(GasSLoad) + gas.Set(GasSLoad) case SSTORE: var mult *big.Int y, x := stack.Peekn() @@ -133,12 +137,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) + gas = new(big.Int).Mul(mult, GasSStore) case BALANCE: - setStepGasUsage(GasBalance) + gas.Set(GasBalance) case MSTORE: require(2) newMemSize = stack.Peek().Uint64() + 32 + case MLOAD: + case MSTORE8: require(2) newMemSize = stack.Peek().Uint64() + 1 @@ -149,7 +155,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) - setStepGasUsage(GasSha) + gas.Set(GasSha) newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() case CALLDATACOPY: @@ -162,7 +168,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: require(7) - setStepGasUsage(GasCall) + gas.Set(GasCall) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -170,17 +177,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = uint64(math.Max(float64(x), float64(y))) case CREATE: require(3) - setStepGasUsage(GasCreate) + gas.Set(GasCreate) newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() - default: - setStepGasUsage(GasStep) } newMemSize = (newMemSize + 31) / 32 * 32 if newMemSize > uint64(mem.Len()) { m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 - setStepGasUsage(big.NewInt(int64(m))) + addStepGasUsage(big.NewInt(int64(m))) } if !closure.UseGas(gas) { @@ -355,7 +360,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case CALLER: - stack.Push(ethutil.BigD(closure.Callee().Address())) + stack.Push(ethutil.BigD(closure.caller.Address())) case CALLVALUE: stack.Push(vm.vars.Value) case CALLDATALOAD: @@ -492,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro snapshot := vm.state.Snapshot() // Generate a new address - addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) + addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) // Create a new contract contract := NewContract(addr, value, []byte("")) // Set the init script @@ -503,7 +508,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //closure.UseGas(gas) // Create the closure - c := NewClosure(closure.callee, + c := NewClosure(closure.caller, closure.Object(), contract.initScript, vm.state, diff --git a/ethutil/common.go b/ethutil/common.go index ddaf78f885..f63ba5d830 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -47,7 +47,7 @@ func CurrencyToString(num *big.Int) string { // Common big integers often used var ( Big1 = big.NewInt(1) - Big2 = big.NewInt(1) + Big2 = big.NewInt(2) Big0 = big.NewInt(0) Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) diff --git a/peer.go b/peer.go index 587bc19747..4434715fbd 100644 --- a/peer.go +++ b/peer.go @@ -402,7 +402,7 @@ func (p *Peer) HandleInbound() { if err != nil { // If the parent is unknown try to catch up with this peer if ethchain.IsParentErr(err) { - ethutil.Config.Log.Infoln("Attempting to catch up since we don't know the parent") + ethutil.Config.Log.Infoln("Attempting to catch. Parent known") p.catchingUp = false p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } else if ethchain.IsValidationErr(err) { @@ -414,7 +414,7 @@ func (p *Peer) HandleInbound() { if p.catchingUp && msg.Data.Len() > 1 { if lastBlock != nil { blockInfo := lastBlock.BlockInfo() - ethutil.Config.Log.Debugf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + ethutil.Config.Log.Debugf("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false From 63883bf27d8b87f601e1603e9024a279b91bffb7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 14 Jun 2014 11:46:09 +0200 Subject: [PATCH 0427/1237] Moving closer to interop --- ethchain/asm.go | 2 +- ethchain/block_chain.go | 2 ++ ethchain/state_transition.go | 16 ++++++++++------ ethchain/types.go | 2 +- ethminer/miner.go | 11 +++++++++-- peer.go | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff93..c267f9b55a 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%#x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 8cede24039..19b5248d77 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -55,6 +55,8 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { nil, "") + block.MinGasPrice = big.NewInt(10000000000000) + if bc.CurrentBlock != nil { var mul *big.Int if block.Time < lastBlockTime+42 { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a080c56025..5ded0cddd9 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -131,14 +131,21 @@ func (self *StateTransition) TransitionState() (err error) { return NonceError(tx.Nonce, sender.Nonce) } - // Increment the nonce for the next transaction - sender.Nonce += 1 - // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // XXX Transactions after this point are considered valid. + + defer func() { + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + }() + + // Increment the nonce for the next transaction + sender.Nonce += 1 + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() @@ -187,9 +194,6 @@ func (self *StateTransition) TransitionState() (err error) { remaining := new(big.Int).Mul(self.gas, tx.GasPrice) sender.AddAmount(remaining) - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) - return nil } diff --git a/ethchain/types.go b/ethchain/types.go index ee70a8d281..d89fad147e 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -226,7 +226,7 @@ var opCodeToString = map[OpCode]string{ func (o OpCode) String() string { str := opCodeToString[o] if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) + return fmt.Sprintf("Missing opcode %#x", int(o)) } return str diff --git a/ethminer/miner.go b/ethminer/miner.go index d054053914..30b7ef35d9 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -136,11 +136,18 @@ func (self *Miner) mineNewBlock() { // Sort the transactions by nonce in case of odd network propagation sort.Sort(ethchain.TxByNonce{self.txs}) + // Accumulate all valid transaction and apply them to the new state - receipts, txs := stateManager.ApplyTransactions(self.block.Coinbase, self.block.State(), self.block, self.txs) - self.txs = txs + // Error may be ignored. It's not important during mining + receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(self.block.Coinbase, self.block.State(), self.block, self.block, self.txs) + if err != nil { + ethutil.Config.Log.Debugln("[MINER]", err) + } + self.txs = append(txs, unhandledTxs...) + // Set the transactions to the block so the new SHA3 can be calculated self.block.SetReceipts(receipts, txs) + // Accumulate the rewards included for this block stateManager.AccumelateRewards(self.block.State(), self.block) diff --git a/peer.go b/peer.go index 4434715fbd..9da2ed002e 100644 --- a/peer.go +++ b/peer.go @@ -19,7 +19,7 @@ const ( // Current protocol version ProtocolVersion = 20 // Interval for ping/pong message - pingPongTimer = 30 * time.Second + pingPongTimer = 1 * time.Second ) type DiscReason byte @@ -270,7 +270,7 @@ out: // Ping timer case <-pingTimer.C: timeSince := time.Since(time.Unix(p.lastPong, 0)) - if p.pingStartTime.IsZero() == false && timeSince > (pingPongTimer+10*time.Second) { + if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+10*time.Second) { ethutil.Config.Log.Infof("[PEER] Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) p.Stop() return From 6d52da58d9337b786a0c869974daa91ce0e34a98 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 14 Jun 2014 15:44:13 +0200 Subject: [PATCH 0428/1237] Logging mechanism --- ethutil/config.go | 27 ++++++++++++++++++++++++++- peer.go | 5 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index f935e8f75c..90037df87d 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -143,12 +143,17 @@ func NewLogger(flag LoggerType, level int) *Logger { return &Logger{logSys: loggers, logLevel: level} } +func (self *Logger) SetLevel(level int) { + self.logLevel = level +} + func (log *Logger) AddLogSystem(logger LogSystem) { log.logSys = append(log.logSys, logger) } const ( - LogLevelDebug = iota + LogLevelSystem = iota + LogLevelDebug LogLevelInfo ) @@ -204,6 +209,26 @@ func (log *Logger) Fatal(v ...interface{}) { os.Exit(1) } +func (log *Logger) Println(level int, v ...interface{}) { + if log.logLevel > level { + return + } + + for _, logger := range log.logSys { + logger.Println(v...) + } +} + +func (log *Logger) Printf(level int, format string, v ...interface{}) { + if log.logLevel > level { + return + } + + for _, logger := range log.logSys { + logger.Printf(format, v...) + } +} + type confValue struct { value string } diff --git a/peer.go b/peer.go index 9da2ed002e..56dd18c65a 100644 --- a/peer.go +++ b/peer.go @@ -244,6 +244,8 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { } } + ethutil.Config.Log.Println(ethutil.LogLevelSystem, "<=", msg.Type, msg.Data) + err := ethwire.WriteMessage(p.conn, msg) if err != nil { ethutil.Config.Log.Debugln("[PEER] Can't send message:", err) @@ -264,6 +266,7 @@ out: select { // Main message queue. All outbound messages are processed through here case msg := <-p.outputQueue: + p.writeMessage(msg) p.lastSend = time.Now() @@ -316,6 +319,8 @@ func (p *Peer) HandleInbound() { ethutil.Config.Log.Debugln(err) } for _, msg := range msgs { + ethutil.Config.Log.Println(ethutil.LogLevelSystem, "=>", msg.Type, msg.Data) + switch msg.Type { case ethwire.MsgHandshakeTy: // Version message From b0e023e43248d09cb273d5b6025d28ee718151c0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:04:18 +0200 Subject: [PATCH 0429/1237] Increase ping timeout to 30 seconds --- peer.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/peer.go b/peer.go index 56dd18c65a..0c4d763559 100644 --- a/peer.go +++ b/peer.go @@ -19,7 +19,7 @@ const ( // Current protocol version ProtocolVersion = 20 // Interval for ping/pong message - pingPongTimer = 1 * time.Second + pingPongTimer = 2 * time.Second ) type DiscReason byte @@ -266,14 +266,13 @@ out: select { // Main message queue. All outbound messages are processed through here case msg := <-p.outputQueue: - p.writeMessage(msg) p.lastSend = time.Now() // Ping timer case <-pingTimer.C: timeSince := time.Since(time.Unix(p.lastPong, 0)) - if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+10*time.Second) { + if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+30*time.Second) { ethutil.Config.Log.Infof("[PEER] Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) p.Stop() return From 5871dbaf5a832a4fd34bdb22cf479d6b0b4da9fb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:10:42 +0200 Subject: [PATCH 0430/1237] Set contract addr for new transactions --- ethchain/transaction.go | 2 +- ethpub/types.go | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 7aaab2fd10..3d52e4f73f 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -25,7 +25,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { diff --git a/ethpub/types.go b/ethpub/types.go index 868fd2713f..a764210073 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -111,11 +111,12 @@ func NewPTx(tx *ethchain.Transaction) *PTx { sender := hex.EncodeToString(tx.Sender()) createsContract := tx.CreatesContract() - data := strings.Join(ethchain.Disassemble(tx.Data), "\n") + data := string(tx.Data) + if tx.CreatesContract() { + data = strings.Join(ethchain.Disassemble(tx.Data), "\n") + } - isContract := len(tx.Data) > 0 - - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: isContract, Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)} } func (self *PTx) ToString() string { From d80f999a215b74e23d21f3548486f996c3eb028d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:11:06 +0200 Subject: [PATCH 0431/1237] Run contracts --- ethchain/state_transition.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5ded0cddd9..2e2a51f72d 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -188,6 +188,13 @@ func (self *StateTransition) TransitionState() (err error) { } receiver.script = code + } else { + if len(receiver.Script()) > 0 { + _, err := self.Eval(receiver.Script(), receiver) + if err != nil { + return fmt.Errorf("Error during code execution %v", err) + } + } } // Return remaining gas From 8198fd7913ea4066afb5c0cf5e57fa5ec4888fac Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:04 +0200 Subject: [PATCH 0432/1237] Cache whole objects instead of states only --- ethchain/state.go | 98 +++++++++++++++++++++++++++++++++++++++- ethchain/state_object.go | 21 +++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 5af748e00e..f413fb8edf 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -16,14 +16,17 @@ type State struct { // Nested states states map[string]*State + stateObjects map[string]*StateObject + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} + return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } +/* // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -43,6 +46,35 @@ func (s *State) Sync() { s.trie.Sync() } +*/ + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Sync() + } + + s.trie.Sync() +} // Purges the current trie. func (s *State) Purge() int { @@ -54,6 +86,7 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } +/* func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -78,7 +111,6 @@ func (s *State) UpdateStateObject(object *StateObject) { if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state - //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -96,13 +128,66 @@ func (s *State) GetAccount(addr []byte) (account *StateObject) { account = NewStateObjectFromBytes(addr, []byte(data)) } + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + return } +*/ + +func (self *State) UpdateStateObject(stateObject *StateObject) { + addr := stateObject.Address() + + if self.stateObjects[string(addr)] == nil { + self.stateObjects[string(addr)] = stateObject + } + + ethutil.Config.Db.Put(ethutil.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)) + if len(data) == 0 { + return nil + } + + 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 = 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 (s *State) Copy() *State { state := NewState(s.trie.Copy()) for k, subState := range s.states { @@ -111,6 +196,15 @@ func (s *State) Copy() *State { return state } +*/ +func (self *State) Copy() *State { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state +} func (s *State) Snapshot() *State { return s.Copy() diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 12ebf8e9b7..3775d436cb 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -38,6 +38,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject { return nil } +func NewStateObject(addr []byte) *StateObject { + return &StateObject{address: addr, Amount: new(big.Int)} +} + func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) @@ -146,6 +150,23 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) Copy() *StateObject { + stCopy := &StateObject{} + stCopy.address = make([]byte, len(self.address)) + copy(stCopy.address, self.address) + stCopy.Amount = new(big.Int).Set(self.Amount) + stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) + copy(stCopy.ScriptHash, self.ScriptHash) + stCopy.Nonce = self.Nonce + stCopy.state = self.state.Copy() + stCopy.script = make([]byte, len(self.script)) + copy(stCopy.script, self.script) + stCopy.initScript = make([]byte, len(self.initScript)) + copy(stCopy.initScript, self.initScript) + + return stCopy +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address From 1fbea2e438d56484ebfa509d7433cc418e17a79b Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:21 +0200 Subject: [PATCH 0433/1237] Reworking messaging interface --- ethwire/messaging.go | 163 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 4 deletions(-) diff --git a/ethwire/messaging.go b/ethwire/messaging.go index cbcbbb8b7a..f13b723538 100644 --- a/ethwire/messaging.go +++ b/ethwire/messaging.go @@ -1,3 +1,5 @@ +// Package ethwire provides low level access to the Ethereum network and allows +// you to broadcast data over the network. package ethwire import ( @@ -9,11 +11,13 @@ import ( "time" ) -// Message: -// [4 bytes token] RLP([TYPE, DATA]) -// Refer to http://wiki.ethereum.org/index.php/Wire_Protocol +// Connection interface describing the methods required to implement the wire protocol. +type Conn interface { + Write(typ MsgType, v ...interface{}) error + Read() *Msg +} -// The magic token which should be the first 4 bytes of every message. +// The magic token which should be the first 4 bytes of every message and can be used as separator between messages. var MagicToken = []byte{34, 64, 8, 145} type MsgType byte @@ -68,6 +72,157 @@ func NewMessage(msgType MsgType, data interface{}) *Msg { } } +type Messages []*Msg + +// The connection object allows you to set up a connection to the Ethereum network. +// The Connection object takes care of all encoding and sending objects properly over +// the network. +type Connection struct { + conn net.Conn + nTimeout time.Duration + pendingMessages Messages +} + +// Create a new connection to the Ethereum network +func New(conn net.Conn) *Connection { + return &Connection{conn: conn, nTimeout: 500} +} + +// Read, reads from the network. It will block until the next message is received. +func (self *Connection) Read() *Msg { + if len(self.pendingMessages) == 0 { + self.readMessages() + } + + ret := self.pendingMessages[0] + self.pendingMessages = self.pendingMessages[1:] + + return ret + +} + +// Write to the Ethereum network specifying the type of the message and +// the data. Data can be of type RlpEncodable or []interface{}. Returns +// nil or if something went wrong an error. +func (self *Connection) Write(typ MsgType, v ...interface{}) error { + var pack []byte + + slice := [][]interface{}{[]interface{}{byte(typ)}} + for _, value := range v { + if encodable, ok := value.(ethutil.RlpEncodable); ok { + slice = append(slice, encodable.RlpValue()) + } else if raw, ok := value.([]interface{}); ok { + slice = append(slice, raw) + } else { + panic(fmt.Sprintf("Unable to 'write' object of type %T", value)) + } + } + + // Encode the type and the (RLP encoded) data for sending over the wire + encoded := ethutil.NewValue(slice).Encode() + payloadLength := ethutil.NumberToBytes(uint32(len(encoded)), 32) + + // Write magic token and payload length (first 8 bytes) + pack = append(MagicToken, payloadLength...) + pack = append(pack, encoded...) + + // Write to the connection + _, err := self.conn.Write(pack) + if err != nil { + return err + } + + return nil +} + +func (self *Connection) readMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { + if len(data) == 0 { + return nil, nil, true, nil + } + + if len(data) <= 8 { + return nil, remaining, false, errors.New("Invalid message") + } + + // Check if the received 4 first bytes are the magic token + if bytes.Compare(MagicToken, data[:4]) != 0 { + return nil, nil, false, fmt.Errorf("MagicToken mismatch. Received %v", data[:4]) + } + + messageLength := ethutil.BytesToNumber(data[4:8]) + remaining = data[8+messageLength:] + if int(messageLength) > len(data[8:]) { + return nil, nil, false, fmt.Errorf("message length %d, expected %d", len(data[8:]), messageLength) + } + + message := data[8 : 8+messageLength] + decoder := ethutil.NewValueFromBytes(message) + // Type of message + t := decoder.Get(0).Uint() + // Actual data + d := decoder.SliceFrom(1) + + msg = &Msg{ + Type: MsgType(t), + Data: d, + } + + return +} + +// The basic message reader waits for data on the given connection, decoding +// and doing a few sanity checks such as if there's a data type and +// unmarhals the given data +func (self *Connection) readMessages() (err error) { + // The recovering function in case anything goes horribly wrong + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("ethwire.ReadMessage error: %v", r) + } + }() + + // Buff for writing network message to + //buff := make([]byte, 1440) + var buff []byte + var totalBytes int + for { + // Give buffering some time + self.conn.SetReadDeadline(time.Now().Add(self.nTimeout * time.Millisecond)) + // Create a new temporarily buffer + b := make([]byte, 1440) + // Wait for a message from this peer + n, _ := self.conn.Read(b) + if err != nil && n == 0 { + if err.Error() != "EOF" { + fmt.Println("err now", err) + return err + } else { + break + } + + // Messages can't be empty + } else if n == 0 { + break + } + + buff = append(buff, b[:n]...) + totalBytes += n + } + + // Reslice buffer + buff = buff[:totalBytes] + msg, remaining, done, err := self.readMessage(buff) + for ; done != true; msg, remaining, done, err = self.readMessage(remaining) { + //log.Println("rx", msg) + + if msg != nil { + self.pendingMessages = append(self.pendingMessages, msg) + } + } + + return +} + func ReadMessage(data []byte) (msg *Msg, remaining []byte, done bool, err error) { if len(data) == 0 { return nil, nil, true, nil From dccef707280bd852ae536e69dea82ad0555ba0a9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:55 +0200 Subject: [PATCH 0434/1237] Method for creating a new key from scratch --- ethutil/keypair.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ethutil/keypair.go b/ethutil/keypair.go index cf5882e2c4..29fb1bac5b 100644 --- a/ethutil/keypair.go +++ b/ethutil/keypair.go @@ -12,6 +12,12 @@ type KeyPair struct { account *StateObject } +func GenerateNewKeyPair() (*KeyPair, error) { + _, prv := secp256k1.GenerateKeyPair() + + return NewKeyPairFromSec(prv) +} + func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { pubkey, err := secp256k1.GeneratePubKey(seckey) if err != nil { From 58a0e8e3e2979b07e9e8f697f947a412ac81e386 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:52:10 +0200 Subject: [PATCH 0435/1237] Changed RlpEncodable --- ethutil/rlp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethutil/rlp.go b/ethutil/rlp.go index 69f80a0a64..195ef0efbb 100644 --- a/ethutil/rlp.go +++ b/ethutil/rlp.go @@ -11,6 +11,7 @@ import ( type RlpEncodable interface { RlpEncode() []byte + RlpValue() []interface{} } type RlpEncoder struct { From 02d8ad030fd1293a03cf905d50533678aaea40fd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:35:35 +0200 Subject: [PATCH 0436/1237] Keeping old code for reference --- ethchain/state.go | 177 +++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 88 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index f413fb8edf..9a9d0a2784 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -26,28 +26,6 @@ func NewState(trie *ethutil.Trie) *State { return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -/* -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, state := range s.states { - state.Reset() - } -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, state := range s.states { - state.Sync() - } - - s.trie.Sync() -} -*/ - // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -86,58 +64,6 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } -/* -func (s *State) GetStateObject(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - stateObject := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) - stateObject.state = cachedStateObject - } - - return stateObject -} - -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil && s.states[string(addr)] == nil { - s.states[string(addr)] = object.state - } - - ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) - - s.trie.Update(string(addr), string(object.RlpEncode())) - - s.manifest.AddObjectChange(object) -} - -func (s *State) GetAccount(addr []byte) (account *StateObject) { - data := s.trie.Get(string(addr)) - if data == "" { - account = NewAccount(addr, big.NewInt(0)) - } else { - account = NewStateObjectFromBytes(addr, []byte(data)) - } - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - account.state = cachedStateObject - } - - return -} -*/ - func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() @@ -187,23 +113,17 @@ func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } -/* -func (s *State) Copy() *State { - state := NewState(s.trie.Copy()) - for k, subState := range s.states { - state.states[k] = subState.Copy() - } - - return state -} -*/ func (self *State) Copy() *State { - state := NewState(self.trie.Copy()) - for k, stateObject := range self.stateObjects { - state.stateObjects[k] = stateObject.Copy() + if self.trie != nil { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state } - return state + return nil } func (s *State) Snapshot() *State { @@ -259,3 +179,84 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } + +/* + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, state := range s.states { + state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, state := range s.states { + state.Sync() + } + + s.trie.Sync() +} +func (s *State) GetStateObject(addr []byte) *StateObject { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + stateObject := NewStateObjectFromBytes(addr, []byte(data)) + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) + stateObject.state = cachedStateObject + } + + return stateObject +} + +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil && s.states[string(addr)] == nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + +func (s *State) GetAccount(addr []byte) (account *StateObject) { + data := s.trie.Get(string(addr)) + if data == "" { + account = NewAccount(addr, big.NewInt(0)) + } else { + account = NewStateObjectFromBytes(addr, []byte(data)) + } + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + + return +} + +func (s *State) Copy() *State { + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} +*/ From 1d76e433f7866763674e4ef06a4a4d9463276490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:40:21 +0200 Subject: [PATCH 0437/1237] Removed some comments --- ethchain/state_transition.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 2e2a51f72d..94546e556d 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -102,7 +102,7 @@ func (self *StateTransition) BuyGas() error { if err != nil { return err } - self.state.UpdateStateObject(coinbase) + //self.state.UpdateStateObject(coinbase) self.AddGas(self.tx.Gas) sender.SubAmount(self.tx.GasValue()) @@ -177,7 +177,6 @@ func (self *StateTransition) TransitionState() (err error) { // Process the init code and create 'valid' contract if tx.CreatesContract() { - //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. From 15d1f753f7ac2f72ce0637135a17d86b29f15515 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:06 +0200 Subject: [PATCH 0438/1237] Removed old fees --- ethchain/fees.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/ethchain/fees.go b/ethchain/fees.go index c0a5d2d880..743be86a2a 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -4,30 +4,6 @@ import ( "math/big" ) -var TxFeeRat *big.Int = big.NewInt(100000000000000) - -var TxFee *big.Int = big.NewInt(100) -var StepFee *big.Int = big.NewInt(1) -var StoreFee *big.Int = big.NewInt(5) -var DataFee *big.Int = big.NewInt(20) -var ExtroFee *big.Int = big.NewInt(40) -var CryptoFee *big.Int = big.NewInt(20) -var ContractFee *big.Int = big.NewInt(100) - var BlockReward *big.Int = big.NewInt(1.5e+18) var UncleReward *big.Int = big.NewInt(1.125e+18) var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) - -var Period1Reward *big.Int = new(big.Int) -var Period2Reward *big.Int = new(big.Int) -var Period3Reward *big.Int = new(big.Int) -var Period4Reward *big.Int = new(big.Int) - -func InitFees() { - StepFee.Mul(StepFee, TxFeeRat) - StoreFee.Mul(StoreFee, TxFeeRat) - DataFee.Mul(DataFee, TxFeeRat) - ExtroFee.Mul(ExtroFee, TxFeeRat) - CryptoFee.Mul(CryptoFee, TxFeeRat) - ContractFee.Mul(ContractFee, TxFeeRat) -} From 7b55bcf4840fc11315ffd055ce7d419ac9baf168 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:19 +0200 Subject: [PATCH 0439/1237] Removed old fees --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6538b00296..24836222a9 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -179,7 +179,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + totAmount := new(big.Int).Set(tx.Value) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. if sender.Amount.Cmp(totAmount) < 0 { From b836267401b731a2cd17c4866a9727b4a05ec124 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:37 +0200 Subject: [PATCH 0440/1237] .. --- peer.go | 1 - 1 file changed, 1 deletion(-) diff --git a/peer.go b/peer.go index 0c4d763559..07c93e5b45 100644 --- a/peer.go +++ b/peer.go @@ -158,7 +158,6 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { } func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { - p := &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), quit: make(chan bool), From 9f62d441a7c785b88f89d52643a9deaa822af15e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:14:01 +0200 Subject: [PATCH 0441/1237] Moved gas limit err check to buy gas --- ethchain/state_manager.go | 8 +++-- ethchain/state_object.go | 21 ++++++++++-- ethchain/state_transition.go | 4 +-- ethchain/vm.go | 65 ++++++++++++++++++------------------ ethminer/miner.go | 3 +- 5 files changed, 59 insertions(+), 42 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c68d5e001d..4b1b872cc1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,7 +97,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { +func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts handled, unhandled Transactions @@ -177,9 +177,12 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } fmt.Println(block.Receipts()) + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.gasPool = block.CalcGasLimit(parent) + // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) - sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) + sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -194,7 +197,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return err } - //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3775d436cb..03f4c9219b 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -17,6 +17,11 @@ type StateObject struct { state *State script []byte initScript []byte + + // Total gas pool is the total amount of gas currently + // left if this object is the coinbase. Gas is directly + // purchased of the coinbase. + gasPool *big.Int } // Converts an transaction in to a state object @@ -139,14 +144,22 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) SetGasPool(gasLimit *big.Int) { + self.gasPool = new(big.Int).Set(gasLimit) + + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) +} + func (self *StateObject) BuyGas(gas, price *big.Int) error { + if self.gasPool.Cmp(gas) < 0 { + return GasLimitError(self.gasPool, gas) + } + rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) self.AddAmount(rGas) - // TODO Do sub from TotalGasPool - // and check if enough left return nil } @@ -158,7 +171,9 @@ func (self *StateObject) Copy() *StateObject { stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) copy(stCopy.ScriptHash, self.ScriptHash) stCopy.Nonce = self.Nonce - stCopy.state = self.state.Copy() + if self.state != nil { + stCopy.state = self.state.Copy() + } stCopy.script = make([]byte, len(self.script)) copy(stCopy.script, self.script) stCopy.initScript = make([]byte, len(self.initScript)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 94546e556d..76936aa7c6 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -32,8 +32,8 @@ type StateTransition struct { cb, rec, sen *StateObject } -func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase.Address(), tx, new(big.Int), state, block, coinbase, nil, nil} } func (self *StateTransition) Coinbase() *StateObject { diff --git a/ethchain/vm.go b/ethchain/vm.go index f0059f6aca..2ba0e2ef37 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -169,7 +169,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-1]) + addStepGasUsage(stack.data[stack.Len()-2]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -529,6 +529,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.UpdateStateObject(contract) } case CALL: + // TODO RE-WRITE require(7) // Closure addr addr := stack.Pop() @@ -538,46 +539,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro inSize, inOffset := stack.Popn() // Pop return size and offset retSize, retOffset := stack.Popn() - // Make sure there's enough gas - if closure.Gas.Cmp(gas) < 0 { - stack.Push(ethutil.BigFalse) - - break - } // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) snapshot := vm.state.Snapshot() - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) + closure.object.Nonce += 1 + if closure.object.Amount.Cmp(value) < 0 { + ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) - if contract != nil { - // Prepay for the gas - //closure.UseGas(gas) - - // Add the value to the state object - contract.AddAmount(value) - - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - vm.state.UpdateStateObject(contract) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) + } else { + // Fetch the contract which will serve as the closure body + contract := vm.state.GetStateObject(addr.Bytes()) + + if contract != nil { + // Add the value to the state object + contract.AddAmount(value) + + // Create a new callable closure + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + // Reset the changes applied this object + vm.state.Revert(snapshot) + } else { + stack.Push(ethutil.BigTrue) + + vm.state.UpdateStateObject(contract) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } + } else { + ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stack.Push(ethutil.BigFalse) + } } case RETURN: require(2) diff --git a/ethminer/miner.go b/ethminer/miner.go index 30b7ef35d9..8ea6c51e53 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -139,7 +139,8 @@ func (self *Miner) mineNewBlock() { // Accumulate all valid transaction and apply them to the new state // Error may be ignored. It's not important during mining - receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(self.block.Coinbase, self.block.State(), self.block, self.block, self.txs) + coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase) + receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs) if err != nil { ethutil.Config.Log.Debugln("[MINER]", err) } From 48bca30e61f869a00111abe5d818ac7379854616 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:51:16 +0200 Subject: [PATCH 0442/1237] Fixed minor issue with the gas pool --- ethchain/state_manager.go | 2 +- ethchain/state_object.go | 4 ++-- ethchain/state_transition.go | 14 ++++++++------ ethminer/miner.go | 2 ++ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4b1b872cc1..36bb148468 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -178,7 +178,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.gasPool = block.CalcGasLimit(parent) + coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 03f4c9219b..337c5a3944 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -120,13 +120,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%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)) - ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 76936aa7c6..5beef61b4c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -113,12 +113,14 @@ func (self *StateTransition) BuyGas() error { func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("state transition err %v", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("state transition err %v", r) + } + }() + */ var ( tx = self.tx diff --git a/ethminer/miner.go b/ethminer/miner.go index 8ea6c51e53..1ef9ca2296 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -139,7 +139,9 @@ func (self *Miner) mineNewBlock() { // Accumulate all valid transaction and apply them to the new state // Error may be ignored. It's not important during mining + parent := self.ethereum.BlockChain().GetBlock(self.block.PrevHash) coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase) + coinbase.SetGasPool(self.block.CalcGasLimit(parent)) receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs) if err != nil { ethutil.Config.Log.Debugln("[MINER]", err) From 8b15732c1e8a1a666ae7469bc43d989918ce754a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:04:56 +0200 Subject: [PATCH 0443/1237] Check for nil receiver --- ethchain/state_transition.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5beef61b4c..c88f4727f7 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -141,8 +141,13 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) + if sender != nil { + self.state.UpdateStateObject(sender) + } + + if receiver != nil { + self.state.UpdateStateObject(receiver) + } }() // Increment the nonce for the next transaction From 0d7763283952a57e5421565cdda19ecabe3222f7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:25:18 +0200 Subject: [PATCH 0444/1237] Refund gas --- ethchain/state_object.go | 9 +++++++++ ethchain/state_transition.go | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 337c5a3944..2c9dfb713c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -163,6 +163,15 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) RefundGas(gas, price *big.Int) { + self.gasPool.Add(self.gasPool, gas) + + rGas := new(big.Int).Set(gas) + rGas.Mul(rGas, price) + + self.Amount.Sub(self.Amount, rGas) +} + func (self *StateObject) Copy() *StateObject { stCopy := &StateObject{} stCopy.address = make([]byte, len(self.address)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c88f4727f7..25efd64cc1 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -110,6 +110,15 @@ func (self *StateTransition) BuyGas() error { return nil } +func (self *StateTransition) RefundGas() { + coinbase, sender := self.Coinbase(), self.Sender() + coinbase.RefundGas(self.gas, self.tx.GasPrice) + + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) + sender.AddAmount(remaining) +} + func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() @@ -141,6 +150,8 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { + self.RefundGas() + if sender != nil { self.state.UpdateStateObject(sender) } @@ -148,6 +159,8 @@ func (self *StateTransition) TransitionState() (err error) { if receiver != nil { self.state.UpdateStateObject(receiver) } + + self.state.UpdateStateObject(self.Coinbase()) }() // Increment the nonce for the next transaction @@ -203,10 +216,6 @@ func (self *StateTransition) TransitionState() (err error) { } } - // Return remaining gas - remaining := new(big.Int).Mul(self.gas, tx.GasPrice) - sender.AddAmount(remaining) - return nil } From 887debb0559b283962530bb42998a67dd1b69347 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 18:20:38 +0200 Subject: [PATCH 0445/1237] comment --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 2c9dfb713c..1445bcd820 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -147,7 +147,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { From ff0f15f7634ca713b0ce8232a8fa63eec5c3fad7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 18:25:21 +0200 Subject: [PATCH 0446/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b10a04c259..4a835afbff 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC12". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC13". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index 90037df87d..a24c39bfe8 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.12"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.13"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) From 53e30f750dd0c91279bfebe01bb12fd170cb74ff Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 11:06:06 +0200 Subject: [PATCH 0447/1237] Removal of manual updating of state objects * You'll only ever need to update the state by calling Update. Update will take care of the updating of it's child state objects. --- ethchain/state.go | 27 +++++++++++++++++++++++++-- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 26 +++++++++++++++----------- ethchain/state_transition.go | 26 +++++++++++++------------- ethchain/vm.go | 19 +++++++------------ ethminer/miner.go | 2 ++ 6 files changed, 65 insertions(+), 39 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 9a9d0a2784..f5a3d30718 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -38,12 +38,16 @@ func (s *State) Reset() { stateObject.state.Reset() } + + s.Empty() } // Syncs the trie and all siblings func (s *State) Sync() { // Sync all nested states for _, stateObject := range s.stateObjects { + s.UpdateStateObject(stateObject) + if stateObject.state == nil { continue } @@ -52,6 +56,18 @@ func (s *State) Sync() { } s.trie.Sync() + + s.Empty() +} + +func (self *State) Empty() { + self.stateObjects = make(map[string]*StateObject) +} + +func (self *State) Update() { + for _, stateObject := range self.stateObjects { + self.UpdateStateObject(stateObject) + } } // Purges the current trie. @@ -68,6 +84,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() if self.stateObjects[string(addr)] == nil { + panic("?") self.stateObjects[string(addr)] = stateObject } @@ -98,13 +115,19 @@ func (self *State) GetStateObject(addr []byte) *StateObject { func (self *State) GetOrNewStateObject(addr []byte) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { - stateObject = NewStateObject(addr) - self.stateObjects[string(addr)] = stateObject + stateObject = self.NewStateObject(addr) } return stateObject } +func (self *State) NewStateObject(addr []byte) *StateObject { + stateObject := NewStateObject(addr) + self.stateObjects[string(addr)] = stateObject + + return stateObject +} + func (self *State) GetAccount(addr []byte) *StateObject { return self.GetOrNewStateObject(addr) } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36bb148468..a0051181f2 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -181,7 +181,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block - //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) // Block validation @@ -197,6 +196,9 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return err } + // Update the state with pending changes + state.Update() + if !block.State().Cmp(state) { return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 1445bcd820..5fc738fee6 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -4,8 +4,15 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" + "strings" ) +type Code []byte + +func (self Code) String() string { + return strings.Join(Disassemble(self), " ") +} + type StateObject struct { // Address of the object address []byte @@ -15,8 +22,8 @@ type StateObject struct { Nonce uint64 // Contract related attributes state *State - script []byte - initScript []byte + script Code + initScript Code // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly @@ -30,12 +37,9 @@ func MakeContract(tx *Transaction, state *State) *StateObject { if tx.IsContract() { addr := tx.CreationAddress() - value := tx.Value - contract := NewContract(addr, value, ZeroHash256) - + contract := state.NewStateObject(addr) contract.initScript = tx.Data - - state.UpdateStateObject(contract) + contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) return contract } @@ -120,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%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)) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -197,12 +201,12 @@ func (c *StateObject) Address() []byte { } // Returns the main script body -func (c *StateObject) Script() []byte { +func (c *StateObject) Script() Code { return c.script } // Returns the initialization script -func (c *StateObject) Init() []byte { +func (c *StateObject) Init() Code { return c.initScript } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 25efd64cc1..23175b0f32 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -67,13 +67,8 @@ func (self *StateTransition) Receiver() *StateObject { func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - return contract - } - - return nil + return contract } func (self *StateTransition) UseGas(amount *big.Int) error { @@ -137,6 +132,8 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash()) + // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) @@ -152,15 +149,17 @@ func (self *StateTransition) TransitionState() (err error) { defer func() { self.RefundGas() - if sender != nil { - self.state.UpdateStateObject(sender) - } + /* + if sender != nil { + self.state.UpdateStateObject(sender) + } - if receiver != nil { - self.state.UpdateStateObject(receiver) - } + if receiver != nil { + self.state.UpdateStateObject(receiver) + } - self.state.UpdateStateObject(self.Coinbase()) + self.state.UpdateStateObject(self.Coinbase()) + */ }() // Increment the nonce for the next transaction @@ -209,6 +208,7 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } else { if len(receiver.Script()) > 0 { + fmt.Println(receiver.Script()) _, err := self.Eval(receiver.Script(), receiver) if err != nil { return fmt.Errorf("Error during code execution %v", err) diff --git a/ethchain/vm.go b/ethchain/vm.go index 2ba0e2ef37..77a08faa6c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -95,9 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step := 0 prevStep := 0 - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("# op\n") - } + ethutil.Config.Log.Debugf("# op\n") for { prevStep = step @@ -109,9 +107,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } + + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -525,8 +522,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigD(addr)) - - vm.state.UpdateStateObject(contract) } case CALL: // TODO RE-WRITE @@ -569,8 +564,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigTrue) - vm.state.UpdateStateObject(contract) - mem.Set(retOffset.Int64(), retSize.Int64(), ret) } } else { @@ -589,9 +582,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - vm.state.UpdateStateObject(receiver) - closure.object.state.Purge() + trie := closure.object.state.trie + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + trie.Delete(key) + }) fallthrough case STOP: // Stop the closure diff --git a/ethminer/miner.go b/ethminer/miner.go index 1ef9ca2296..4343b43336 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -154,6 +154,8 @@ func (self *Miner) mineNewBlock() { // Accumulate the rewards included for this block stateManager.AccumelateRewards(self.block.State(), self.block) + self.block.State().Update() + ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") // Find a valid nonce From 3621988e15c025d2bd7b80e4691a6b236574f0a1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 11:07:37 +0200 Subject: [PATCH 0448/1237] Removed deprecated states --- ethchain/deprecated.go | 236 ----------------------------------------- ethchain/state.go | 6 +- 2 files changed, 2 insertions(+), 240 deletions(-) delete mode 100644 ethchain/deprecated.go diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go deleted file mode 100644 index 0985fa25d0..0000000000 --- a/ethchain/deprecated.go +++ /dev/null @@ -1,236 +0,0 @@ -package ethchain - -import ( - "bytes" - "fmt" - "github.com/ethereum/eth-go/ethutil" - "math/big" -) - -func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { - contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - - return contract - } - - return nil -} - -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { - account := state.GetAccount(tx.Sender()) - - err = account.ConvertGas(tx.Gas, tx.GasPrice) - if err != nil { - ethutil.Config.Log.Debugln(err) - return - } - - closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) - vm := NewVm(state, sm, RuntimeVars{ - Origin: account.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - //Price: tx.GasPrice, - }) - ret, gas, err = closure.Call(vm, tx.Data, nil) - - // Update the account (refunds) - state.UpdateStateObject(account) - state.UpdateStateObject(object) - - return -} - -func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) - - if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return - } - - sender.Nonce += 1 - defer func() { - //state.UpdateStateObject(sender) - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - }() - - txTotalBytes := big.NewInt(int64(len(tx.Data))) - //fmt.Println("txTotalBytes", txTotalBytes) - //txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasData)) - - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) - - // Make sure there's enough in the sender's account. Having insufficient - // funds won't invalidate this transaction but simple ignores it. - totAmount := new(big.Int).Add(tx.Value, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - state.UpdateStateObject(sender) - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return - } - - coinbase.BuyGas(gas, tx.GasPrice) - state.UpdateStateObject(coinbase) - fmt.Printf("1. root %x\n", state.Root()) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) - - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) - state.UpdateStateObject(sender) - fmt.Printf("3. root %x\n", state.Root()) - - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - state.UpdateStateObject(receiver) - fmt.Printf("2. root %x\n", state.Root()) - } - - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - - return -} - -func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { - /* - Applies transactions to the given state and creates new - state objects where needed. - - If said objects needs to be created - run the initialization script provided by the transaction and - assume there's a return value. The return value will be set to - the script section of the state object. - */ - var ( - addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } - gas = new(big.Int) - script []byte - ) - totalGasUsed = big.NewInt(0) - snapshot := state.Snapshot() - - ca := state.GetAccount(coinbase) - // Apply the transaction to the current state - gas, err = sm.ProcessTransaction(tx, ca, state, false) - addTotalGas(gas) - fmt.Println("gas used by tx", gas) - - if tx.CreatesContract() { - if err == nil { - // Create a new state object and the transaction - // as it's data provider. - contract := sm.MakeStateObject(state, tx) - if contract != nil { - fmt.Println(Disassemble(contract.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) - fmt.Println("gas used by eval", gas) - addTotalGas(gas) - fmt.Println("total =", totalGasUsed) - - fmt.Println("script len =", len(script)) - - if err != nil { - err = fmt.Errorf("[STATE] Error during init script run %v", err) - return - } - contract.script = script - state.UpdateStateObject(contract) - } else { - err = fmt.Errorf("[STATE] Unable to create contract") - } - } else { - err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) - } - } else { - // Find the state object at the "recipient" address. If - // there's an object attempt to run the script. - stateObject := state.GetStateObject(tx.Recipient) - if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - addTotalGas(gas) - } - } - - parent := sm.bc.GetBlock(block.PrevHash) - total := new(big.Int).Add(block.GasUsed, totalGasUsed) - limit := block.CalcGasLimit(parent) - if total.Cmp(limit) > 0 { - state.Revert(snapshot) - err = GasLimitError(total, limit) - } - - return -} - -// Apply transactions uses the transaction passed to it and applies them onto -// the current processing state. -func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { - // Process each transaction/contract - var receipts []*Receipt - var validTxs []*Transaction - var ignoredTxs []*Transaction // Transactions which go over the gasLimit - - totalUsedGas := big.NewInt(0) - - for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) - if err != nil { - if IsNonceErr(err) { - continue - } - if IsGasLimitErr(err) { - ignoredTxs = append(ignoredTxs, tx) - // We need to figure out if we want to do something with thse txes - ethutil.Config.Log.Debugln("Gastlimit:", err) - continue - } - - ethutil.Config.Log.Infoln(err) - } - - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) - receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} - - receipts = append(receipts, receipt) - validTxs = append(validTxs, tx) - } - - fmt.Println("################# MADE\n", receipts, "\n############################") - - // Update the total gas used for the block (to be mined) - block.GasUsed = totalUsedGas - - return receipts, validTxs -} diff --git a/ethchain/state.go b/ethchain/state.go index f5a3d30718..993f1fb08b 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -13,8 +13,6 @@ import ( type State struct { // The trie for this structure trie *ethutil.Trie - // Nested states - states map[string]*State stateObjects map[string]*StateObject @@ -23,7 +21,7 @@ type State struct { // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} + return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } // Resets the trie and all siblings @@ -155,7 +153,7 @@ func (s *State) Snapshot() *State { func (s *State) Revert(snapshot *State) { s.trie = snapshot.trie - s.states = snapshot.states + s.stateObjects = snapshot.stateObjects } func (s *State) Put(key, object []byte) { From 01e6f63e98636e7200b626185b85dfa254ce2834 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 17 Jun 2014 11:40:23 +0200 Subject: [PATCH 0449/1237] A handful of GUI fixes --- ethpub/types.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ethpub/types.go b/ethpub/types.go index a764210073..31b92f6ed6 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -104,16 +104,17 @@ type PTx struct { func NewPTx(tx *ethchain.Transaction) *PTx { hash := hex.EncodeToString(tx.Hash()) receiver := hex.EncodeToString(tx.Recipient) - - if receiver == "" { + if receiver == "0000000000000000000000000000000000000000" { receiver = hex.EncodeToString(tx.CreationAddress()) } sender := hex.EncodeToString(tx.Sender()) createsContract := tx.CreatesContract() - data := string(tx.Data) + var data string if tx.CreatesContract() { data = strings.Join(ethchain.Disassemble(tx.Data), "\n") + } else { + data = hex.EncodeToString(tx.Data) } return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)} From 34c8045d5be6488e9800c24e1e696e1b912f344c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 18:05:46 +0200 Subject: [PATCH 0450/1237] Fixed issue where JUMPI would do an equally check with 1 instead of GT --- ethchain/state.go | 2 ++ ethchain/state_transition.go | 22 ++---------------- ethchain/transaction.go | 2 +- ethchain/vm.go | 14 +++++++---- ethutil/trie_test.go | 45 ++++++++++++++++++++++++++++-------- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 993f1fb08b..616ab77e0f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -120,6 +120,8 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(+) %x\n", addr) + stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 23175b0f32..dc465bbbd2 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -97,7 +97,6 @@ func (self *StateTransition) BuyGas() error { if err != nil { return err } - //self.state.UpdateStateObject(coinbase) self.AddGas(self.tx.Gas) sender.SubAmount(self.tx.GasValue()) @@ -115,7 +114,7 @@ func (self *StateTransition) RefundGas() { } func (self *StateTransition) TransitionState() (err error) { - //snapshot := st.state.Snapshot() + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) /* defer func() { @@ -132,8 +131,6 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash()) - // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) @@ -146,26 +143,11 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. - defer func() { - self.RefundGas() - - /* - if sender != nil { - self.state.UpdateStateObject(sender) - } - - if receiver != nil { - self.state.UpdateStateObject(receiver) - } - - self.state.UpdateStateObject(self.Coinbase()) - */ - }() + defer self.RefundGas() // Increment the nonce for the next transaction sender.Nonce += 1 - // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() // Transaction gas diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 3d52e4f73f..9044f586ed 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -65,7 +65,7 @@ func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } -/* Depricated */ +/* Deprecated */ func (tx *Transaction) IsContract() bool { return tx.CreatesContract() } diff --git a/ethchain/vm.go b/ethchain/vm.go index 77a08faa6c..6904331801 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -120,7 +120,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro var newMemSize uint64 = 0 switch op { case STOP: + gas.Set(ethutil.Big0) case SUICIDE: + gas.Set(ethutil.Big0) case SLOAD: gas.Set(GasSLoad) case SSTORE: @@ -296,6 +298,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EQ: require(2) x, y := stack.Popn() + fmt.Printf("%x == %x\n", x, y) // x == y if x.Cmp(y) == 0 { stack.Push(ethutil.BigTrue) @@ -365,12 +368,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro offset := stack.Pop().Int64() var data []byte - if len(closure.Args) >= int(offset+32) { - data = closure.Args[offset : offset+32] + if len(closure.Args) >= int(offset) { + l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) + data = closure.Args[offset : offset+l] } else { data = []byte{0} } + fmt.Println("CALLDATALOAD", string(data), len(data), "==", len(closure.Args)) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) @@ -452,12 +457,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) - //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) case SSTORE: require(2) val, loc := stack.Popn() - //fmt.Println("storing", val, "@", loc) + fmt.Println("storing", string(val.Bytes()), "@", string(loc.Bytes())) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest @@ -471,7 +475,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case JUMPI: require(2) cond, pos := stack.Popn() - if cond.Cmp(ethutil.BigTrue) == 0 { + if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos //pc.Sub(pc, ethutil.Big1) continue diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index c89f2fbb7b..15dbc5567e 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,12 @@ package ethutil import ( + "bytes" + "encoding/json" "fmt" + "io" + "io/ioutil" + "net/http" "reflect" "testing" ) @@ -171,14 +176,34 @@ func TestTriePurge(t *testing.T) { } } -func TestTrieIt(t *testing.T) { - _, trie := New() - trie.Update("c", LONG_WORD) - trie.Update("ca", LONG_WORD) - trie.Update("cat", LONG_WORD) - - it := trie.NewIterator() - it.Each(func(key string, node *Value) { - fmt.Println(key, ":", node.Str()) - }) +type TestItem struct { + Name string + Inputs [][]string + Expectations string +} + +func TestTrieIt(t *testing.T) { + //_, trie := New() + resp, err := http.Get("https://raw.githubusercontent.com/ethereum/tests/master/trietest.json") + if err != nil { + t.Fail() + } + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fail() + } + + dec := json.NewDecoder(bytes.NewReader(body)) + for { + var test TestItem + if err := dec.Decode(&test); err == io.EOF { + break + } else if err != nil { + t.Error("Fail something", err) + break + } + fmt.Println(test) + } } From ca79360fd7621a96382c0304e74e0d1f39b739fc Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Jun 2014 18:49:26 +0200 Subject: [PATCH 0451/1237] Verbose logging for VM --- ethchain/state_transition.go | 1 + ethchain/vm.go | 45 ++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index dc465bbbd2..c70dc54b49 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -236,6 +236,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by Diff: block.Difficulty, Value: tx.Value, }) + vm.Verbose = true ret, _, err = closure.Call(vm, tx.Data, nil) return diff --git a/ethchain/vm.go b/ethchain/vm.go index 6904331801..7a4e30a33f 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -45,6 +45,10 @@ type Vm struct { state *State stateManager *StateManager + + Verbose bool + + logStr string } type RuntimeVars struct { @@ -58,6 +62,23 @@ type RuntimeVars struct { Value *big.Int } +func (self *Vm) Printf(format string, v ...interface{}) *Vm { + if self.Verbose { + self.logStr += fmt.Sprintf(format, v...) + } + + return self +} + +func (self *Vm) Endl() *Vm { + if self.Verbose { + ethutil.Config.Log.Infoln(self.logStr) + self.logStr = "" + } + + return self +} + func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { return &Vm{vars: vars, state: state, stateManager: stateManager} } @@ -95,8 +116,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step := 0 prevStep := 0 - ethutil.Config.Log.Debugf("# op\n") - for { prevStep = step // The base for all big integer arithmetic @@ -108,7 +127,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) + //ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -193,6 +213,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) + mem.Resize(newMemSize) switch op { @@ -428,6 +450,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, a.Sub(a, big.NewInt(1))) step += int(op) - int(PUSH1) + 1 + + vm.Printf(" => %#x", data.Bytes()) case POP: require(1) stack.Pop() @@ -448,11 +472,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + vm.Printf(" => %#x", val) case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + + vm.Printf(" => %#x", val) case SLOAD: require(1) loc := stack.Pop() @@ -466,18 +494,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) + + vm.Printf(" => %#x", val) case JUMP: require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop - //pc.Sub(pc, ethutil.Big1) + vm.Printf(" ~> %v", pc).Endl() + continue case JUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - //pc.Sub(pc, ethutil.Big1) + + vm.Printf(" ~> %v", pc).Endl() + continue } case PC: @@ -603,6 +636,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro pc.Add(pc, ethutil.Big1) + vm.Endl() + if hook != nil { if !hook(prevStep, op, mem, stack, closure.Object()) { return nil, nil From 8a885c2606fbf675770cf40b31f9ceb5ef8acae9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:25:58 +0200 Subject: [PATCH 0452/1237] Fixed GT and LT --- ethchain/asm.go | 2 +- ethchain/types.go | 2 +- ethchain/vm.go | 35 ++++++++++++++++++++++++----------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index c267f9b55a..277326ff93 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("%#x", data)) + asm = append(asm, fmt.Sprintf("0x%x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/types.go b/ethchain/types.go index d89fad147e..ee70a8d281 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -226,7 +226,7 @@ var opCodeToString = map[OpCode]string{ func (o OpCode) String() string { str := opCodeToString[o] if len(str) == 0 { - return fmt.Sprintf("Missing opcode %#x", int(o)) + return fmt.Sprintf("Missing opcode 0x%x", int(o)) } return str diff --git a/ethchain/vm.go b/ethchain/vm.go index 7a4e30a33f..9dbc13eadf 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -97,7 +97,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } }() - ethutil.Config.Log.Debugf("[VM] Running closure %x\n", closure.object.Address()) + ethutil.Config.Log.Debugf("[VM] Running %x\n", closure.object.Address()) // Memory for the current closure mem := &Memory{} @@ -301,7 +301,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - x, y := stack.Popn() + y, x := stack.Popn() // x < y if x.Cmp(y) < 0 { stack.Push(ethutil.BigTrue) @@ -310,7 +310,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } case GT: require(2) - x, y := stack.Popn() + y, x := stack.Popn() + vm.Printf(" %v > %v", x, y) + // x > y if x.Cmp(y) > 0 { stack.Push(ethutil.BigTrue) @@ -382,7 +384,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case CALLER: - stack.Push(ethutil.BigD(closure.caller.Address())) + caller := closure.caller.Address() + stack.Push(ethutil.BigD(caller)) + + vm.Printf(" => %x", caller) case CALLVALUE: stack.Push(vm.vars.Value) case CALLDATALOAD: @@ -397,10 +402,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro data = []byte{0} } - fmt.Println("CALLDATALOAD", string(data), len(data), "==", len(closure.Args)) + vm.Printf(" => 0x%x", data) + stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - stack.Push(big.NewInt(int64(len(closure.Args)))) + l := int64(len(closure.Args)) + stack.Push(big.NewInt(l)) + + vm.Printf(" => %d", l) case CALLDATACOPY: case CODESIZE: case CODECOPY: @@ -451,7 +460,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro step += int(op) - int(PUSH1) + 1 - vm.Printf(" => %#x", data.Bytes()) + vm.Printf(" => 0x%x", data.Bytes()) case POP: require(1) stack.Pop() @@ -473,19 +482,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case MSTORE8: require(2) val, mStart := stack.Popn() base.And(val, new(big.Int).SetInt64(0xff)) mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case SLOAD: require(1) loc := stack.Pop() val := closure.GetMem(loc) stack.Push(val.BigInt()) + + vm.Printf(" {} 0x%x", val) case SSTORE: require(2) val, loc := stack.Popn() @@ -495,7 +506,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - vm.Printf(" => %#x", val) + vm.Printf(" => 0x%x", val) case JUMP: require(1) pc = stack.Pop() @@ -509,9 +520,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - vm.Printf(" ~> %v", pc).Endl() + vm.Printf(" (t) ~> %v", pc).Endl() continue + } else { + vm.Printf(" (f)") } case PC: stack.Push(pc) From 2565a79575c6a6b839a6585c9ad3ebbcf7db9115 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:32:48 +0200 Subject: [PATCH 0453/1237] Swapped vars --- ethchain/vm.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 9dbc13eadf..f832584303 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -226,28 +226,28 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(2) x, y := stack.Popn() // (x + y) % 2 ** 256 - base.Add(x, y) + base.Add(y, x) // Pop result back on the stack stack.Push(base) case SUB: require(2) x, y := stack.Popn() // (x - y) % 2 ** 256 - base.Sub(x, y) + base.Sub(y, x) // Pop result back on the stack stack.Push(base) case MUL: require(2) x, y := stack.Popn() // (x * y) % 2 ** 256 - base.Mul(x, y) + base.Mul(y, x) // Pop result back on the stack stack.Push(base) case DIV: require(2) x, y := stack.Popn() // floor(x / y) - base.Div(x, y) + base.Div(y, x) // Pop result back on the stack stack.Push(base) case SDIV: @@ -270,7 +270,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MOD: require(2) x, y := stack.Popn() - base.Mod(x, y) + base.Mod(y, x) stack.Push(base) case SMOD: require(2) @@ -292,7 +292,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EXP: require(2) x, y := stack.Popn() - base.Exp(x, y, Pow256) + base.Exp(y, x, Pow256) stack.Push(base) case NEG: @@ -302,6 +302,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case LT: require(2) y, x := stack.Popn() + vm.Printf(" %v < %v", x, y) // x < y if x.Cmp(y) < 0 { stack.Push(ethutil.BigTrue) @@ -342,20 +343,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case AND: require(2) x, y := stack.Popn() - if (x.Cmp(ethutil.BigTrue) >= 0) && (y.Cmp(ethutil.BigTrue) >= 0) { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - + stack.Push(base.And(y, x)) case OR: require(2) x, y := stack.Popn() - if (x.Cmp(ethutil.BigInt0) >= 0) || (y.Cmp(ethutil.BigInt0) >= 0) { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } + stack.Push(base.Or(y, x)) case XOR: require(2) x, y := stack.Popn() From dc9c9369e0b44873dedfdf37195268f0e524872d Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 00:36:23 +0200 Subject: [PATCH 0454/1237] log --- ethchain/vm.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index f832584303..b8ba72c7e0 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -323,7 +323,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EQ: require(2) x, y := stack.Popn() - fmt.Printf("%x == %x\n", x, y) + vm.Printf(" %v == %v", y, x) + // x == y if x.Cmp(y) == 0 { stack.Push(ethutil.BigTrue) @@ -343,15 +344,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case AND: require(2) x, y := stack.Popn() + vm.Printf(" %v & %v", y, x) + stack.Push(base.And(y, x)) case OR: require(2) x, y := stack.Popn() + vm.Printf(" %v | %v", y, x) + stack.Push(base.Or(y, x)) case XOR: require(2) x, y := stack.Popn() - stack.Push(base.Xor(x, y)) + vm.Printf(" %v ^ %v", y, x) + + stack.Push(base.Xor(y, x)) case BYTE: require(2) val, th := stack.Popn() From 22e16f15a69f53934a61978eb18fdf0244a74a99 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 18 Jun 2014 10:39:42 +0200 Subject: [PATCH 0455/1237] Reduce peer timeout to 10 seconds --- peer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/peer.go b/peer.go index 07c93e5b45..5362b0f778 100644 --- a/peer.go +++ b/peer.go @@ -124,6 +124,7 @@ type Peer struct { port uint16 caps Caps + // This peer's public key pubkey []byte // Indicated whether the node is catching up or not @@ -171,7 +172,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { // Set up the connection in another goroutine so we don't block the main thread go func() { - conn, err := net.DialTimeout("tcp", addr, 30*time.Second) + conn, err := net.DialTimeout("tcp", addr, 10*time.Second) if err != nil { ethutil.Config.Log.Debugln("Connection to peer failed", err) From 2fbcfd88249de8f55b7f06619d9003fadcc8e1e3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 11:55:05 +0200 Subject: [PATCH 0456/1237] Proper checks for multiple data items. Fixes #80 --- ethpub/pub.go | 5 ----- ethutil/bytes.go | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 20ba79d0b1..b475453af0 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -170,11 +170,6 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc tx = ethchain.NewContractCreationTx(value, gas, gasPrice, script) } else { - // Just in case it was submitted as a 0x prefixed string - if len(scriptStr) > 0 && scriptStr[0:2] == "0x" { - scriptStr = scriptStr[2:len(scriptStr)] - } - data := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) { slice := strings.Split(s, "\n") for _, dataItem := range slice { diff --git a/ethutil/bytes.go b/ethutil/bytes.go index bd0df68ecd..5e3ee4a6f6 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "math/big" + "strings" ) // Number to bytes @@ -91,7 +92,7 @@ func IsHex(str string) bool { } func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { - if len(str) > 1 && str[0:2] == "0x" { + if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") { ret = FromHex(str[2:]) } else { ret = cb(str) From 1f7917589822d4327147949c610fad3979819ab3 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 18 Jun 2014 13:06:48 +0200 Subject: [PATCH 0457/1237] Reworked peers to check for public key duplication and adding peers to peerlist only after the handshake has come in --- ethereum.go | 14 ++++---------- peer.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/ethereum.go b/ethereum.go index d9281cd574..a6cb78b1fc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -149,7 +149,9 @@ func (s *Ethereum) IsUpToDate() bool { }) return upToDate } - +func (s *Ethereum) PushPeer(peer *Peer) { + s.peers.PushBack(peer) +} func (s *Ethereum) IsListening() bool { return s.listening } @@ -159,14 +161,11 @@ func (s *Ethereum) AddPeer(conn net.Conn) { if peer != nil { if s.peers.Len() < s.MaxPeers { - s.peers.PushBack(peer) peer.Start() } else { ethutil.Config.Log.Debugf("[SERV] Max connected peers reached. Not adding incoming peer.") } } - - s.reactor.Post("peerList", s.peers) } func (s *Ethereum) ProcessPeerList(addrs []string) { @@ -233,12 +232,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { return nil } - peer := NewOutboundPeer(addr, s, s.serverCaps) - - s.peers.PushBack(peer) - - ethutil.Config.Log.Infof("[SERV] Adding peer (%s) %d / %d\n", addr, s.peers.Len(), s.MaxPeers) - s.reactor.Post("peerList", s.peers) + NewOutboundPeer(addr, s, s.serverCaps) } return nil diff --git a/peer.go b/peer.go index 5362b0f778..2ece9b3596 100644 --- a/peer.go +++ b/peer.go @@ -2,6 +2,7 @@ package eth import ( "bytes" + "container/list" "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" @@ -615,6 +616,30 @@ func (p *Peer) pushPeers() { func (p *Peer) handleHandshake(msg *ethwire.Msg) { c := msg.Data + // Set pubkey + p.pubkey = c.Get(5).Bytes() + + if p.pubkey == nil { + //ethutil.Config.Log.Debugln("Pubkey required, not supplied in handshake.") + p.Stop() + return + } + + usedPub := 0 + // This peer is already added to the peerlist so we expect to find a double pubkey at least once + + eachPeer(p.ethereum.Peers(), func(peer *Peer, e *list.Element) { + if bytes.Compare(p.pubkey, peer.pubkey) == 0 { + usedPub++ + } + }) + + if usedPub > 0 { + //ethutil.Config.Log.Debugf("Pubkey %x found more then once. Already connected to client.", p.pubkey) + p.Stop() + return + } + if c.Get(0).Uint() != ProtocolVersion { ethutil.Config.Log.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint()) p.Stop() @@ -626,7 +651,6 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { // If this is an inbound connection send an ack back if p.inbound { - p.pubkey = c.Get(5).Bytes() p.port = uint16(c.Get(4).Uint()) // Self connect detection @@ -648,6 +672,11 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.SetVersion(c.Get(2).Str()) } + p.ethereum.PushPeer(p) + p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) + + ethutil.Config.Log.Infof("[SERV] Added peer (%s) %d / %d\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) + // Catch up with the connected peer if !p.ethereum.IsUpToDate() { ethutil.Config.Log.Debugln("Already syncing up with a peer; sleeping") From 7f94bd09ae5791836d94d4d9efb9e345212e49b6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:47:40 +0200 Subject: [PATCH 0458/1237] Return a single byte if byte get called --- ethutil/value.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethutil/value.go b/ethutil/value.go index c86c24a7a7..ddd864d8a3 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -114,6 +114,8 @@ func (val *Value) Str() string { func (val *Value) Bytes() []byte { if a, ok := val.Val.([]byte); ok { return a + } else if s, ok := val.Val.(byte); ok { + return []byte{s} } return []byte{} From 3bc57fe5b5182cd2e0ae0c6b53b3bbb02ce34304 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:08 +0200 Subject: [PATCH 0459/1237] CALLDATALOAD return 32 byte at all times --- ethchain/vm.go | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index b8ba72c7e0..5a15ba81be 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -225,29 +225,41 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ADD: require(2) x, y := stack.Popn() - // (x + y) % 2 ** 256 + vm.Printf(" %v + %v", y, x) + base.Add(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case SUB: require(2) x, y := stack.Popn() - // (x - y) % 2 ** 256 + vm.Printf(" %v - %v", y, x) + base.Sub(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case MUL: require(2) x, y := stack.Popn() - // (x * y) % 2 ** 256 + vm.Printf(" %v * %v", y, x) + base.Mul(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case DIV: require(2) x, y := stack.Popn() - // floor(x / y) + vm.Printf(" %v / %v", y, x) + base.Div(y, x) + + vm.Printf(" = %v", base) // Pop result back on the stack stack.Push(base) case SDIV: @@ -270,7 +282,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MOD: require(2) x, y := stack.Popn() + + vm.Printf(" %v %% %v", y, x) + base.Mod(y, x) + + vm.Printf(" = %v", base) stack.Push(base) case SMOD: require(2) @@ -292,8 +309,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case EXP: require(2) x, y := stack.Popn() + + vm.Printf(" %v ** %v", y, x) + base.Exp(y, x, Pow256) + vm.Printf(" = %v", base) + stack.Push(base) case NEG: require(1) @@ -393,12 +415,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) offset := stack.Pop().Int64() - var data []byte + data := make([]byte, 32) if len(closure.Args) >= int(offset) { l := int64(math.Min(float64(offset+32), float64(len(closure.Args)))) - data = closure.Args[offset : offset+l] - } else { - data = []byte{0} + + copy(data, closure.Args[offset:l]) } vm.Printf(" => 0x%x", data) @@ -499,13 +520,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SSTORE: require(2) val, loc := stack.Popn() - fmt.Println("storing", string(val.Bytes()), "@", string(loc.Bytes())) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) - vm.Printf(" => 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc, val) case JUMP: require(1) pc = stack.Pop() @@ -519,7 +539,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if cond.Cmp(ethutil.BigTrue) >= 0 { pc = pos - vm.Printf(" (t) ~> %v", pc).Endl() + vm.Printf(" ~> %v (t)", pc).Endl() continue } else { From c4af1340fac12397b6cc5c9f32a1bea4aa6400f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:29 +0200 Subject: [PATCH 0460/1237] Updated test --- ethutil/trie_test.go | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 15dbc5567e..2937b15250 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,12 +1,7 @@ package ethutil import ( - "bytes" - "encoding/json" "fmt" - "io" - "io/ioutil" - "net/http" "reflect" "testing" ) @@ -176,34 +171,23 @@ func TestTriePurge(t *testing.T) { } } -type TestItem struct { - Name string - Inputs [][]string - Expectations string -} - func TestTrieIt(t *testing.T) { - //_, trie := New() - resp, err := http.Get("https://raw.githubusercontent.com/ethereum/tests/master/trietest.json") - if err != nil { - t.Fail() + _, trie := New() + + data := [][]string{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"ether", ""}, + {"dog", "puppy"}, + {"shaman", ""}, } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fail() + for _, item := range data { + trie.Update(item[0], item[1]) } - dec := json.NewDecoder(bytes.NewReader(body)) - for { - var test TestItem - if err := dec.Decode(&test); err == io.EOF { - break - } else if err != nil { - t.Error("Fail something", err) - break - } - fmt.Println(test) - } + fmt.Printf("root %x", trie.Root) } From f911087eab6b31fcdbc22a9a74c0be410e8f0177 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 18 Jun 2014 13:48:42 +0200 Subject: [PATCH 0461/1237] Logging --- ethchain/state_transition.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c70dc54b49..8a6565e56c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -89,7 +89,7 @@ func (self *StateTransition) BuyGas() error { sender := self.Sender() if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Amount) } coinbase := self.Coinbase() @@ -181,7 +181,8 @@ func (self *StateTransition) TransitionState() (err error) { // Evaluate the initialization script // and use the return value as the // script section for the state object. - //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) + code, err := self.Eval(receiver.Init(), receiver) if err != nil { return fmt.Errorf("Error during init script run %v", err) @@ -190,7 +191,8 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } else { if len(receiver.Script()) > 0 { - fmt.Println(receiver.Script()) + ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) + _, err := self.Eval(receiver.Script(), receiver) if err != nil { return fmt.Errorf("Error during code execution %v", err) From 731f55a05db44fcd5191bd7af6c99f4a4433e342 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:41:17 +0200 Subject: [PATCH 0462/1237] Reset state when a transition fails --- ethchain/state.go | 7 +- ethchain/state_transition.go | 134 +++++++++++++++++++++++------------ 2 files changed, 94 insertions(+), 47 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 616ab77e0f..98fcb24db4 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -78,11 +78,16 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } +func (self *State) ResetStateObject(stateObject *StateObject) { + stateObject.state.Reset() + + delete(self.stateObjects, string(stateObject.Address())) +} + func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() if self.stateObjects[string(addr)] == nil { - panic("?") self.stateObjects[string(addr)] = stateObject } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8a6565e56c..8757246a01 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -23,17 +23,36 @@ import ( * 6) Derive new state root */ type StateTransition struct { - coinbase []byte - tx *Transaction - gas *big.Int - state *State - block *Block + coinbase, receiver []byte + tx *Transaction + gas, gasPrice *big.Int + value *big.Int + data []byte + state *State + block *Block cb, rec, sen *StateObject } +func Transition(coinbase, sender, receiver, data []byte, gas, gasPrice, value *big.Int, state *State, block *Block) (ret []byte, err error) { + stateTransition := &StateTransition{ + coinbase: coinbase, + receiver: receiver, + cb: state.GetOrNewStateObject(coinbase), + rec: state.GetOrNewStateObject(receiver), + sen: state.GetOrNewStateObject(sender), + gas: gas, + gasPrice: gasPrice, + value: value, + state: state, + block: block, + } + + return stateTransition.Transition() +} + func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase.Address(), tx, new(big.Int), state, block, coinbase, nil, nil} + return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } func (self *StateTransition) Coinbase() *StateObject { @@ -53,7 +72,7 @@ func (self *StateTransition) Sender() *StateObject { return self.sen } func (self *StateTransition) Receiver() *StateObject { - if self.tx.CreatesContract() { + if self.tx != nil && self.tx.CreatesContract() { return nil } @@ -113,22 +132,10 @@ func (self *StateTransition) RefundGas() { sender.AddAmount(remaining) } -func (self *StateTransition) TransitionState() (err error) { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) - - /* - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("state transition err %v", r) - } - }() - */ - +func (self *StateTransition) preCheck() (err error) { var ( - tx = self.tx - sender = self.Sender() - receiver *StateObject + tx = self.tx + sender = self.Sender() ) // Make sure this transaction's nonce is correct @@ -141,10 +148,40 @@ func (self *StateTransition) TransitionState() (err error) { return err } + return nil +} + +func (self *StateTransition) TransitionState() (err error) { + ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) + + /* + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("state transition err %v", r) + } + }() + */ + // XXX Transactions after this point are considered valid. + if err = self.preCheck(); err != nil { + return + } defer self.RefundGas() + _, err = self.Transition() + + return +} + +func (self *StateTransition) Transition() (ret []byte, err error) { + var ( + tx = self.tx + sender = self.Sender() + receiver *StateObject + ) + // Increment the nonce for the next transaction sender.Nonce += 1 @@ -152,14 +189,14 @@ func (self *StateTransition) TransitionState() (err error) { // Transaction gas if err = self.UseGas(GasTx); err != nil { - return err + return } // Pay data gas - dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice := big.NewInt(int64(len(self.data))) dataPrice.Mul(dataPrice, GasData) if err = self.UseGas(dataPrice); err != nil { - return err + return } // If the receiver is nil it's a contract (\0*32). @@ -167,25 +204,28 @@ func (self *StateTransition) TransitionState() (err error) { // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { - return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + return nil, fmt.Errorf("Unable to create contract") } } // Transfer value from sender to receiver if err = self.transferValue(sender, receiver); err != nil { - return err + return } // Process the init code and create 'valid' contract - if tx.CreatesContract() { + if IsContractAddr(self.receiver) { // Evaluate the initialization script // and use the return value as the // script section for the state object. + self.data = nil ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) code, err := self.Eval(receiver.Init(), receiver) if err != nil { - return fmt.Errorf("Error during init script run %v", err) + self.state.ResetStateObject(receiver) + + return nil, fmt.Errorf("Error during init script run %v", err) } receiver.script = code @@ -193,53 +233,55 @@ func (self *StateTransition) TransitionState() (err error) { if len(receiver.Script()) > 0 { ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) - _, err := self.Eval(receiver.Script(), receiver) + ret, err = self.Eval(receiver.Script(), receiver) if err != nil { - return fmt.Errorf("Error during code execution %v", err) + self.state.ResetStateObject(receiver) + + return nil, fmt.Errorf("Error during code execution %v", err) } } } - return nil + return } func (self *StateTransition) transferValue(sender, receiver *StateObject) error { - if sender.Amount.Cmp(self.tx.Value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) + if sender.Amount.Cmp(self.value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } - if self.tx.Value.Cmp(ethutil.Big0) > 0 { - // Subtract the amount from the senders account - sender.SubAmount(self.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.tx.Value) + //if self.value.Cmp(ethutil.Big0) > 0 { + // 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) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) - } + //ethutil.Config.Log.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) + //} return nil } func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { var ( - tx = self.tx block = self.block initiator = self.Sender() state = self.state ) - closure := NewClosure(initiator, context, script, state, self.gas, tx.GasPrice) + closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: initiator.Address(), - BlockNumber: block.BlockInfo().Number, + Block: block, + BlockNumber: block.Number, PrevHash: block.PrevHash, Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, - Value: tx.Value, + Value: self.value, }) vm.Verbose = true - ret, _, err = closure.Call(vm, tx.Data, nil) + ret, _, err = closure.Call(vm, self.data, nil) return } From 5ea7598408321dcc15ae3dc2f2a740c9c2c644e1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:14 +0200 Subject: [PATCH 0463/1237] Update after each transition instead of at the end. Updating the state /after/ the entire transition creates invalid receipts. --- ethchain/state_manager.go | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index a0051181f2..b20ea401c6 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -127,6 +127,9 @@ done: // Notify all subscribers self.Ethereum.Reactor().Post("newTx:post", tx) + // Update the state with pending changes + state.Update() + txGas.Sub(txGas, st.gas) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} @@ -135,8 +138,6 @@ done: handled = append(handled, tx) } - fmt.Println("################# MADE\n", receipts, "\n############################") - parent.GasUsed = totalUsedGas return receipts, handled, unhandled, err @@ -154,7 +155,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) error { } // Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -175,32 +176,42 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } - fmt.Println(block.Receipts()) coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) + fmt.Println(block.Receipts()) + // Process the transactions on to current block - sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + defer func() { + if err != nil { + if len(receipts) == len(block.Receipts()) { + for i, receipt := range block.Receipts() { + ethutil.Config.Log.Debugf("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 { + ethutil.Config.Log.Debugln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) + } + } + }() // Block validation - if err := sm.ValidateBlock(block); err != nil { + if err = sm.ValidateBlock(block); err != nil { fmt.Println("[SM] Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. - if err := sm.AccumelateRewards(state, block); err != nil { + if err = sm.AccumelateRewards(state, block); err != nil { fmt.Println("[SM] Error accumulating reward", err) return err } - // Update the state with pending changes - state.Update() - if !block.State().Cmp(state) { - return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + return } // Calculate the new total difficulty and sync back to the db From 1b431f29e5c2283fb3d7a0c035e7ec575a563ca7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:28 +0200 Subject: [PATCH 0464/1237] Added missing types --- ethchain/types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethchain/types.go b/ethchain/types.go index ee70a8d281..9e7269f741 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -166,6 +166,7 @@ var opCodeToString = map[OpCode]string{ GASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution + POP: "POP", DUP: "DUP", SWAP: "SWAP", MLOAD: "MLOAD", From 7e6684d92600bc7def9469abea6d7abf33439017 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:42:47 +0200 Subject: [PATCH 0465/1237] Method for checking contract addresses --- ethchain/transaction.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 9044f586ed..34ab357a17 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -10,6 +10,10 @@ import ( var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +func IsContractAddr(addr []byte) bool { + return bytes.Compare(addr, ContractAddr) == 0 +} + type Transaction struct { Nonce uint64 Recipient []byte @@ -149,7 +153,7 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if bytes.Compare(tx.Recipient, ContractAddr) == 0 { + if IsContractAddr(tx.Recipient) { tx.contractCreation = true } } From 9104dcc29c96baf645ff567bdd6800dc30b2784a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:45:29 +0200 Subject: [PATCH 0466/1237] Fixed call --- ethchain/vm.go | 73 +++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index 5a15ba81be..6c30c94173 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,7 +53,8 @@ type Vm struct { type RuntimeVars struct { Origin []byte - BlockNumber uint64 + Block *Block + BlockNumber *big.Int PrevHash []byte Coinbase []byte Time int64 @@ -90,14 +91,14 @@ var isRequireError = false func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err error) { // Recover from any require exception defer func() { - if r := recover(); r != nil /*&& isRequireError*/ { + if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) fmt.Println("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] Running %x\n", closure.object.Address()) + ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) // Memory for the current closure mem := &Memory{} @@ -128,7 +129,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro op := OpCode(val.Uint()) vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - //ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -188,7 +188,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-2]) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -208,9 +208,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } if !closure.UseGas(gas) { - ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) + err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) - return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) + closure.UseGas(closure.Gas) + + return closure.Return(nil), err } vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) @@ -431,7 +433,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: + panic("not implemented") case CODESIZE: + stack.Push(big.NewInt(int64(len(closure.Script)))) case CODECOPY: var ( size = int64(len(closure.Script)) @@ -461,7 +465,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case TIMESTAMP: stack.Push(big.NewInt(vm.vars.Time)) case NUMBER: - stack.Push(big.NewInt(int64(vm.vars.BlockNumber))) + stack.Push(vm.vars.BlockNumber) case DIFFICULTY: stack.Push(vm.vars.Diff) case GASLIMIT: @@ -595,10 +599,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: // TODO RE-WRITE require(7) - // Closure addr - addr := stack.Pop() + + vm.Endl() + + gas := stack.Pop() // Pop gas and value of the stack. - gas, value := stack.Popn() + value, addr := stack.Popn() // Pop input size and offset inSize, inOffset := stack.Popn() // Pop return size and offset @@ -607,37 +613,34 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - snapshot := vm.state.Snapshot() + //snapshot := vm.state.Snapshot() - closure.object.Nonce += 1 if closure.object.Amount.Cmp(value) < 0 { ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) + stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) - if contract != nil { - // Add the value to the state object - contract.AddAmount(value) + closure.object.SubAmount(value) + // Add the value to the state object + stateObject.AddAmount(value) - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + // Create a new callable closure + closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { stack.Push(ethutil.BigFalse) + + // Reset the changes applied this object + vm.state.ResetStateObject(stateObject) + + ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } } case RETURN: @@ -645,6 +648,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) + vm.Printf(" => 0x%x", ret).Endl() + return closure.Return(ret), nil case SUICIDE: require(1) @@ -659,6 +664,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure + vm.Endl() + return closure.Return(nil), nil default: ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) From 80ffe1610c87bc56f625797a4f839a931af70558 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 13:45:46 +0200 Subject: [PATCH 0467/1237] Removed log --- ethchain/state_manager.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index b20ea401c6..59cd8eec60 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -180,8 +180,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) - fmt.Println(block.Receipts()) - // Process the transactions on to current block receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) defer func() { From 933aa63b7d302cff4287ba2814f3bd0f7744ed8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Jun 2014 21:41:37 +0200 Subject: [PATCH 0468/1237] Length check on get --- ethchain/stack.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ethchain/stack.go b/ethchain/stack.go index 37d1f84b9f..a9fa2e5224 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -2,7 +2,7 @@ package ethchain import ( "fmt" - _ "github.com/ethereum/eth-go/ethutil" + "math" "math/big" ) @@ -118,7 +118,13 @@ func (m *Memory) Resize(size uint64) { } func (m *Memory) Get(offset, size int64) []byte { - return m.store[offset : offset+size] + if len(m.store) > int(offset) { + end := int(math.Min(float64(len(m.store)), float64(offset+size))) + + return m.store[offset:end] + } + + return nil } func (m *Memory) Len() int { From 0b8ba1d55b6b4cdb63e0967790e34b1b499b638f Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:41:28 +0200 Subject: [PATCH 0469/1237] Renamed snapshot to copy/set and added it back to the VM --- ethchain/state.go | 15 ++++++--------- ethchain/vm.go | 39 ++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 98fcb24db4..a08dfac83e 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -79,9 +79,9 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { } func (self *State) ResetStateObject(stateObject *StateObject) { - stateObject.state.Reset() - delete(self.stateObjects, string(stateObject.Address())) + + stateObject.state.Reset() } func (self *State) UpdateStateObject(stateObject *StateObject) { @@ -154,13 +154,10 @@ func (self *State) Copy() *State { return nil } -func (s *State) Snapshot() *State { - return s.Copy() -} - -func (s *State) Revert(snapshot *State) { - s.trie = snapshot.trie - s.stateObjects = snapshot.stateObjects +func (self *State) Set(state *State) { + //s.trie = snapshot.trie + //s.stateObjects = snapshot.stateObjects + self = state } func (s *State) Put(key, object []byte) { diff --git a/ethchain/vm.go b/ethchain/vm.go index 6c30c94173..fc3c37dc16 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -1,12 +1,9 @@ package ethchain import ( - _ "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" - _ "github.com/obscuren/secp256k1-go" "math" - _ "math" "math/big" ) @@ -49,6 +46,8 @@ type Vm struct { Verbose bool logStr string + + err error } type RuntimeVars struct { @@ -128,11 +127,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { - gas.Add(gas, amount) + if amount.Cmp(ethutil.Big0) >= 0 { + gas.Add(gas, amount) + } } addStepGasUsage(GasStep) @@ -215,6 +214,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), err } + vm.Printf("(pc) %-3d -o- %-14s", pc, op.String()) vm.Printf(" (g) %-3v (%v)", gas, closure.Gas) mem.Resize(newMemSize) @@ -491,6 +491,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case DUP: require(1) stack.Push(stack.Peek()) + + vm.Printf(" => 0x%x", stack.Peek().Bytes()) case SWAP: require(2) x, y := stack.Popn() @@ -524,7 +526,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SSTORE: require(2) val, loc := stack.Popn() - closure.SetStorage(loc, ethutil.NewValue(val)) + + // FIXME This should be handled in the Trie it self + if val.Cmp(big.NewInt(0)) != 0 { + closure.SetStorage(loc, ethutil.NewValue(val)) + } // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -564,7 +570,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Snapshot the current stack so we are able to // revert back to it later. - snapshot := vm.state.Snapshot() + snapshot := vm.state.Copy() // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) @@ -592,12 +598,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigFalse) // Revert the state as it was before. - vm.state.Revert(snapshot) + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigD(addr)) } case CALL: - // TODO RE-WRITE require(7) vm.Endl() @@ -613,13 +618,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - //snapshot := vm.state.Snapshot() - if closure.object.Amount.Cmp(value) < 0 { ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { + snapshot := vm.state.Copy() + stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) closure.object.SubAmount(value) @@ -633,10 +638,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.ResetStateObject(stateObject) - ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + + vm.err = err + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigTrue) @@ -648,7 +653,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - vm.Printf(" => 0x%x", ret).Endl() + vm.Printf(" => (%d) 0x%x", len(ret), ret).Endl() return closure.Return(ret), nil case SUICIDE: @@ -664,7 +669,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Endl() + vm.Printf(" (g) %v", closure.Gas).Endl() return closure.Return(nil), nil default: From 6fcc6a2f7c35f10a8be3fc90bab39f2865adace9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:41:42 +0200 Subject: [PATCH 0470/1237] Changed copy/set --- ethchain/state_object.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5fc738fee6..5b64c3b372 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -48,7 +48,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - return &StateObject{address: addr, Amount: new(big.Int)} + return &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { @@ -176,6 +176,26 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { self.Amount.Sub(self.Amount, rGas) } +func (self *StateObject) Copy() *StateObject { + stateObject := NewStateObject(self.Address()) + stateObject.Amount.Set(self.Amount) + stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash) + stateObject.Nonce = self.Nonce + if self.state != nil { + stateObject.state = self.state.Copy() + } + stateObject.script = ethutil.CopyBytes(self.script) + stateObject.initScript = ethutil.CopyBytes(self.initScript) + //stateObject.gasPool.Set(self.gasPool) + + return self +} + +func (self *StateObject) Set(stateObject *StateObject) { + self = stateObject +} + +/* func (self *StateObject) Copy() *StateObject { stCopy := &StateObject{} stCopy.address = make([]byte, len(self.address)) @@ -194,6 +214,7 @@ func (self *StateObject) Copy() *StateObject { return stCopy } +*/ // Returns the address of the contract/account func (c *StateObject) Address() []byte { From 8f29f6a4d4e2c62d3eff0dfd84cc8cab59dd28e8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:42:26 +0200 Subject: [PATCH 0471/1237] Removed some logging --- ethchain/state_manager.go | 2 ++ ethchain/state_transition.go | 17 ++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 59cd8eec60..36ba1731c1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -281,10 +281,12 @@ func (sm *StateManager) ValidateBlock(block *Block) error { return ValidationError("Block timestamp less then prev block %v", diff) } + /* XXX // New blocks must be within the 15 minute range of the last block. if diff > int64(15*time.Minute) { return ValidationError("Block is too far in the future of last block (> 15 minutes)") } + */ // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 8757246a01..5f4588e482 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -219,25 +219,23 @@ func (self *StateTransition) Transition() (ret []byte, err error) { // and use the return value as the // script section for the state object. self.data = nil - ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Init()) - code, err := self.Eval(receiver.Init(), receiver) - if err != nil { + code, err, deepErr := self.Eval(receiver.Init(), receiver) + if err != nil || deepErr { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during init script run %v", err) + return nil, fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) } receiver.script = code } else { if len(receiver.Script()) > 0 { - ethutil.Config.Log.Println(ethutil.LogLevelSystem, receiver.Script()) - - ret, err = self.Eval(receiver.Script(), receiver) + var deepErr bool + ret, err, deepErr = self.Eval(receiver.Script(), receiver) if err != nil { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during code execution %v", err) + return nil, fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) } } } @@ -262,7 +260,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } -func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block initiator = self.Sender() @@ -282,6 +280,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by }) vm.Verbose = true ret, _, err = closure.Call(vm, self.data, nil) + deepErr = vm.err != nil return } From 09f37bd0235198145974db6430da0c429d2a0e79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:45:44 +0200 Subject: [PATCH 0472/1237] Returned to single method --- ethchain/state_transition.go | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5f4588e482..1f5b4f9592 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -34,23 +34,6 @@ type StateTransition struct { cb, rec, sen *StateObject } -func Transition(coinbase, sender, receiver, data []byte, gas, gasPrice, value *big.Int, state *State, block *Block) (ret []byte, err error) { - stateTransition := &StateTransition{ - coinbase: coinbase, - receiver: receiver, - cb: state.GetOrNewStateObject(coinbase), - rec: state.GetOrNewStateObject(receiver), - sen: state.GetOrNewStateObject(sender), - gas: gas, - gasPrice: gasPrice, - value: value, - state: state, - block: block, - } - - return stateTransition.Transition() -} - func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } @@ -168,20 +151,14 @@ func (self *StateTransition) TransitionState() (err error) { return } - defer self.RefundGas() - - _, err = self.Transition() - - return -} - -func (self *StateTransition) Transition() (ret []byte, err error) { var ( tx = self.tx sender = self.Sender() receiver *StateObject ) + defer self.RefundGas() + // Increment the nonce for the next transaction sender.Nonce += 1 @@ -204,7 +181,7 @@ func (self *StateTransition) Transition() (ret []byte, err error) { // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { - return nil, fmt.Errorf("Unable to create contract") + return fmt.Errorf("Unable to create contract") } } @@ -224,18 +201,18 @@ func (self *StateTransition) Transition() (ret []byte, err error) { if err != nil || deepErr { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during init script run %v (deepErr = %v)", err, deepErr) } receiver.script = code } else { if len(receiver.Script()) > 0 { var deepErr bool - ret, err, deepErr = self.Eval(receiver.Script(), receiver) + _, err, deepErr = self.Eval(receiver.Script(), receiver) if err != nil { self.state.ResetStateObject(receiver) - return nil, fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) + return fmt.Errorf("Error during code execution %v (deepErr = %v)", err, deepErr) } } } From 7ad073fb30e92689942d938939223bd01cb5fe38 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 00:47:50 +0200 Subject: [PATCH 0473/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a835afbff..dda1e3a839 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC13". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC14". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index a24c39bfe8..a573e108bc 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -75,7 +75,7 @@ func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id s if Config == nil { path := ApplicationFolder(base) - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.13"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.14"} Config.conf = g Config.Identifier = id Config.Log = NewLogger(logTypes, LogLevelDebug) From 0c6b41f4c9edf33cf36b5e044b62e29161d50b07 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 01:10:20 +0200 Subject: [PATCH 0474/1237] CALLDATACOPY --- ethchain/vm.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index fc3c37dc16..b9e8353fbe 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -433,9 +433,28 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: - panic("not implemented") + var ( + size = int64(len(closure.Args)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Args[cOff : cOff+l] + + mem.Set(mOff, l, code) case CODESIZE: - stack.Push(big.NewInt(int64(len(closure.Script)))) + l := big.NewInt(int64(len(closure.Script))) + stack.Push(l) + + vm.Printf(" => %d", l) case CODECOPY: var ( size = int64(len(closure.Script)) From 0251fae5ccf6984c558d59cd2b36ef89116c061e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 01:10:39 +0200 Subject: [PATCH 0475/1237] Changed loggers --- peer.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/peer.go b/peer.go index 2ece9b3596..b4bde2c1d6 100644 --- a/peer.go +++ b/peer.go @@ -419,7 +419,7 @@ func (p *Peer) HandleInbound() { if p.catchingUp && msg.Data.Len() > 1 { if lastBlock != nil { blockInfo := lastBlock.BlockInfo() - ethutil.Config.Log.Debugf("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false @@ -486,7 +486,7 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { - ethutil.Config.Log.Debugf("[PEER] Found canonical block, returning chain from: %x ", parent.Hash()) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "[PEER] Found canonical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { //ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) @@ -506,7 +506,7 @@ func (p *Peer) HandleInbound() { } } case ethwire.MsgNotInChainTy: - ethutil.Config.Log.Debugf("Not in chain: %x\n", msg.Data.Get(0).Bytes()) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Not in chain: %x\n", msg.Data.Get(0).Bytes()) if p.diverted == true { // If were already looking for a common parent and we get here again we need to go deeper p.blocksRequested = p.blocksRequested * 2 @@ -727,7 +727,7 @@ func (p *Peer) FindCommonParentBlock() { msgInfo := append(hashes, uint64(len(hashes))) - ethutil.Config.Log.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) p.QueueMessage(msg) @@ -739,7 +739,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) p.QueueMessage(msg) From 7fb5e993e3a1cc2251bba7af1c85ed1d024b4b50 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:11:40 +0200 Subject: [PATCH 0476/1237] Moved 0 check to state object for now --- ethchain/state_object.go | 7 +++++++ ethchain/vm.go | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b372..17391963f7 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -90,6 +90,13 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) + + // FIXME This should be handled in the Trie it self + if val.BigInt().Cmp(ethutil.Big0) == 0 { + c.state.trie.Delete(string(addr)) + return + } + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } diff --git a/ethchain/vm.go b/ethchain/vm.go index b9e8353fbe..bacd05ba55 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -325,21 +325,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - y, x := stack.Popn() - vm.Printf(" %v < %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) // x < y - if x.Cmp(y) < 0 { + if y.Cmp(x) < 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) } case GT: require(2) - y, x := stack.Popn() - vm.Printf(" %v > %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) // x > y - if x.Cmp(y) > 0 { + if y.Cmp(x) > 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -520,7 +520,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MLOAD: require(1) offset := stack.Pop() - stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + vm.Printf(" => 0x%x", val.Bytes()) case MSTORE: // Store the value at stack top-1 in to memory at location stack top require(2) // Pop value of the stack @@ -541,15 +544,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.GetMem(loc) stack.Push(val.BigInt()) - vm.Printf(" {} 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) case SSTORE: require(2) val, loc := stack.Popn() - // FIXME This should be handled in the Trie it self - if val.Cmp(big.NewInt(0)) != 0 { - closure.SetStorage(loc, ethutil.NewValue(val)) - } + //if val.Cmp(big.NewInt(0)) != 0 { + closure.SetStorage(loc, ethutil.NewValue(val)) + //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) From 931ae0f116ca65c3758524160bf21e28f06db50e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Jun 2014 20:12:08 +0200 Subject: [PATCH 0477/1237] Append zero's in R & S --- ethchain/transaction.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 34ab357a17..29b167355b 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -150,8 +150,11 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() + + r := make([]byte, 32-len(decoder.Get(7).Bytes())) + s := make([]byte, 32-len(decoder.Get(8).Bytes())) + tx.r = append(r, decoder.Get(7).Bytes()...) + tx.s = append(s, decoder.Get(8).Bytes()...) if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -175,7 +178,8 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - tx.Sender(), + //tx.Sender(), + nil, tx.Recipient, tx.Nonce, tx.GasPrice, From 299b50a0d4e1ec0d7c6e5820c4f68da4e424f382 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Jun 2014 02:40:25 +0200 Subject: [PATCH 0478/1237] Support serpent lang --- ethutil/script.go | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/ethutil/script.go b/ethutil/script.go index 94e4014069..c8b1da51cf 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -3,23 +3,35 @@ package ethutil import ( "fmt" "github.com/obscuren/mutan" + "github.com/obscuren/serpent-go" "strings" ) // General compile function -func Compile(script string) ([]byte, error) { - byteCode, errors := mutan.Compile(strings.NewReader(script), false) - if len(errors) > 0 { - var errs string - for _, er := range errors { - if er != nil { - errs += er.Error() - } - } - return nil, fmt.Errorf("%v", errs) - } +func Compile(script string) (ret []byte, err error) { + c := strings.Split(script, "\n")[0] - return byteCode, nil + if c == "#!serpent" { + byteCode, err := serpent.Compile(script) + if err != nil { + return nil, err + } + + return byteCode, nil + } else { + byteCode, errors := mutan.Compile(strings.NewReader(script), false) + if len(errors) > 0 { + var errs string + for _, er := range errors { + if er != nil { + errs += er.Error() + } + } + return nil, fmt.Errorf("%v", errs) + } + + return byteCode, nil + } } func CompileScript(script string) ([]byte, []byte, error) { From bb1641e4ecd92884f219d77acd5348ceb0782490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:18 +0200 Subject: [PATCH 0479/1237] Clean up & refactored methods --- ethchain/state_manager.go | 57 ++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c1..7444d51808 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -143,27 +143,23 @@ done: return receipts, handled, unhandled, err } -func (sm *StateManager) Process(block *Block, dontReact bool) error { +func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { + // Processing a blocks may never happen simultaneously + sm.mutex.Lock() + defer sm.mutex.Unlock() + + if sm.bc.HasBlock(block.Hash()) { + return nil + } + if !sm.bc.HasBlock(block.PrevHash) { return ParentError(block.PrevHash) } - parent := sm.bc.GetBlock(block.PrevHash) - - return sm.ProcessBlock(parent.State(), parent, block, dontReact) - -} - -// Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { - // Processing a blocks may never happen simultaneously - sm.mutex.Lock() - defer sm.mutex.Unlock() - hash := block.Hash() - - if sm.bc.HasBlock(hash) { - return nil - } + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State() + ) // Defer the Undo on the Trie. If the block processing happened // we don't want to undo but since undo only happens on dirty @@ -171,17 +167,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea // before that. defer state.Reset() - // Check if we have the parent hash, if it isn't known we discard it - // Reasons might be catching up or simply an invalid block - if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { - return ParentError(block.PrevHash) - } - - coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) - - // Process the transactions on to current block - receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { if len(receipts) == len(block.Receipts()) { @@ -194,6 +180,10 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } }() + if err != nil { + return err + } + // Block validation if err = sm.ValidateBlock(block); err != nil { fmt.Println("[SM] Error validating block:", err) @@ -237,6 +227,17 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return nil } + +func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.SetGasPool(block.CalcGasLimit(parent)) + + // Process the transactions on to current block + receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + + return receipts, nil +} + func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { From 842d52db7b98fb309ed99ccc4b65ca3973fb81ec Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:23:51 +0200 Subject: [PATCH 0480/1237] Make sure that public key always uses 64 bytes --- ethchain/transaction.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 29b167355b..2ab6810304 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -89,11 +89,12 @@ func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - // If we don't make a copy we will overwrite the existing underlying array - dst := make([]byte, len(tx.r)) - copy(dst, tx.r) + r := make([]byte, 32-len(tx.r)) + s := make([]byte, 32-len(tx.s)) + r = append(r, ethutil.CopyBytes(tx.r)...) + s = append(s, ethutil.CopyBytes(tx.s)...) - sig := append(dst, tx.s...) + sig := append(r, s...) sig = append(sig, tx.v-27) pubkey, _ := secp256k1.RecoverPubkey(hash, sig) @@ -127,6 +128,8 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + // TODO Remove prefixing zero's + return append(data, tx.v, tx.r, tx.s) } @@ -151,10 +154,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) - r := make([]byte, 32-len(decoder.Get(7).Bytes())) - s := make([]byte, 32-len(decoder.Get(8).Bytes())) - tx.r = append(r, decoder.Get(7).Bytes()...) - tx.s = append(s, decoder.Get(8).Bytes()...) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() if IsContractAddr(tx.Recipient) { tx.contractCreation = true @@ -178,8 +179,7 @@ func (tx *Transaction) String() string { `, tx.Hash(), len(tx.Recipient) == 0, - //tx.Sender(), - nil, + tx.Sender(), tx.Recipient, tx.Nonce, tx.GasPrice, From 8c96c5662f9a362c50f3e6e04e886e2518cc68b9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:24:07 +0200 Subject: [PATCH 0481/1237] Added hex script method --- ethpub/types.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethpub/types.go b/ethpub/types.go index 31b92f6ed6..3525981483 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -244,6 +244,14 @@ func (c *PStateObject) Script() string { return "" } +func (c *PStateObject) HexScript() string { + if c.object != nil { + return ethutil.Hex(c.object.Script()) + } + + return "" +} + type PStorageState struct { StateAddress string Address string From 9350ecd36fe3a30bea4cfd60db9a53787d4d5852 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:24:45 +0200 Subject: [PATCH 0482/1237] Do not keep on asking for the same chain --- peer.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/peer.go b/peer.go index b4bde2c1d6..ca41689408 100644 --- a/peer.go +++ b/peer.go @@ -138,6 +138,8 @@ type Peer struct { // We use this to give some kind of pingtime to a node, not very accurate, could be improved. pingTime time.Duration pingStartTime time.Time + + lastRequestedBlock *ethchain.Block } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { @@ -351,6 +353,12 @@ func (p *Peer) HandleInbound() { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) + if p.lastRequestedBlock != nil && bytes.Compare(lastBlock.Hash(), p.lastRequestedBlock.Hash()) == 0 { + p.catchingUp = false + continue + } + p.lastRequestedBlock = lastBlock + ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) From a4e26bf7c2c0cfc65be14ef98af695a0d663609f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:25:14 +0200 Subject: [PATCH 0483/1237] Added Block do which replays the given block or error --- ethereum.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ethereum.go b/ethereum.go index a6cb78b1fc..77a7c92c77 100644 --- a/ethereum.go +++ b/ethereum.go @@ -113,6 +113,24 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { return ethereum, nil } +// Replay block +func (self *Ethereum) BlockDo(hash []byte) error { + block := self.blockChain.GetBlock(hash) + if block == nil { + return fmt.Errorf("unknown block %x", hash) + } + + parent := self.blockChain.GetBlock(block.PrevHash) + + _, err := self.stateManager.ApplyDiff(parent.State(), parent, block) + if err != nil { + return err + } + + return nil + +} + func (s *Ethereum) Reactor() *ethutil.ReactorEngine { return s.reactor } From 803e4807ede157db36030c6415a4f515f723ccf0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:31 +0200 Subject: [PATCH 0484/1237] Removed comments --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 17391963f7..0a2e28ded5 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -94,10 +94,10 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { // FIXME This should be handled in the Trie it self if val.BigInt().Cmp(ethutil.Big0) == 0 { c.state.trie.Delete(string(addr)) + return } - //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } From d890258af6de8c5ef9701826fb4ee7c353788ad5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 11:26:51 +0200 Subject: [PATCH 0485/1237] Minor fixes to vm output --- ethchain/vm.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index bacd05ba55..a2e1c60fd5 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -358,10 +358,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case NOT: require(1) x := stack.Pop() - if x.Cmp(ethutil.BigFalse) == 0 { - stack.Push(ethutil.BigTrue) - } else { + if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) } // 0x10 range @@ -542,16 +542,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + stack.Push(val.BigInt()) - vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val.Bytes()) case SSTORE: require(2) val, loc := stack.Popn() - - //if val.Cmp(big.NewInt(0)) != 0 { closure.SetStorage(loc, ethutil.NewValue(val)) - //} // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -690,7 +688,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Printf(" (g) %v", closure.Gas).Endl() + vm.Endl() return closure.Return(nil), nil default: From 614624754d2dcaf9344a3efbfa880c9b0ddba6be Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 13:42:30 +0200 Subject: [PATCH 0486/1237] Let the state create the object --- ethchain/vm.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethchain/vm.go b/ethchain/vm.go index a2e1c60fd5..432bc4e6d2 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -594,7 +594,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) // Create a new contract - contract := NewContract(addr, value, []byte("")) + contract := vm.state.NewStateObject(addr) + contract.Amount = value + // Set the init script contract.initScript = mem.Get(offset.Int64(), size.Int64()) // Transfer all remaining gas to the new From 8e9cc3697944c3e568186a5c23ac729f6eb4a1f4 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Jun 2014 12:49:04 +0100 Subject: [PATCH 0487/1237] refactor logging. Details: - packages use tagged logger sending log messages to shared (process-wide) logging engine - log writers (interface ethlog.LogSystem) can be added to the logging engine by wrappers/guis/clients - shared logging engine dispatching to multiple log systems - log level can be set separately per log system - async logging thread: logging IO does not block main thread - log messages are synchronously stringified to avoid incorrectly logging of changed states - README.md - loggers_test --- ethlog/README.md | 58 +++++++++++++ ethlog/loggers.go | 179 +++++++++++++++++++++++++++++++++++++++++ ethlog/loggers_test.go | 115 ++++++++++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 ethlog/README.md create mode 100644 ethlog/loggers.go create mode 100644 ethlog/loggers_test.go diff --git a/ethlog/README.md b/ethlog/README.md new file mode 100644 index 0000000000..f8818d98e7 --- /dev/null +++ b/ethlog/README.md @@ -0,0 +1,58 @@ +## Features + +- packages use tagged logger sending log messages to shared (process-wide) logging engine +- log writers (interface ethlog.LogSystem) can be added to the logging engine by wrappers/guis/clients +- shared logging engine dispatching to multiple log systems +- log level can be set separately per log system +- async logging thread: logging IO does not block main thread +- log messages are synchronously stringified to avoid incorrectly logging of changed states + +## Usage + +In an ethereum component package: + + import "github.com/ethereum/eth-go/ethlog" + + // package-wide logger using tag + var logger = ethlog.NewLogger("TAG") + + logger.Infoln("this is info") # > [TAG] This is info + +Ethereum wrappers should register log systems conforming to ethlog.LogSystem + + import "github.com/ethereum/eth-go/ethlog" + + type CustomLogWriter struct { + logLevel ethlog.LogLevel + } + + func (t *TestLogSystem) SetLogLevel(i LogLevel) { + t.level = i + } + + func (t *TestLogSystem) GetLogLevel() LogLevel { + return t.level + } + + func (c *CustomLogWriter) Printf(format string, v...interface{}) { + //.... + } + + func (c *CustomLogWriter) Println(v...interface{}) { + //.... + } + + ethlog.AddLogWriter(&CustomLogWriter{}) + +ethlog also provides constructors for that wrap io.Writers into a standard logger with a settable level: + + filename := "test.log" + file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) + fileLogSystem := NewStdLogSystem(file, 0, WarnLevel) + AddLogSystem(fileLogSystem) + stdOutLogSystem := NewStdLogSystem(os.Stdout, 0, WarnLevel) + AddLogSystem(stdOutLogSystem) + + + + diff --git a/ethlog/loggers.go b/ethlog/loggers.go new file mode 100644 index 0000000000..e656ffbe59 --- /dev/null +++ b/ethlog/loggers.go @@ -0,0 +1,179 @@ +package ethlog + +import ( + "fmt" + "sync" + "log" + "io" + "os" +) + +type LogSystem interface { + GetLogLevel() LogLevel + SetLogLevel(i LogLevel) + Println(v ...interface{}) + Printf(format string, v ...interface{}) +} + +type logMessage struct { + LogLevel LogLevel + format bool + msg string +} + +func newPrintlnLogMessage(level LogLevel, tag string, v...interface{}) *logMessage { + return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))} +} + +func newPrintfLogMessage(level LogLevel, tag string, format string, v...interface{}) *logMessage { + return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))} +} + +func (msg *logMessage) send(logger LogSystem) { + if msg.format { + logger.Printf(msg.msg) + } else { + logger.Println(msg.msg) + } +} + +var logMessages chan(*logMessage) +var logSystems []LogSystem +var drained = true + +type LogLevel uint8 + +const ( + Silence LogLevel = iota + ErrorLevel + WarnLevel + InfoLevel + DebugLevel +) + +// log messages are dispatched to log writers +func start() { + for { + select { + case msg := <- logMessages: + for _, logSystem := range logSystems { + if logSystem.GetLogLevel() >= msg.LogLevel { + msg.send(logSystem) + } + } + default: + drained = true + } + } +} + +// waits until log messages are drained (dispatched to log writers) +func Flush() { + for !drained {} +} + +type Logger struct { + tag string +} + +func NewLogger(tag string) *Logger { + return &Logger{tag} +} + +func AddLogSystem(logSystem LogSystem) { + var mutex = &sync.Mutex{} + mutex.Lock() + defer mutex.Unlock() + if logSystems == nil { + logMessages = make(chan *logMessage) + go start() + } + logSystems = append(logSystems, logSystem) +} + +func (logger *Logger) sendln(level LogLevel, v...interface{}) { + if logMessages != nil { + msg := newPrintlnLogMessage(level, logger.tag, v...) + drained = false + logMessages <- msg + } +} + +func (logger *Logger) sendf(level LogLevel, format string, v...interface{}) { + if logMessages != nil { + msg := newPrintfLogMessage(level, logger.tag, format, v...) + drained = false + logMessages <- msg + } +} + +func (logger *Logger) Errorln(v...interface{}) { + logger.sendln(ErrorLevel, v...) +} + +func (logger *Logger) Warnln(v...interface{}) { + logger.sendln(WarnLevel, v...) +} + +func (logger *Logger) Infoln(v...interface{}) { + logger.sendln(InfoLevel, v...) +} + +func (logger *Logger) Debugln(v...interface{}) { + logger.sendln(DebugLevel, v...) +} + +func (logger *Logger) Errorf(format string, v...interface{}) { + logger.sendf(ErrorLevel, format, v...) +} + +func (logger *Logger) Warnf(format string, v...interface{}) { + logger.sendf(WarnLevel, format, v...) +} + +func (logger *Logger) Infof(format string, v...interface{}) { + logger.sendf(InfoLevel, format, v...) +} + +func (logger *Logger) Debugf(format string, v...interface{}) { + logger.sendf(DebugLevel, format, v...) +} + +func (logger *Logger) Fatalln (v...interface{}) { + logger.sendln(ErrorLevel, v...) + Flush() + os.Exit(0) +} + +func (logger *Logger) Fatalf (format string, v...interface{}) { + logger.sendf(ErrorLevel, format, v...) + Flush() + os.Exit(0) +} + +type StdLogSystem struct { + logger *log.Logger + level LogLevel +} + +func (t *StdLogSystem) Println(v ...interface{}) { + t.logger.Println(v...) +} + +func (t *StdLogSystem) Printf(format string, v ...interface{}) { + t.logger.Printf(format, v...) +} + +func (t *StdLogSystem) SetLogLevel(i LogLevel) { + t.level = i +} + +func (t *StdLogSystem) GetLogLevel() LogLevel { + return t.level +} + +func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem { + logger := log.New(writer, "", flags) + return &StdLogSystem{logger, level} +} + diff --git a/ethlog/loggers_test.go b/ethlog/loggers_test.go new file mode 100644 index 0000000000..c330820120 --- /dev/null +++ b/ethlog/loggers_test.go @@ -0,0 +1,115 @@ +package ethlog + +import ( + "testing" + "fmt" + "io/ioutil" + "os" +) + +type TestLogSystem struct { + Output string + level LogLevel +} + +func (t *TestLogSystem) Println(v ...interface{}) { + t.Output += fmt.Sprintln(v...) +} + +func (t *TestLogSystem) Printf(format string, v ...interface{}) { + t.Output += fmt.Sprintf(format, v...) +} + +func (t *TestLogSystem) SetLogLevel(i LogLevel) { + t.level = i +} + +func (t *TestLogSystem) GetLogLevel() LogLevel { + return t.level +} + +func quote(s string) string { + return fmt.Sprintf("'%s'", s) +} + +func TestLoggerPrintln(t *testing.T) { + logger := NewLogger("TEST") + testLogSystem := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem) + logger.Errorln("error") + logger.Warnln("warn") + logger.Infoln("info") + logger.Debugln("debug") + Flush() + output := testLogSystem.Output + fmt.Println(quote(output)) + if output != "[TEST] error\n[TEST] warn\n" { + t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem.Output)) + } +} + +func TestLoggerPrintf(t *testing.T) { + logger := NewLogger("TEST") + testLogSystem := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem) + logger.Errorf("error to %v\n", *testLogSystem) + logger.Warnf("warn") + logger.Infof("info") + logger.Debugf("debug") + Flush() + output := testLogSystem.Output + fmt.Println(quote(output)) + if output != "[TEST] error to { 2}\n[TEST] warn" { + t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", quote(testLogSystem.Output)) + } +} + +func TestMultipleLogSystems(t *testing.T) { + logger := NewLogger("TEST") + testLogSystem0 := &TestLogSystem{level: ErrorLevel} + testLogSystem1 := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem0) + AddLogSystem(testLogSystem1) + logger.Errorln("error") + logger.Warnln("warn") + Flush() + output0 := testLogSystem0.Output + output1 := testLogSystem1.Output + if output0 != "[TEST] error\n" { + t.Error("Expected logger 0 output '[TEST] error\\n', got ", quote(testLogSystem0.Output)) + } + if output1 != "[TEST] error\n[TEST] warn\n" { + t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem1.Output)) + } +} + +func TestFileLogSystem(t *testing.T) { + logger := NewLogger("TEST") + filename := "test.log" + file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) + testLogSystem := NewStdLogSystem(file, 0, WarnLevel) + AddLogSystem(testLogSystem) + logger.Errorf("error to %s\n", filename) + logger.Warnln("warn") + Flush() + contents, _ := ioutil.ReadFile(filename) + output := string(contents) + fmt.Println(quote(output)) + if output != "[TEST] error to test.log\n[TEST] warn\n" { + t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", quote(output)) + } else { + os.Remove(filename) + } +} + +func TestNoLogSystem(t *testing.T) { + logger := NewLogger("TEST") + logger.Warnln("warn") + Flush() +} + + + + + + From b9e8a3e02493d5bbf23cfcab259e66f6ae166612 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Jun 2014 12:54:10 +0100 Subject: [PATCH 0488/1237] modified logging API - package vars for tagged loggers - weed out spurious fmt.PrintX and log.PrintX logging - tried to second guess loglevel for some :) --- ethchain/block_chain.go | 30 +++++++++--------- ethchain/dagger.go | 10 +++--- ethchain/state.go | 2 +- ethchain/state_manager.go | 20 ++++++------ ethchain/state_object.go | 6 ++-- ethchain/state_transition.go | 7 ++--- ethchain/transaction_pool.go | 20 ++++++------ ethchain/vm.go | 15 +++++---- ethereum.go | 36 +++++++++++----------- ethminer/miner.go | 21 +++++++------ ethpub/pub.go | 5 ++- ethrpc/server.go | 12 +++++--- peer.go | 59 +++++++++++++++++++----------------- 13 files changed, 132 insertions(+), 111 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 19b5248d77..f964e0e3af 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -4,11 +4,13 @@ import ( "bytes" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) +var chainlogger = ethlog.NewLogger("CHAIN") + type BlockChain struct { Ethereum EthManager // The famous, the fabulous Mister GENESIIIIIIS (block) @@ -129,38 +131,38 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte // Start with the newest block we got, all the way back to the common block we both know for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("[CHAIN] We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty) + chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty) curChainDifficulty := new(big.Int) block := bc.CurrentBlock for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("We have found the common parent block, breaking") break } anOtherBlock := bc.GetBlock(block.PrevHash) if anOtherBlock == nil { // We do not want to count the genesis block for difficulty since that's not being sent - log.Println("[CHAIN] At genesis block, breaking") + chainlogger.Infoln("At genesis block, breaking") break } curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) + chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) + chainlogger.Infof("The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) bc.ResetTillBlockHash(commonBlockHash) return false } else { - log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + chainlogger.Infoln("Our chain showed the incoming chain who is boss. Ignoring.") return true } } @@ -195,7 +197,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { var block *Block for ; block != nil; block = bc.GetBlock(block.PrevHash) { if bytes.Compare(block.Hash(), hash) == 0 { - log.Println("[CHAIN] We have arrived at the the common parent block, breaking") + chainlogger.Infoln("We have arrived at the the common parent block, breaking") break } err = ethutil.Config.Db.Delete(block.Hash()) @@ -203,7 +205,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { return err } } - log.Println("[CHAIN] Split chain deleted and reverted to common parent block.") + chainlogger.Infoln("Split chain deleted and reverted to common parent block.") return nil } @@ -286,7 +288,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -294,14 +296,14 @@ func (bc *BlockChain) setLastBlock() { // Prepare the genesis block bc.Add(bc.genesisBlock) - //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //chainlogger.Infof("root %x\n", bm.bc.genesisBlock.State().Root) //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { @@ -358,6 +360,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) { func (bc *BlockChain) Stop() { if bc.CurrentBlock != nil { - log.Println("[CHAIN] Stopped") + chainlogger.Infoln("Stopped") } } diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 565e1e4473..43725e3362 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -2,14 +2,16 @@ package ethchain import ( "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "github.com/obscuren/sha3" "hash" - "log" "math/big" "math/rand" "time" ) +var powlogger = ethlog.NewLogger("POW") + type PoW interface { Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool @@ -29,14 +31,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") + //powlogger.Infoln("Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") + powlogger.Infoln("Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) @@ -81,7 +83,7 @@ func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { rnd := r.Int63() res := dag.Eval(big.NewInt(rnd)) - log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) if res.Cmp(obj) < 0 { // Post back result on the channel resChan <- rnd diff --git a/ethchain/state.go b/ethchain/state.go index a08dfac83e..e28b919099 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -125,7 +125,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(+) %x\n", addr) + statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c1..20e0a13a2e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,14 +3,16 @@ package ethchain import ( "bytes" "container/list" - "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/ethlog" "math/big" "sync" "time" ) +var statelogger = ethlog.NewLogger("STATE") + type BlockProcessor interface { ProcessBlock(block *Block) } @@ -120,7 +122,7 @@ done: break done default: - ethutil.Config.Log.Infoln(err) + statelogger.Infoln(err) } } @@ -186,29 +188,29 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if err != nil { if len(receipts) == len(block.Receipts()) { for i, receipt := range block.Receipts() { - ethutil.Config.Log.Debugf("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()) + statelogger.Debugf("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 { - ethutil.Config.Log.Debugln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) + statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) } } }() // Block validation if err = sm.ValidateBlock(block); err != nil { - fmt.Println("[SM] Error validating block:", err) + statelogger.Errorln("Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. if err = sm.AccumelateRewards(state, block); err != nil { - fmt.Println("[SM] Error accumulating reward", err) + statelogger.Errorln("Error accumulating reward", err) return err } if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + statelogger.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } @@ -221,7 +223,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) + statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) @@ -232,7 +234,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.Ethereum.TxPool().RemoveInvalid(state) } else { - fmt.Println("total diff failed") + statelogger.Errorln("total diff failed") } return nil diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b372..f53f47d7ea 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -124,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%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)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -151,7 +151,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.Infof("%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1f5b4f9592..f84c3486bb 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,7 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -135,12 +134,12 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) + statelogger.Infof("(~) %x\n", self.tx.Hash()) /* defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + logger.Infoln(r) err = fmt.Errorf("state transition err %v", r) } }() @@ -231,7 +230,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(self.value) - //ethutil.Config.Log.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) + //statelogger.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) //} return nil diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 24836222a9..44218ae287 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -3,15 +3,15 @@ package ethchain import ( "bytes" "container/list" - "errors" "fmt" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" + "github.com/ethereum/eth-go/ethlog" "math/big" "sync" ) +var txplogger = ethlog.NewLogger("TXP") + const ( txPoolQueueSize = 50 ) @@ -97,7 +97,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + txplogger.Infoln(r) err = fmt.Errorf("%v", r) } }() @@ -156,7 +156,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root after receiver update %x\n", state.Root()) } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + txplogger.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) return } @@ -168,7 +168,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { - return errors.New("[TXPL] No last block on the block chain") + return fmt.Errorf("[TXPL] No last block on the block chain") } if len(tx.Recipient) != 20 { @@ -188,7 +188,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { if tx.IsContract() { if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { - return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + return fmt.Errorf("[TXPL] Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) } } @@ -215,12 +215,12 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - ethutil.Config.Log.Debugln("Validating Tx failed", err) + txplogger.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) @@ -282,5 +282,5 @@ func (pool *TxPool) Stop() { pool.Flush() - log.Println("[TXP] Stopped") + txplogger.Infoln("Stopped") } diff --git a/ethchain/vm.go b/ethchain/vm.go index b9e8353fbe..75bcfd782d 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -3,10 +3,13 @@ package ethchain import ( "fmt" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) +var vmlogger = ethlog.NewLogger("VM") + var ( GasStep = big.NewInt(1) GasSha = big.NewInt(20) @@ -72,7 +75,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { func (self *Vm) Endl() *Vm { if self.Verbose { - ethutil.Config.Log.Infoln(self.logStr) + vmlogger.Infoln(self.logStr) self.logStr = "" } @@ -93,11 +96,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - fmt.Println("vm err", err) + vmlogger.Errorln("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) // Memory for the current closure mem := &Memory{} @@ -638,7 +641,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) if closure.object.Amount.Cmp(value) < 0 { - ethutil.Config.Log.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) stack.Push(ethutil.BigFalse) } else { @@ -657,7 +660,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) - ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + vmlogger.Debugf("Closure execution failed. %v\n", err) vm.err = err vm.state.Set(snapshot) @@ -692,7 +695,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), nil default: - ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) + vmlogger.Debugf("Invalid opcode %x\n", op) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } diff --git a/ethereum.go b/ethereum.go index a6cb78b1fc..1de6717125 100644 --- a/ethereum.go +++ b/ethereum.go @@ -8,8 +8,8 @@ import ( "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/ethlog" "io/ioutil" - "log" "math/rand" "net" "net/http" @@ -20,6 +20,8 @@ import ( "time" ) +var ethlogger = ethlog.NewLogger("SERV") + func eachPeer(peers *list.List, callback func(*Peer, *list.Element)) { // Loop thru the peers and close them (if we had them) for e := peers.Front(); e != nil; e = e.Next() { @@ -85,7 +87,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { if usePnp { nat, err = Discover() if err != nil { - ethutil.Config.Log.Debugln("UPnP failed", err) + ethlogger.Debugln("UPnP failed", err) } } @@ -163,7 +165,7 @@ func (s *Ethereum) AddPeer(conn net.Conn) { if s.peers.Len() < s.MaxPeers { peer.Start() } else { - ethutil.Config.Log.Debugf("[SERV] Max connected peers reached. Not adding incoming peer.") + ethlogger.Debugf("Max connected peers reached. Not adding incoming peer.") } } } @@ -223,7 +225,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error { if phost == chost { alreadyConnected = true - //ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost) + //ethlogger.Debugf("Peer %s already added.\n", chost) return } }) @@ -340,12 +342,12 @@ func (s *Ethereum) Start(seed bool) { // Bind to addr and port ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { - log.Println("Connection listening disabled. Acting as client") + ethlogger.Warnln("Connection listening disabled. Acting as client") s.listening = false } else { s.listening = true // Starting accepting connections - ethutil.Config.Log.Infoln("Ready and accepting connections") + ethlogger.Infoln("Ready and accepting connections") // Start the peer handler go s.peerHandler(ln) } @@ -363,7 +365,7 @@ func (s *Ethereum) Start(seed bool) { } func (s *Ethereum) Seed() { - ethutil.Config.Log.Debugln("[SERV] Retrieving seed nodes") + ethlogger.Debugln("Retrieving seed nodes") // Eth-Go Bootstrapping ips, er := net.LookupIP("seed.bysh.me") @@ -371,7 +373,7 @@ func (s *Ethereum) Seed() { peers := []string{} for _, ip := range ips { node := fmt.Sprintf("%s:%d", ip.String(), 30303) - ethutil.Config.Log.Debugln("[SERV] Found DNS Go Peer:", node) + ethlogger.Debugln("Found DNS Go Peer:", node) peers = append(peers, node) } s.ProcessPeerList(peers) @@ -391,11 +393,11 @@ func (s *Ethereum) Seed() { for _, a := range addr { // Build string out of SRV port and Resolved IP peer := net.JoinHostPort(a, port) - ethutil.Config.Log.Debugln("[SERV] Found DNS Bootstrap Peer:", peer) + ethlogger.Debugln("Found DNS Bootstrap Peer:", peer) peers = append(peers, peer) } } else { - ethutil.Config.Log.Debugln("[SERV} Couldn't resolve :", target) + ethlogger.Debugln("Couldn't resolve :", target) } } // Connect to Peer list @@ -404,13 +406,13 @@ func (s *Ethereum) Seed() { // Fallback to servers.poc3.txt resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") if err != nil { - log.Println("Fetching seed failed:", err) + ethlogger.Warnln("Fetching seed failed:", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - log.Println("Reading seed failed:", err) + ethlogger.Warnln("Reading seed failed:", err) return } @@ -422,7 +424,7 @@ func (s *Ethereum) peerHandler(listener net.Listener) { for { conn, err := listener.Accept() if err != nil { - ethutil.Config.Log.Debugln(err) + ethlogger.Debugln(err) continue } @@ -468,13 +470,13 @@ out: var err error _, err = s.nat.AddPortMapping("TCP", int(lport), int(lport), "eth listen port", 20*60) if err != nil { - ethutil.Config.Log.Debugln("can't add UPnP port mapping:", err) + ethlogger.Debugln("can't add UPnP port mapping:", err) break out } if first && err == nil { _, err = s.nat.GetExternalAddress() if err != nil { - ethutil.Config.Log.Debugln("UPnP can't get external address:", err) + ethlogger.Debugln("UPnP can't get external address:", err) continue out } first = false @@ -488,8 +490,8 @@ out: timer.Stop() if err := s.nat.DeletePortMapping("TCP", int(lport), int(lport)); err != nil { - ethutil.Config.Log.Debugln("unable to remove UPnP port mapping:", err) + ethlogger.Debugln("unable to remove UPnP port mapping:", err) } else { - ethutil.Config.Log.Debugln("succesfully disestablished UPnP port mapping") + ethlogger.Debugln("succesfully disestablished UPnP port mapping") } } diff --git a/ethminer/miner.go b/ethminer/miner.go index 4343b43336..5f5c40134e 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -5,9 +5,12 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/ethlog" "sort" ) +var logger = ethlog.NewLogger("MINER") + type Miner struct { pow ethchain.PoW ethereum ethchain.EthManager @@ -67,10 +70,10 @@ out: break out case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - //ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") + //logger.Infoln("Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - //ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") + //logger.Infoln("New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -92,7 +95,7 @@ out: } else { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { - ethutil.Config.Log.Infoln("[MINER] Adding uncle block") + logger.Infoln("Adding uncle block") miner.uncles = append(miner.uncles, block) } } @@ -137,14 +140,14 @@ func (self *Miner) mineNewBlock() { // Sort the transactions by nonce in case of odd network propagation sort.Sort(ethchain.TxByNonce{self.txs}) - // Accumulate all valid transaction and apply them to the new state + // Accumulate all valid transactions and apply them to the new state // Error may be ignored. It's not important during mining parent := self.ethereum.BlockChain().GetBlock(self.block.PrevHash) coinbase := self.block.State().GetOrNewStateObject(self.block.Coinbase) coinbase.SetGasPool(self.block.CalcGasLimit(parent)) receipts, txs, unhandledTxs, err := stateManager.ProcessTransactions(coinbase, self.block.State(), self.block, self.block, self.txs) if err != nil { - ethutil.Config.Log.Debugln("[MINER]", err) + logger.Debugln(err) } self.txs = append(txs, unhandledTxs...) @@ -156,18 +159,18 @@ func (self *Miner) mineNewBlock() { self.block.State().Update() - ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") + logger.Infoln("Mining on block. Includes", len(self.txs), "transactions") // Find a valid nonce self.block.Nonce = self.pow.Search(self.block, self.powQuitChan) if self.block.Nonce != nil { err := self.ethereum.StateManager().Process(self.block, false) if err != nil { - ethutil.Config.Log.Infoln(err) + logger.Infoln(err) } else { self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val}) - ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", self.block.Hash()) - ethutil.Config.Log.Infoln(self.block) + logger.Infof("🔨 Mined block %x\n", self.block.Hash()) + logger.Infoln(self.block) // Gather the new batch of transactions currently in the tx pool self.txs = self.ethereum.TxPool().CurrentTransactions() } diff --git a/ethpub/pub.go b/ethpub/pub.go index b475453af0..a49ee2f125 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -4,11 +4,14 @@ import ( "encoding/hex" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "math/big" "strings" "sync/atomic" ) +var logger = ethlog.NewLogger("PUB") + type PEthereum struct { manager ethchain.EthManager stateManager *ethchain.StateManager @@ -191,7 +194,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc lib.txPool.QueueTransaction(tx) if contractCreation { - ethutil.Config.Log.Infof("Contract addr %x", tx.CreationAddress()) + logger.Infof("Contract addr %x", tx.CreationAddress()) } return NewPReciept(contractCreation, tx.CreationAddress(), tx.Hash(), keyPair.Address()), nil diff --git a/ethrpc/server.go b/ethrpc/server.go index 3960e641c3..b55469b832 100644 --- a/ethrpc/server.go +++ b/ethrpc/server.go @@ -3,12 +3,14 @@ package ethrpc import ( "fmt" "github.com/ethereum/eth-go/ethpub" - "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "net" "net/rpc" "net/rpc/jsonrpc" ) +var logger = ethlog.NewLogger("JSON") + type JsonRpcServer struct { quit chan bool listener net.Listener @@ -25,7 +27,7 @@ out: } } - ethutil.Config.Log.Infoln("[JSON] Shutdown JSON-RPC server") + logger.Infoln("Shutdown JSON-RPC server") } func (s *JsonRpcServer) Stop() { @@ -33,7 +35,7 @@ func (s *JsonRpcServer) Stop() { } func (s *JsonRpcServer) Start() { - ethutil.Config.Log.Infoln("[JSON] Starting JSON-RPC server") + logger.Infoln("Starting JSON-RPC server") go s.exitHandler() rpc.Register(&EthereumApi{ethp: s.ethp}) rpc.HandleHTTP() @@ -41,10 +43,10 @@ func (s *JsonRpcServer) Start() { for { conn, err := s.listener.Accept() if err != nil { - ethutil.Config.Log.Infoln("[JSON] Error starting JSON-RPC:", err) + logger.Infoln("Error starting JSON-RPC:", err) break } - ethutil.Config.Log.Debugln("[JSON] Incoming request.") + logger.Debugln("Incoming request.") go jsonrpc.ServeConn(conn) } } diff --git a/peer.go b/peer.go index b4bde2c1d6..fd8a33d656 100644 --- a/peer.go +++ b/peer.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" + "github.com/ethereum/eth-go/ethlog" "net" "strconv" "strings" @@ -14,6 +15,8 @@ import ( "time" ) +var peerlogger = ethlog.NewLogger("PEER") + const ( // The size of the output buffer for writing messages outputBufferSize = 50 @@ -176,7 +179,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { conn, err := net.DialTimeout("tcp", addr, 10*time.Second) if err != nil { - ethutil.Config.Log.Debugln("Connection to peer failed", err) + peerlogger.Debugln("Connection to peer failed", err) p.Stop() return } @@ -245,11 +248,11 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { } } - ethutil.Config.Log.Println(ethutil.LogLevelSystem, "<=", msg.Type, msg.Data) + peerlogger.Infoln("<=", msg.Type, msg.Data) err := ethwire.WriteMessage(p.conn, msg) if err != nil { - ethutil.Config.Log.Debugln("[PEER] Can't send message:", err) + peerlogger.Debugln(" Can't send message:", err) // Stop the client if there was an error writing to it p.Stop() return @@ -274,7 +277,7 @@ out: case <-pingTimer.C: timeSince := time.Since(time.Unix(p.lastPong, 0)) if !p.pingStartTime.IsZero() && p.lastPong != 0 && timeSince > (pingPongTimer+30*time.Second) { - ethutil.Config.Log.Infof("[PEER] Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) + peerlogger.Infof("Peer did not respond to latest pong fast enough, it took %s, disconnecting.\n", timeSince) p.Stop() return } @@ -316,10 +319,10 @@ func (p *Peer) HandleInbound() { // Wait for a message from the peer msgs, err := ethwire.ReadMessages(p.conn) if err != nil { - ethutil.Config.Log.Debugln(err) + peerlogger.Debugln(err) } for _, msg := range msgs { - ethutil.Config.Log.Println(ethutil.LogLevelSystem, "=>", msg.Type, msg.Data) + peerlogger.Infoln("=>", msg.Type, msg.Data) switch msg.Type { case ethwire.MsgHandshakeTy: @@ -331,7 +334,7 @@ func (p *Peer) HandleInbound() { } case ethwire.MsgDiscTy: p.Stop() - ethutil.Config.Log.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) + peerlogger.Infoln("Disconnect peer:", DiscReason(msg.Data.Get(0).Uint())) case ethwire.MsgPingTy: // Respond back with pong p.QueueMessage(ethwire.NewMessage(ethwire.MsgPongTy, "")) @@ -351,7 +354,7 @@ func (p *Peer) HandleInbound() { // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // common ground to start syncing from lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) - ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) + peerlogger.Infof("Last block: %x. Checking if we have it locally.\n", lastBlock.Hash()) for i := msg.Data.Len() - 1; i >= 0; i-- { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) // Do we have this block on our chain? If so we can continue @@ -372,7 +375,7 @@ func (p *Peer) HandleInbound() { // we just keep increasing the amount of blocks. p.blocksRequested = p.blocksRequested * 2 - ethutil.Config.Log.Infof("[PEER] No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) + peerlogger.Infof("No common ancestor found, requesting %d more blocks.\n", p.blocksRequested) p.catchingUp = false p.FindCommonParentBlock() break @@ -388,9 +391,9 @@ func (p *Peer) HandleInbound() { if err != nil { if ethutil.Config.Debug { - ethutil.Config.Log.Infof("[PEER] Block %x failed\n", block.Hash()) - ethutil.Config.Log.Infof("[PEER] %v\n", err) - ethutil.Config.Log.Debugln(block) + peerlogger.Infof("Block %x failed\n", block.Hash()) + peerlogger.Infof("%v\n", err) + peerlogger.Debugln(block) } break } else { @@ -407,7 +410,7 @@ func (p *Peer) HandleInbound() { if err != nil { // If the parent is unknown try to catch up with this peer if ethchain.IsParentErr(err) { - ethutil.Config.Log.Infoln("Attempting to catch. Parent known") + peerlogger.Infoln("Attempting to catch. Parent known") p.catchingUp = false p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) } else if ethchain.IsValidationErr(err) { @@ -419,7 +422,7 @@ func (p *Peer) HandleInbound() { if p.catchingUp && msg.Data.Len() > 1 { if lastBlock != nil { blockInfo := lastBlock.BlockInfo() - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + peerlogger.Infof("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false @@ -486,17 +489,17 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "[PEER] Found canonical block, returning chain from: %x ", parent.Hash()) + peerlogger.Infof("Found canonical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { - //ethutil.Config.Log.Debugf("[PEER] Returning %d blocks: %x ", len(chain), parent.Hash()) + //peerlogger.Debugf("Returning %d blocks: %x ", len(chain), parent.Hash()) p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, chain)) } else { p.QueueMessage(ethwire.NewMessage(ethwire.MsgBlockTy, []interface{}{})) } } else { - //ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") + //peerlogger.Debugf("Could not find a similar block") // If no blocks are found we send back a reply with msg not in chain // and the last hash from get chain if l > 0 { @@ -506,7 +509,7 @@ func (p *Peer) HandleInbound() { } } case ethwire.MsgNotInChainTy: - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Not in chain: %x\n", msg.Data.Get(0).Bytes()) + peerlogger.Infof("Not in chain: %x\n", msg.Data.Get(0).Bytes()) if p.diverted == true { // If were already looking for a common parent and we get here again we need to go deeper p.blocksRequested = p.blocksRequested * 2 @@ -527,7 +530,7 @@ func (p *Peer) HandleInbound() { // Unofficial but fun nonetheless case ethwire.MsgTalkTy: - ethutil.Config.Log.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) + peerlogger.Infoln("%v says: %s\n", p.conn.RemoteAddr(), msg.Data.Str()) } } } @@ -546,7 +549,7 @@ func (p *Peer) Start() { err := p.pushHandshake() if err != nil { - ethutil.Config.Log.Debugln("Peer can't send outbound version ack", err) + peerlogger.Debugln("Peer can't send outbound version ack", err) p.Stop() @@ -620,7 +623,7 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.pubkey = c.Get(5).Bytes() if p.pubkey == nil { - //ethutil.Config.Log.Debugln("Pubkey required, not supplied in handshake.") + peerlogger.Warnln("Pubkey required, not supplied in handshake.") p.Stop() return } @@ -635,13 +638,13 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { }) if usedPub > 0 { - //ethutil.Config.Log.Debugf("Pubkey %x found more then once. Already connected to client.", p.pubkey) + peerlogger.Debugf("Pubkey %x found more then once. Already connected to client.", p.pubkey) p.Stop() return } if c.Get(0).Uint() != ProtocolVersion { - ethutil.Config.Log.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint()) + peerlogger.Debugf("Invalid peer version. Require protocol: %d. Received: %d\n", ProtocolVersion, c.Get(0).Uint()) p.Stop() return } @@ -675,16 +678,16 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.ethereum.PushPeer(p) p.ethereum.reactor.Post("peerList", p.ethereum.Peers()) - ethutil.Config.Log.Infof("[SERV] Added peer (%s) %d / %d\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) + ethlogger.Infof("Added peer (%s) %d / %d\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers) // Catch up with the connected peer if !p.ethereum.IsUpToDate() { - ethutil.Config.Log.Debugln("Already syncing up with a peer; sleeping") + peerlogger.Debugln("Already syncing up with a peer; sleeping") time.Sleep(10 * time.Second) } p.SyncWithPeerToLastKnown() - ethutil.Config.Log.Debugln("[PEER]", p) + peerlogger.Debugln(p) } func (p *Peer) String() string { @@ -727,7 +730,7 @@ func (p *Peer) FindCommonParentBlock() { msgInfo := append(hashes, uint64(len(hashes))) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) + peerlogger.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) p.QueueMessage(msg) @@ -739,7 +742,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) p.QueueMessage(msg) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) + peerlogger.Infof("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) p.QueueMessage(msg) From 63157c798d613f1ca638597515bb89768e2c1aad Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 23 Jun 2014 12:55:38 +0100 Subject: [PATCH 0489/1237] refactor config (transitional). Details: - ReadConfig initialiser sets up global ethutil.Config via config file passed from wrappers - does not write out adhoc default (not meant to) but creates empty config file if it does not exist so that globalconf does not complain if persists a flag - default datadir and default config file set together with other flag defaults in wrappers - default assetpath set together with other command line flags defaults in gui wrapper (not in ethutil.Config or ui/ui_lib) - add EnvPrefix, to handle environment variable options too via globalconf - this is still transitional: global Config should just be a wrapper around globalconfig config handler and should be moved to go-ethereum - actual eth stack config should not be global instead config handled properly with explicit dependency injectioninto eth stack component instances --- ethutil/config.go | 200 +++++----------------------------------------- 1 file changed, 20 insertions(+), 180 deletions(-) diff --git a/ethutil/config.go b/ethutil/config.go index a573e108bc..52537ffa6c 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -4,18 +4,14 @@ import ( "flag" "fmt" "github.com/rakyll/globalconf" - "log" - "os" - "os/user" - "path" "runtime" + "os" ) // Config struct type config struct { Db Database - Log *Logger ExecPath string Debug bool Ver string @@ -26,62 +22,31 @@ type config struct { conf *globalconf.GlobalConf } -const defaultConf = ` -id = "" -port = 30303 -upnp = true -maxpeer = 10 -rpc = false -rpcport = 8080 -` - var Config *config -func ApplicationFolder(base string) string { - usr, _ := user.Current() - p := path.Join(usr.HomeDir, base) - - if len(base) > 0 { - //Check if the logging directory already exists, create it if not - _, err := os.Stat(p) - if err != nil { - if os.IsNotExist(err) { - log.Printf("Debug logging directory %s doesn't exist, creating it\n", p) - os.Mkdir(p, 0777) - - } - } - - iniFilePath := path.Join(p, "conf.ini") - _, err = os.Stat(iniFilePath) - if err != nil && os.IsNotExist(err) { - file, err := os.Create(iniFilePath) - if err != nil { - fmt.Println(err) - } else { - assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets") - file.Write([]byte(defaultConf + "\nasset_path = " + assetPath)) - } - } - } - - return p -} - // Read config // -// Initialize the global Config variable with default settings -func ReadConfig(base string, logTypes LoggerType, g *globalconf.GlobalConf, id string) *config { +// Initialize Config from Config File +func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { if Config == nil { - path := ApplicationFolder(base) - - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.14"} - Config.conf = g - Config.Identifier = id - Config.Log = NewLogger(logTypes, LogLevelDebug) + // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags + _, err := os.Stat(ConfigFile) + if err != nil && os.IsNotExist(err) { + fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) + os.Create(ConfigFile) + } + g, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: ConfigFile, + EnvPrefix: EnvPrefix, + }) + if err != nil { + fmt.Println(err) + } else { + g.ParseAll() + } + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } - return Config } @@ -98,137 +63,12 @@ func (c *config) SetIdentifier(id string) { c.Set("id", id) } +// provides persistence for flags func (c *config) Set(key, value string) { f := &flag.Flag{Name: key, Value: &confValue{value}} c.conf.Set("", f) } -type LoggerType byte - -const ( - LogFile = 0x1 - LogStd = 0x2 -) - -type LogSystem interface { - Println(v ...interface{}) - Printf(format string, v ...interface{}) -} - -type Logger struct { - logSys []LogSystem - logLevel int -} - -func NewLogger(flag LoggerType, level int) *Logger { - var loggers []LogSystem - - flags := log.LstdFlags - - if flag&LogFile > 0 { - file, err := os.OpenFile(path.Join(Config.ExecPath, "debug.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) - if err != nil { - log.Panic("unable to create file logger", err) - } - - log := log.New(file, "", flags) - - loggers = append(loggers, log) - } - if flag&LogStd > 0 { - log := log.New(os.Stdout, "", flags) - loggers = append(loggers, log) - } - - return &Logger{logSys: loggers, logLevel: level} -} - -func (self *Logger) SetLevel(level int) { - self.logLevel = level -} - -func (log *Logger) AddLogSystem(logger LogSystem) { - log.logSys = append(log.logSys, logger) -} - -const ( - LogLevelSystem = iota - LogLevelDebug - LogLevelInfo -) - -func (log *Logger) Debugln(v ...interface{}) { - if log.logLevel != LogLevelDebug { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Debugf(format string, v ...interface{}) { - if log.logLevel != LogLevelDebug { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - -func (log *Logger) Infoln(v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Infof(format string, v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - -func (log *Logger) Fatal(v ...interface{}) { - if log.logLevel > LogLevelInfo { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } - - os.Exit(1) -} - -func (log *Logger) Println(level int, v ...interface{}) { - if log.logLevel > level { - return - } - - for _, logger := range log.logSys { - logger.Println(v...) - } -} - -func (log *Logger) Printf(level int, format string, v ...interface{}) { - if log.logLevel > level { - return - } - - for _, logger := range log.logSys { - logger.Printf(format, v...) - } -} - type confValue struct { value string } From 16e8fc7427115e67096c6056b2ad9401803fcb44 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 23 Jun 2014 16:11:55 +0200 Subject: [PATCH 0490/1237] Logging order --- ethchain/state_object.go | 1 - ethchain/vm.go | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 0a2e28ded5..270c9a7f8c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -91,7 +91,6 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - // FIXME This should be handled in the Trie it self if val.BigInt().Cmp(ethutil.Big0) == 0 { c.state.trie.Delete(string(addr)) diff --git a/ethchain/vm.go b/ethchain/vm.go index 432bc4e6d2..4c6c5e24da 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -93,7 +93,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - fmt.Println("vm err", err) + fmt.Println(err) } }() @@ -106,11 +106,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require := func(m int) { if stack.Len() < m { isRequireError = true - panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) + panic(fmt.Sprintf("stack err = %d, req = %d", stack.Len(), m)) } } - // Instruction pointer + // Program counter pc := big.NewInt(0) // Current step count step := 0 @@ -593,16 +593,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) + + vm.Printf(" (*) %x", addr).Endl() + // Create a new contract contract := vm.state.NewStateObject(addr) contract.Amount = value // Set the init script - contract.initScript = mem.Get(offset.Int64(), size.Int64()) + contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - //closure.UseGas(gas) // Create the closure c := NewClosure(closure.caller, @@ -613,6 +615,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. + var err error c.Script, gas, err = c.Call(vm, nil, hook) if err != nil { From 0c55a113180955aa149a6e961c6e4bba9a7418e0 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 24 Jun 2014 11:15:26 +0200 Subject: [PATCH 0491/1237] Support hex and decimal keys for GetStorageAt RPC. Fixes ethereum/go-ethereum#74 --- ethrpc/packages.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 1c4fb99f6f..34d7a3d6fb 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethutil" "math/big" + "strings" ) type EthereumApi struct { @@ -174,9 +175,15 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { return err } state := p.ethp.GetStateObject(args.Address) - // Convert the incoming string (which is a bigint) into hex - i, _ := new(big.Int).SetString(args.Key, 10) - hx := ethutil.Hex(i.Bytes()) + + var hx string + if strings.Index(args.Key, "0x") == 0 { + hx = string([]byte(args.Key)[2:]) + } else { + // Convert the incoming string (which is a bigint) into hex + i, _ := new(big.Int).SetString(args.Key, 10) + hx = ethutil.Hex(i.Bytes()) + } value := state.GetStorage(hx) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil From 9dae1a17324df671bf2223ae80257a310cecfea5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 25 Jun 2014 09:47:19 +0200 Subject: [PATCH 0492/1237] Removed BlockDo Method --- ethereum.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/ethereum.go b/ethereum.go index 77a7c92c77..a6cb78b1fc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -113,24 +113,6 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { return ethereum, nil } -// Replay block -func (self *Ethereum) BlockDo(hash []byte) error { - block := self.blockChain.GetBlock(hash) - if block == nil { - return fmt.Errorf("unknown block %x", hash) - } - - parent := self.blockChain.GetBlock(block.PrevHash) - - _, err := self.stateManager.ApplyDiff(parent.State(), parent, block) - if err != nil { - return err - } - - return nil - -} - func (s *Ethereum) Reactor() *ethutil.ReactorEngine { return s.reactor } From 589d27386a4d630f052bf645a9e134a8b2d6fcad Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 25 Jun 2014 14:05:55 +0200 Subject: [PATCH 0493/1237] Fix key generation in ethPub --- ethpub/pub.go | 2 +- ethrpc/packages.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index b475453af0..6a41f575cc 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -142,7 +142,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc var keyPair *ethutil.KeyPair var err error if key[0:2] == "0x" { - keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2]))) + keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key[2:]))) } else { keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) } diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 34d7a3d6fb..3f57f69826 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -184,6 +184,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { i, _ := new(big.Int).SetString(args.Key, 10) hx = ethutil.Hex(i.Bytes()) } + ethutil.Config.Log.Debugf("[JSON] GetStorageAt(%s, %s)\n", args.Address, hx) value := state.GetStorage(hx) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil From 8fe8175c7870e18a791888a14630253f5a0476b0 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 25 Jun 2014 16:12:33 +0200 Subject: [PATCH 0494/1237] Implemented TX History for ethPub --- ethpub/pub.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 6a41f575cc..c4b10f0e6c 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -1,7 +1,9 @@ package ethpub import ( + "bytes" "encoding/hex" + "encoding/json" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -81,6 +83,34 @@ func (lib *PEthereum) GetCoinBase() string { return lib.SecretToAddress(hex.EncodeToString(key)) } +func (lib *PEthereum) GetTransactionsFor(address string, asJson bool) interface{} { + sBlk := lib.manager.BlockChain().LastBlockHash + blk := lib.manager.BlockChain().GetBlock(sBlk) + addr := []byte(ethutil.FromHex(address)) + + var txs []*PTx + + for ; blk != nil; blk = lib.manager.BlockChain().GetBlock(sBlk) { + sBlk = blk.PrevHash + + // Loop through all transactions to see if we missed any while being offline + for _, tx := range blk.Transactions() { + if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 { + ethutil.Config.Log.Debugf("FOund tx: %x\n", tx) + txs = append(txs, NewPTx(tx)) + } + } + } + if asJson { + txJson, err := json.Marshal(txs) + if err != nil { + return nil + } + return string(txJson) + } + return txs +} + func (lib *PEthereum) GetStorage(address, storageAddress string) string { return lib.GetStateObject(address).GetStorage(storageAddress) } @@ -123,7 +153,6 @@ func GetAddressFromNameReg(stateManager *ethchain.StateManager, name string) []b return nil } - func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool From d8c675afbf98178ffa447e4d36b77bbdad3f9ec0 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 25 Jun 2014 16:23:10 +0200 Subject: [PATCH 0495/1237] Implement something that looks like confirmations, wip --- ethpub/pub.go | 6 ++++-- ethpub/types.go | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index c4b10f0e6c..05acdb0583 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -96,8 +96,10 @@ func (lib *PEthereum) GetTransactionsFor(address string, asJson bool) interface{ // Loop through all transactions to see if we missed any while being offline for _, tx := range blk.Transactions() { if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 { - ethutil.Config.Log.Debugf("FOund tx: %x\n", tx) - txs = append(txs, NewPTx(tx)) + ptx := NewPTx(tx) + //TODO: somehow move this to NewPTx + ptx.Confirmations = int(lib.manager.BlockChain().LastBlockNumber - blk.BlockInfo().Number) + txs = append(txs, ptx) } } } diff --git a/ethpub/types.go b/ethpub/types.go index 3525981483..0ced68ad17 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -99,6 +99,7 @@ type PTx struct { Data string `json:"data"` Contract bool `json:"isContract"` CreatesContract bool `json:"createsContract"` + Confirmations int `json:"confirmations"` } func NewPTx(tx *ethchain.Transaction) *PTx { From b0dc50c2a0e25bf88901f3dd481f14bc3375adc5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 25 Jun 2014 17:26:34 +0200 Subject: [PATCH 0496/1237] New mutan implementation --- ethutil/script.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/ethutil/script.go b/ethutil/script.go index c8b1da51cf..235498df25 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -3,6 +3,7 @@ package ethutil import ( "fmt" "github.com/obscuren/mutan" + "github.com/obscuren/mutan/backends" "github.com/obscuren/serpent-go" "strings" ) @@ -19,7 +20,9 @@ func Compile(script string) (ret []byte, err error) { return byteCode, nil } else { - byteCode, errors := mutan.Compile(strings.NewReader(script), false) + compiler := mutan.NewCompiler(backend.NewEthereumBackend()) + byteCode, errors := compiler.Compile(strings.NewReader(script)) + //byteCode, errors := mutan.Compile(strings.NewReader(script), false) if len(errors) > 0 { var errs string for _, er := range errors { @@ -33,21 +36,3 @@ func Compile(script string) (ret []byte, err error) { return byteCode, nil } } - -func CompileScript(script string) ([]byte, []byte, error) { - // Preprocess - mainInput, initInput := mutan.PreParse(script) - // Compile main script - mainScript, err := Compile(mainInput) - if err != nil { - return nil, nil, err - } - - // Compile init script - initScript, err := Compile(initInput) - if err != nil { - return nil, nil, err - } - - return mainScript, initScript, nil -} From e75f7ae3301bb66ca6d4e9c099c6a14bbe2be418 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 16:37:38 +0100 Subject: [PATCH 0497/1237] implement DebugDetail loglevel and named print methods --- ethlog/loggers.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethlog/loggers.go b/ethlog/loggers.go index e656ffbe59..be42c9fb73 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -49,6 +49,7 @@ const ( WarnLevel InfoLevel DebugLevel + DebugDetailLevel ) // log messages are dispatched to log writers @@ -123,6 +124,10 @@ func (logger *Logger) Debugln(v...interface{}) { logger.sendln(DebugLevel, v...) } +func (logger *Logger) DebugDetailln(v...interface{}) { + logger.sendln(DebugDetailLevel, v...) +} + func (logger *Logger) Errorf(format string, v...interface{}) { logger.sendf(ErrorLevel, format, v...) } @@ -139,6 +144,10 @@ func (logger *Logger) Debugf(format string, v...interface{}) { logger.sendf(DebugLevel, format, v...) } +func (logger *Logger) DebugDetailf(format string, v...interface{}) { + logger.sendf(DebugDetailLevel, format, v...) +} + func (logger *Logger) Fatalln (v...interface{}) { logger.sendln(ErrorLevel, v...) Flush() From 6465e4c3fd21e7002e5870069c51755bd2c66df5 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 16:38:42 +0100 Subject: [PATCH 0498/1237] update doc: list levels and show usage of named print methods --- ethlog/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethlog/README.md b/ethlog/README.md index f8818d98e7..d9b69e1066 100644 --- a/ethlog/README.md +++ b/ethlog/README.md @@ -6,6 +6,7 @@ - log level can be set separately per log system - async logging thread: logging IO does not block main thread - log messages are synchronously stringified to avoid incorrectly logging of changed states +- log level enum: ethlog.LogLevel: Silence, ErrorLevel, WarnLevel, InfoLevel, DebugLevel, DebugDetailLevel ## Usage @@ -16,7 +17,10 @@ In an ethereum component package: // package-wide logger using tag var logger = ethlog.NewLogger("TAG") +Logger provides named Printf and Println style methods for all loglevels + logger.Infoln("this is info") # > [TAG] This is info + logger.Infof("this %v is info", object) # > [TAG] This object is info Ethereum wrappers should register log systems conforming to ethlog.LogSystem From a02edf7a9306c9c0b2f0208152347b47f1a4e689 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 16:40:06 +0100 Subject: [PATCH 0499/1237] put back extra debug detail logging to the right places using logger.DebugDetailf --- ethchain/state_object.go | 2 +- peer.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7d7352af4b..26ad3e9827 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -158,7 +158,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - statelogger.Infof("%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { diff --git a/peer.go b/peer.go index 18d1da4553..2dcdea4742 100644 --- a/peer.go +++ b/peer.go @@ -250,7 +250,7 @@ func (p *Peer) writeMessage(msg *ethwire.Msg) { } } - peerlogger.Infoln("<=", msg.Type, msg.Data) + peerlogger.DebugDetailln("<=", msg.Type, msg.Data) err := ethwire.WriteMessage(p.conn, msg) if err != nil { @@ -324,7 +324,7 @@ func (p *Peer) HandleInbound() { peerlogger.Debugln(err) } for _, msg := range msgs { - peerlogger.Infoln("=>", msg.Type, msg.Data) + peerlogger.DebugDetailln("=>", msg.Type, msg.Data) switch msg.Type { case ethwire.MsgHandshakeTy: @@ -429,7 +429,7 @@ func (p *Peer) HandleInbound() { if p.catchingUp && msg.Data.Len() > 1 { if lastBlock != nil { blockInfo := lastBlock.BlockInfo() - peerlogger.Infof("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) + peerlogger.DebugDetailf("Synced chain to #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) } p.catchingUp = false @@ -496,7 +496,7 @@ func (p *Peer) HandleInbound() { // If a parent is found send back a reply if parent != nil { - peerlogger.Infof("Found canonical block, returning chain from: %x ", parent.Hash()) + peerlogger.DebugDetailf("Found canonical block, returning chain from: %x ", parent.Hash()) chain := p.ethereum.BlockChain().GetChainFromHash(parent.Hash(), amountOfBlocks) if len(chain) > 0 { //peerlogger.Debugf("Returning %d blocks: %x ", len(chain), parent.Hash()) @@ -516,7 +516,7 @@ func (p *Peer) HandleInbound() { } } case ethwire.MsgNotInChainTy: - peerlogger.Infof("Not in chain: %x\n", msg.Data.Get(0).Bytes()) + peerlogger.DebugDetailf("Not in chain: %x\n", msg.Data.Get(0).Bytes()) if p.diverted == true { // If were already looking for a common parent and we get here again we need to go deeper p.blocksRequested = p.blocksRequested * 2 @@ -737,7 +737,7 @@ func (p *Peer) FindCommonParentBlock() { msgInfo := append(hashes, uint64(len(hashes))) - peerlogger.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) + peerlogger.DebugDetailf("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String()) msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo) p.QueueMessage(msg) @@ -749,7 +749,7 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) p.QueueMessage(msg) - peerlogger.Infof("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()) msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) p.QueueMessage(msg) From a243e3b8588bb3a65af4a7131c279b9d94c62be1 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 17:59:35 +0100 Subject: [PATCH 0500/1237] new logger API for upstream merge --- ethrpc/packages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 3f57f69826..7102757803 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -184,7 +184,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { i, _ := new(big.Int).SetString(args.Key, 10) hx = ethutil.Hex(i.Bytes()) } - ethutil.Config.Log.Debugf("[JSON] GetStorageAt(%s, %s)\n", args.Address, hx) + logger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) value := state.GetStorage(hx) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil From 782f780476afb3c895c30583fc5cbd6d7d830d3d Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 25 Jun 2014 18:43:35 +0100 Subject: [PATCH 0501/1237] space in miner logging message --- ethminer/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 5f5c40134e..2c16456723 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -159,7 +159,7 @@ func (self *Miner) mineNewBlock() { self.block.State().Update() - logger.Infoln("Mining on block. Includes", len(self.txs), "transactions") + logger.Infof("Mining on block. Includes %v transactions", len(self.txs)) // Find a valid nonce self.block.Nonce = self.pow.Search(self.block, self.powQuitChan) From 39cb34850a573ea9b2ea73eb624139684502bc79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 11:25:43 +0200 Subject: [PATCH 0502/1237] Added instruction numbers --- ethchain/asm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff93..09d6af56fc 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -18,7 +18,7 @@ func Disassemble(script []byte) (asm []string) { // Get the opcode (it must be an opcode!) op := OpCode(val) - asm = append(asm, fmt.Sprintf("%v", op)) + asm = append(asm, fmt.Sprintf("%04v: %v", pc, op)) switch op { 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: @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data)) pc.Add(pc, big.NewInt(a-1)) } From 0ed19d9f2024744ba93d0e34db6939766b3cfed5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 11:26:42 +0200 Subject: [PATCH 0503/1237] Logging, variable rearrangement --- ethchain/block_chain.go | 11 +++++------ ethchain/vm.go | 31 +++++++++++++++---------------- ethereum.go | 4 ++-- ethutil/script.go | 1 - ethutil/trie.go | 2 +- 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 19b5248d77..286a158ba2 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -174,18 +174,12 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockHash = bc.genesisBlock.Hash() bc.LastBlockNumber = 1 } else { - // TODO: Somehow this doesn't really give the right numbers, double check. - // TODO: Change logs into debug lines returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - //info := bc.BlockInfo(returnTo) bc.LastBlockNumber = returnTo.Number.Uint64() } - // XXX Why are we resetting? This is the block chain, it has nothing to do with states - //bc.Ethereum.StateManager().PrepareDefault(returnTo) - // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { @@ -231,6 +225,11 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { // Get the block of the chain block := bc.GetBlock(currentHash) + if block == nil { + ethutil.Config.Log.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash) + break + } + currentHash = block.PrevHash chain = append(chain, block.Value().Val) diff --git a/ethchain/vm.go b/ethchain/vm.go index 4c6c5e24da..199eaae50c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -99,22 +99,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) - // Memory for the current closure - mem := &Memory{} - // New stack (should this be shared?) - stack := NewStack() - require := func(m int) { - if stack.Len() < m { - isRequireError = true - panic(fmt.Sprintf("stack err = %d, req = %d", stack.Len(), m)) - } - } + var ( + op OpCode - // Program counter - pc := big.NewInt(0) - // Current step count - step := 0 - prevStep := 0 + mem = &Memory{} + stack = NewStack() + pc = big.NewInt(0) + step = 0 + prevStep = 0 + require = func(m int) { + if stack.Len() < m { + isRequireError = true + panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) + } + } + ) for { prevStep = step @@ -125,7 +124,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the memory location of pc val := closure.Get(pc) // Get the opcode (it must be an opcode!) - op := OpCode(val.Uint()) + op = OpCode(val.Uint()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { diff --git a/ethereum.go b/ethereum.go index a6cb78b1fc..6345f8864d 100644 --- a/ethereum.go +++ b/ethereum.go @@ -340,7 +340,7 @@ func (s *Ethereum) Start(seed bool) { // Bind to addr and port ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { - log.Println("Connection listening disabled. Acting as client") + ethutil.Config.Log.Infof("port=%s in use. Connection listening disabled.") s.listening = false } else { s.listening = true @@ -395,7 +395,7 @@ func (s *Ethereum) Seed() { peers = append(peers, peer) } } else { - ethutil.Config.Log.Debugln("[SERV} Couldn't resolve :", target) + ethutil.Config.Log.Debugln("[SERV] Couldn't resolve :", target) } } // Connect to Peer list diff --git a/ethutil/script.go b/ethutil/script.go index 235498df25..af4ca6a387 100644 --- a/ethutil/script.go +++ b/ethutil/script.go @@ -22,7 +22,6 @@ func Compile(script string) (ret []byte, err error) { } else { compiler := mutan.NewCompiler(backend.NewEthereumBackend()) byteCode, errors := compiler.Compile(strings.NewReader(script)) - //byteCode, errors := mutan.Compile(strings.NewReader(script), false) if len(errors) > 0 { var errs string for _, er := range errors { diff --git a/ethutil/trie.go b/ethutil/trie.go index 18d0a5f0ae..0c1a6d2603 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -47,7 +47,7 @@ func (cache *Cache) Put(v interface{}) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) >= 32 { + if len(enc) < 32 { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) From 098136b68198083a47408ec5c04cd0c8f9fdcc87 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 10:43:02 +0100 Subject: [PATCH 0504/1237] ethereum logs server started/stopped message --- ethereum.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethereum.go b/ethereum.go index 1de6717125..28d1c04378 100644 --- a/ethereum.go +++ b/ethereum.go @@ -362,6 +362,7 @@ func (s *Ethereum) Start(seed bool) { if seed { s.Seed() } + ethlogger.Infoln("Server started") } func (s *Ethereum) Seed() { @@ -449,6 +450,7 @@ func (s *Ethereum) Stop() { s.txPool.Stop() s.stateManager.Stop() + ethlogger.Infoln("Server stopped") close(s.shutdownChan) } From 21e389bec5c6ce287273f5a1dd7ed5eee496616a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 26 Jun 2014 19:04:57 +0200 Subject: [PATCH 0505/1237] bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dda1e3a839..26783d12d6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC14". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.5.15". 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. From 853053a3b204ddf4ae935e70e0aa5b5d8994493e Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 18:45:57 +0100 Subject: [PATCH 0506/1237] go fmt --- ethchain/block_chain.go | 2 +- ethchain/dagger.go | 3 +- ethchain/state_manager.go | 2 +- ethchain/transaction_pool.go | 2 +- ethchain/vm.go | 2 +- ethereum.go | 2 +- ethlog/loggers.go | 202 +++++++++++++++++------------------ ethlog/loggers_test.go | 150 +++++++++++++------------- ethminer/miner.go | 10 +- ethpub/pub.go | 2 +- ethrpc/server.go | 2 +- ethutil/config.go | 26 ++--- ethutil/encoding_test.go | 2 +- peer.go | 2 +- 14 files changed, 204 insertions(+), 205 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 05b2564cfd..d0fea6641d 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,9 +2,9 @@ package ethchain import ( "bytes" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "math" "math/big" ) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 43725e3362..08c4826dbf 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,8 +1,8 @@ package ethchain import ( - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" "math/big" @@ -31,7 +31,6 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - //powlogger.Infoln("Received reactor event; breaking out.") return nil default: i++ diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index e5941b1652..312ba3084e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,9 +3,9 @@ package ethchain import ( "bytes" "container/list" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "math/big" "sync" "time" diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 44218ae287..6ab8d83d9d 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -4,8 +4,8 @@ import ( "bytes" "container/list" "fmt" - "github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethwire" "math/big" "sync" ) diff --git a/ethchain/vm.go b/ethchain/vm.go index 20d355674c..82591e2745 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,8 +2,8 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" "math" "math/big" ) diff --git a/ethereum.go b/ethereum.go index 8caa75cbd4..a3df23e924 100644 --- a/ethereum.go +++ b/ethereum.go @@ -5,10 +5,10 @@ import ( "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "io/ioutil" "math/rand" "net" diff --git a/ethlog/loggers.go b/ethlog/loggers.go index be42c9fb73..9ebe590967 100644 --- a/ethlog/loggers.go +++ b/ethlog/loggers.go @@ -1,188 +1,188 @@ package ethlog import ( - "fmt" - "sync" - "log" - "io" - "os" + "fmt" + "io" + "log" + "os" + "sync" ) type LogSystem interface { - GetLogLevel() LogLevel - SetLogLevel(i LogLevel) - Println(v ...interface{}) - Printf(format string, v ...interface{}) + GetLogLevel() LogLevel + SetLogLevel(i LogLevel) + Println(v ...interface{}) + Printf(format string, v ...interface{}) } type logMessage struct { - LogLevel LogLevel - format bool - msg string + LogLevel LogLevel + format bool + msg string } -func newPrintlnLogMessage(level LogLevel, tag string, v...interface{}) *logMessage { - return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))} +func newPrintlnLogMessage(level LogLevel, tag string, v ...interface{}) *logMessage { + return &logMessage{level, false, fmt.Sprintf("[%s] %s", tag, fmt.Sprint(v...))} } -func newPrintfLogMessage(level LogLevel, tag string, format string, v...interface{}) *logMessage { - return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))} +func newPrintfLogMessage(level LogLevel, tag string, format string, v ...interface{}) *logMessage { + return &logMessage{level, true, fmt.Sprintf("[%s] %s", tag, fmt.Sprintf(format, v...))} } func (msg *logMessage) send(logger LogSystem) { - if msg.format { - logger.Printf(msg.msg) - } else { - logger.Println(msg.msg) - } + if msg.format { + logger.Printf(msg.msg) + } else { + logger.Println(msg.msg) + } } -var logMessages chan(*logMessage) -var logSystems []LogSystem +var logMessages chan (*logMessage) +var logSystems []LogSystem var drained = true type LogLevel uint8 const ( - Silence LogLevel = iota - ErrorLevel - WarnLevel - InfoLevel - DebugLevel - DebugDetailLevel + Silence LogLevel = iota + ErrorLevel + WarnLevel + InfoLevel + DebugLevel + DebugDetailLevel ) // log messages are dispatched to log writers func start() { - for { - select { - case msg := <- logMessages: - for _, logSystem := range logSystems { - if logSystem.GetLogLevel() >= msg.LogLevel { - msg.send(logSystem) - } - } - default: - drained = true - } - } + for { + select { + case msg := <-logMessages: + for _, logSystem := range logSystems { + if logSystem.GetLogLevel() >= msg.LogLevel { + msg.send(logSystem) + } + } + default: + drained = true + } + } } // waits until log messages are drained (dispatched to log writers) func Flush() { - for !drained {} + for !drained { + } } type Logger struct { - tag string + tag string } func NewLogger(tag string) *Logger { - return &Logger{tag} + return &Logger{tag} } func AddLogSystem(logSystem LogSystem) { - var mutex = &sync.Mutex{} - mutex.Lock() - defer mutex.Unlock() - if logSystems == nil { - logMessages = make(chan *logMessage) - go start() - } - logSystems = append(logSystems, logSystem) + var mutex = &sync.Mutex{} + mutex.Lock() + defer mutex.Unlock() + if logSystems == nil { + logMessages = make(chan *logMessage) + go start() + } + logSystems = append(logSystems, logSystem) } -func (logger *Logger) sendln(level LogLevel, v...interface{}) { - if logMessages != nil { - msg := newPrintlnLogMessage(level, logger.tag, v...) - drained = false - logMessages <- msg - } +func (logger *Logger) sendln(level LogLevel, v ...interface{}) { + if logMessages != nil { + msg := newPrintlnLogMessage(level, logger.tag, v...) + drained = false + logMessages <- msg + } } -func (logger *Logger) sendf(level LogLevel, format string, v...interface{}) { - if logMessages != nil { - msg := newPrintfLogMessage(level, logger.tag, format, v...) - drained = false - logMessages <- msg - } +func (logger *Logger) sendf(level LogLevel, format string, v ...interface{}) { + if logMessages != nil { + msg := newPrintfLogMessage(level, logger.tag, format, v...) + drained = false + logMessages <- msg + } } -func (logger *Logger) Errorln(v...interface{}) { - logger.sendln(ErrorLevel, v...) +func (logger *Logger) Errorln(v ...interface{}) { + logger.sendln(ErrorLevel, v...) } -func (logger *Logger) Warnln(v...interface{}) { - logger.sendln(WarnLevel, v...) +func (logger *Logger) Warnln(v ...interface{}) { + logger.sendln(WarnLevel, v...) } -func (logger *Logger) Infoln(v...interface{}) { - logger.sendln(InfoLevel, v...) +func (logger *Logger) Infoln(v ...interface{}) { + logger.sendln(InfoLevel, v...) } -func (logger *Logger) Debugln(v...interface{}) { - logger.sendln(DebugLevel, v...) +func (logger *Logger) Debugln(v ...interface{}) { + logger.sendln(DebugLevel, v...) } -func (logger *Logger) DebugDetailln(v...interface{}) { - logger.sendln(DebugDetailLevel, v...) +func (logger *Logger) DebugDetailln(v ...interface{}) { + logger.sendln(DebugDetailLevel, v...) } -func (logger *Logger) Errorf(format string, v...interface{}) { - logger.sendf(ErrorLevel, format, v...) +func (logger *Logger) Errorf(format string, v ...interface{}) { + logger.sendf(ErrorLevel, format, v...) } -func (logger *Logger) Warnf(format string, v...interface{}) { - logger.sendf(WarnLevel, format, v...) +func (logger *Logger) Warnf(format string, v ...interface{}) { + logger.sendf(WarnLevel, format, v...) } -func (logger *Logger) Infof(format string, v...interface{}) { - logger.sendf(InfoLevel, format, v...) +func (logger *Logger) Infof(format string, v ...interface{}) { + logger.sendf(InfoLevel, format, v...) } -func (logger *Logger) Debugf(format string, v...interface{}) { - logger.sendf(DebugLevel, format, v...) +func (logger *Logger) Debugf(format string, v ...interface{}) { + logger.sendf(DebugLevel, format, v...) } -func (logger *Logger) DebugDetailf(format string, v...interface{}) { - logger.sendf(DebugDetailLevel, format, v...) +func (logger *Logger) DebugDetailf(format string, v ...interface{}) { + logger.sendf(DebugDetailLevel, format, v...) } -func (logger *Logger) Fatalln (v...interface{}) { - logger.sendln(ErrorLevel, v...) - Flush() - os.Exit(0) +func (logger *Logger) Fatalln(v ...interface{}) { + logger.sendln(ErrorLevel, v...) + Flush() + os.Exit(0) } -func (logger *Logger) Fatalf (format string, v...interface{}) { - logger.sendf(ErrorLevel, format, v...) - Flush() - os.Exit(0) +func (logger *Logger) Fatalf(format string, v ...interface{}) { + logger.sendf(ErrorLevel, format, v...) + Flush() + os.Exit(0) } type StdLogSystem struct { - logger *log.Logger - level LogLevel + logger *log.Logger + level LogLevel } func (t *StdLogSystem) Println(v ...interface{}) { - t.logger.Println(v...) + t.logger.Println(v...) } func (t *StdLogSystem) Printf(format string, v ...interface{}) { - t.logger.Printf(format, v...) + t.logger.Printf(format, v...) } func (t *StdLogSystem) SetLogLevel(i LogLevel) { - t.level = i + t.level = i } func (t *StdLogSystem) GetLogLevel() LogLevel { - return t.level + return t.level } func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem { - logger := log.New(writer, "", flags) - return &StdLogSystem{logger, level} + logger := log.New(writer, "", flags) + return &StdLogSystem{logger, level} } - diff --git a/ethlog/loggers_test.go b/ethlog/loggers_test.go index c330820120..89f4166810 100644 --- a/ethlog/loggers_test.go +++ b/ethlog/loggers_test.go @@ -1,115 +1,109 @@ package ethlog import ( - "testing" - "fmt" - "io/ioutil" - "os" + "fmt" + "io/ioutil" + "os" + "testing" ) type TestLogSystem struct { - Output string - level LogLevel + Output string + level LogLevel } func (t *TestLogSystem) Println(v ...interface{}) { - t.Output += fmt.Sprintln(v...) + t.Output += fmt.Sprintln(v...) } func (t *TestLogSystem) Printf(format string, v ...interface{}) { - t.Output += fmt.Sprintf(format, v...) + t.Output += fmt.Sprintf(format, v...) } func (t *TestLogSystem) SetLogLevel(i LogLevel) { - t.level = i + t.level = i } func (t *TestLogSystem) GetLogLevel() LogLevel { - return t.level + return t.level } func quote(s string) string { - return fmt.Sprintf("'%s'", s) + return fmt.Sprintf("'%s'", s) } func TestLoggerPrintln(t *testing.T) { - logger := NewLogger("TEST") - testLogSystem := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem) - logger.Errorln("error") - logger.Warnln("warn") - logger.Infoln("info") - logger.Debugln("debug") - Flush() - output := testLogSystem.Output - fmt.Println(quote(output)) - if output != "[TEST] error\n[TEST] warn\n" { - t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem.Output)) - } + logger := NewLogger("TEST") + testLogSystem := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem) + logger.Errorln("error") + logger.Warnln("warn") + logger.Infoln("info") + logger.Debugln("debug") + Flush() + output := testLogSystem.Output + fmt.Println(quote(output)) + if output != "[TEST] error\n[TEST] warn\n" { + t.Error("Expected logger output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem.Output)) + } } func TestLoggerPrintf(t *testing.T) { - logger := NewLogger("TEST") - testLogSystem := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem) - logger.Errorf("error to %v\n", *testLogSystem) - logger.Warnf("warn") - logger.Infof("info") - logger.Debugf("debug") - Flush() - output := testLogSystem.Output - fmt.Println(quote(output)) - if output != "[TEST] error to { 2}\n[TEST] warn" { - t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", quote(testLogSystem.Output)) - } + logger := NewLogger("TEST") + testLogSystem := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem) + logger.Errorf("error to %v\n", *testLogSystem) + logger.Warnf("warn") + logger.Infof("info") + logger.Debugf("debug") + Flush() + output := testLogSystem.Output + fmt.Println(quote(output)) + if output != "[TEST] error to { 2}\n[TEST] warn" { + t.Error("Expected logger output '[TEST] error to { 2}\\n[TEST] warn', got ", quote(testLogSystem.Output)) + } } func TestMultipleLogSystems(t *testing.T) { - logger := NewLogger("TEST") - testLogSystem0 := &TestLogSystem{level: ErrorLevel} - testLogSystem1 := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem0) - AddLogSystem(testLogSystem1) - logger.Errorln("error") - logger.Warnln("warn") - Flush() - output0 := testLogSystem0.Output - output1 := testLogSystem1.Output - if output0 != "[TEST] error\n" { - t.Error("Expected logger 0 output '[TEST] error\\n', got ", quote(testLogSystem0.Output)) - } - if output1 != "[TEST] error\n[TEST] warn\n" { - t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem1.Output)) - } + logger := NewLogger("TEST") + testLogSystem0 := &TestLogSystem{level: ErrorLevel} + testLogSystem1 := &TestLogSystem{level: WarnLevel} + AddLogSystem(testLogSystem0) + AddLogSystem(testLogSystem1) + logger.Errorln("error") + logger.Warnln("warn") + Flush() + output0 := testLogSystem0.Output + output1 := testLogSystem1.Output + if output0 != "[TEST] error\n" { + t.Error("Expected logger 0 output '[TEST] error\\n', got ", quote(testLogSystem0.Output)) + } + if output1 != "[TEST] error\n[TEST] warn\n" { + t.Error("Expected logger 1 output '[TEST] error\\n[TEST] warn\\n', got ", quote(testLogSystem1.Output)) + } } func TestFileLogSystem(t *testing.T) { - logger := NewLogger("TEST") - filename := "test.log" - file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - testLogSystem := NewStdLogSystem(file, 0, WarnLevel) - AddLogSystem(testLogSystem) - logger.Errorf("error to %s\n", filename) - logger.Warnln("warn") - Flush() - contents, _ := ioutil.ReadFile(filename) - output := string(contents) - fmt.Println(quote(output)) - if output != "[TEST] error to test.log\n[TEST] warn\n" { - t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", quote(output)) - } else { - os.Remove(filename) - } + logger := NewLogger("TEST") + filename := "test.log" + file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) + testLogSystem := NewStdLogSystem(file, 0, WarnLevel) + AddLogSystem(testLogSystem) + logger.Errorf("error to %s\n", filename) + logger.Warnln("warn") + Flush() + contents, _ := ioutil.ReadFile(filename) + output := string(contents) + fmt.Println(quote(output)) + if output != "[TEST] error to test.log\n[TEST] warn\n" { + t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", quote(output)) + } else { + os.Remove(filename) + } } func TestNoLogSystem(t *testing.T) { - logger := NewLogger("TEST") - logger.Warnln("warn") - Flush() + logger := NewLogger("TEST") + logger.Warnln("warn") + Flush() } - - - - - - diff --git a/ethminer/miner.go b/ethminer/miner.go index 2c16456723..66388723ec 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -3,9 +3,9 @@ package ethminer import ( "bytes" "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "sort" ) @@ -57,18 +57,23 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner { return miner } + func (miner *Miner) Start() { // Prepare inital block //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) go miner.listener() + logger.Infoln("Started") } + func (miner *Miner) listener() { out: for { select { case <-miner.quitChan: + logger.Infoln("Stopped") break out case chanMessage := <-miner.reactChan: + if block, ok := chanMessage.Resource.(*ethchain.Block); ok { //logger.Infoln("Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { @@ -123,8 +128,9 @@ out: } func (self *Miner) Stop() { - self.powQuitChan <- ethutil.React{} + logger.Infoln("Stopping...") self.quitChan <- true + self.powQuitChan <- ethutil.React{} } func (self *Miner) mineNewBlock() { diff --git a/ethpub/pub.go b/ethpub/pub.go index 647e689ce2..1bc9e0ce7d 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -5,8 +5,8 @@ import ( "encoding/hex" "encoding/json" "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" "math/big" "strings" "sync/atomic" diff --git a/ethrpc/server.go b/ethrpc/server.go index b55469b832..d9d6f695b5 100644 --- a/ethrpc/server.go +++ b/ethrpc/server.go @@ -2,8 +2,8 @@ package ethrpc import ( "fmt" - "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethpub" "net" "net/rpc" "net/rpc/jsonrpc" diff --git a/ethutil/config.go b/ethutil/config.go index 52537ffa6c..aa4ae9c3eb 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -4,8 +4,8 @@ import ( "flag" "fmt" "github.com/rakyll/globalconf" - "runtime" "os" + "runtime" ) // Config struct @@ -29,21 +29,21 @@ var Config *config // Initialize Config from Config File func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { if Config == nil { - // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags - _, err := os.Stat(ConfigFile) - if err != nil && os.IsNotExist(err) { + // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags + _, err := os.Stat(ConfigFile) + if err != nil && os.IsNotExist(err) { fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) - os.Create(ConfigFile) - } - g, err := globalconf.NewWithOptions(&globalconf.Options{ - Filename: ConfigFile, - EnvPrefix: EnvPrefix, + os.Create(ConfigFile) + } + g, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: ConfigFile, + EnvPrefix: EnvPrefix, }) if err != nil { - fmt.Println(err) - } else { - g.ParseAll() - } + fmt.Println(err) + } else { + g.ParseAll() + } Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } diff --git a/ethutil/encoding_test.go b/ethutil/encoding_test.go index cbfbc0eafa..10e1995c02 100644 --- a/ethutil/encoding_test.go +++ b/ethutil/encoding_test.go @@ -64,4 +64,4 @@ func TestCompactDecode(t *testing.T) { if !CompareIntSlice(res, exp) { t.Error("even terminated compact decode. Expected", exp, "got", res) } -} \ No newline at end of file +} diff --git a/peer.go b/peer.go index 2dcdea4742..e50fd43f93 100644 --- a/peer.go +++ b/peer.go @@ -5,9 +5,9 @@ import ( "container/list" "fmt" "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/eth-go/ethlog" "net" "strconv" "strings" From d551a75c35027a3cf6344293923cdcdab61d5f38 Mon Sep 17 00:00:00 2001 From: zelig Date: Thu, 26 Jun 2014 21:20:02 +0100 Subject: [PATCH 0507/1237] bump v5.15 --- ethutil/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index aa4ae9c3eb..b253aa203a 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } return Config From 8119d77a21d3973fe6379c5d57f393dda8fce392 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 27 Jun 2014 00:08:19 +0200 Subject: [PATCH 0508/1237] :-( --- ethutil/trie.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 0c1a6d2603..18d0a5f0ae 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -47,7 +47,7 @@ func (cache *Cache) Put(v interface{}) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) < 32 { + if len(enc) >= 32 { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) From 423beddf574383ec58246938f738f08cd50f031a Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 27 Jun 2014 00:16:49 +0200 Subject: [PATCH 0509/1237] nil check --- ethchain/block_chain.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index d0fea6641d..6e4c72b278 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -221,9 +221,16 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { startNumber := parentNumber + count num := lastNumber - for ; num > startNumber; currentHash = bc.GetBlock(currentHash).PrevHash { + for num > startNumber { num-- + + block := bc.GetBlock(currentHash) + if block == nil { + break + } + currentHash = block.PrevHash } + for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { // Get the block of the chain block := bc.GetBlock(currentHash) From 79009ca074d77561c655b65254103b4070b74c69 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 27 Jun 2014 15:56:45 +0100 Subject: [PATCH 0510/1237] transitional ethutil.ReadConfig fixes in ethchain tests (they still fail! FIXME :) --- ethchain/block_chain_test.go | 10 +++++++++- ethchain/state_object_test.go | 4 ++-- ethchain/state_test.go | 2 +- ethchain/vm_test.go | 2 +- ethutil/config.go | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index ecaf8ca894..bbc96c823c 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -1,6 +1,7 @@ package ethchain import ( + "container/list" "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" @@ -30,6 +31,10 @@ func (s *TestManager) PeerCount() int { return 0 } +func (s *TestManager) Peers() *list.List { + return list.New() +} + func (s *TestManager) BlockChain() *BlockChain { return s.blockChain } @@ -50,7 +55,8 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", ethutil.LogStd, "") + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, err := ethdb.NewMemDatabase() if err != nil { @@ -71,12 +77,14 @@ func NewTestManager() *TestManager { return testManager } + func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) err := tm.StateManager().Process(block, false) return err } + func (tm *TestManager) CreateChain1() error { err := tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 58, 253, 98, 206, 198, 181, 152, 223, 201, 116, 197, 154, 111, 104, 54, 113, 249, 184, 246, 15, 226, 142, 187, 47, 138, 60, 201, 66, 226, 237, 29, 7, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 240, 0, 132, 83, 48, 32, 251, 128, 160, 4, 10, 11, 225, 132, 86, 146, 227, 229, 137, 164, 245, 16, 139, 219, 12, 251, 178, 154, 168, 210, 18, 84, 40, 250, 41, 124, 92, 169, 242, 246, 180, 192, 192}) err = tm.AddFakeBlock([]byte{248, 246, 248, 242, 160, 222, 229, 152, 228, 200, 163, 244, 144, 120, 18, 203, 253, 195, 185, 105, 131, 163, 226, 116, 40, 140, 68, 249, 198, 221, 152, 121, 0, 124, 11, 180, 125, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 184, 65, 4, 103, 109, 19, 120, 219, 91, 248, 48, 204, 17, 28, 7, 146, 72, 203, 15, 207, 251, 31, 216, 138, 26, 59, 34, 238, 40, 114, 233, 1, 13, 207, 90, 71, 136, 124, 86, 196, 127, 10, 176, 193, 154, 165, 76, 155, 154, 59, 45, 34, 96, 183, 212, 99, 41, 27, 40, 119, 171, 231, 160, 114, 56, 218, 173, 160, 80, 218, 177, 253, 147, 35, 101, 59, 37, 87, 97, 193, 119, 21, 132, 111, 93, 53, 152, 203, 38, 134, 25, 104, 138, 236, 92, 27, 176, 89, 229, 176, 160, 29, 204, 77, 232, 222, 199, 93, 122, 171, 133, 181, 103, 182, 204, 212, 26, 211, 18, 69, 27, 148, 138, 116, 19, 240, 161, 66, 253, 64, 212, 147, 71, 131, 63, 224, 4, 132, 83, 48, 36, 250, 128, 160, 79, 58, 51, 246, 238, 249, 210, 253, 136, 83, 71, 134, 49, 114, 190, 189, 242, 78, 100, 238, 101, 84, 204, 176, 198, 25, 139, 151, 60, 84, 51, 126, 192, 192}) diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index 91ed7c0ddf..2588100d0b 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -9,7 +9,7 @@ import ( ) func TestSync(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) @@ -28,7 +28,7 @@ func TestSync(t *testing.T) { } func TestObjectGet(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 2921299536..503bdddb47 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -7,7 +7,7 @@ import ( ) func TestSnapshot(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 518a88766d..c569d89ae0 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -12,7 +12,7 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd, "") + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) diff --git a/ethutil/config.go b/ethutil/config.go index aa4ae9c3eb..b253aa203a 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.14", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} Config.SetClientString("Ethereum(G)") } return Config From 7489fb784e1dfc780017b105a01fe49d00228c34 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:56:19 +0100 Subject: [PATCH 0511/1237] move ethutil helper slice functions -> slice --- ethutil/slice.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ethutil/slice.go diff --git a/ethutil/slice.go b/ethutil/slice.go new file mode 100644 index 0000000000..67f43705dc --- /dev/null +++ b/ethutil/slice.go @@ -0,0 +1,28 @@ +package ethutil + +import ( + "strconv" +) + +// Helper function for comparing slices +func CompareIntSlice(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +// Returns the amount of nibbles that match each other from 0 ... +func MatchingNibbleLength(a, b []int) int { + i := 0 + for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { + i += 1 + } + + return i +} From 5c1e0a6dc4e49154c185503ef7c8e96328dd6492 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:56:40 +0100 Subject: [PATCH 0512/1237] move ethutil hex conversion functions to bytes --- ethutil/bytes.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index 5e3ee4a6f6..c2817946bf 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -3,6 +3,7 @@ package ethutil import ( "bytes" "encoding/binary" + "encoding/hex" "fmt" "math/big" "strings" @@ -91,9 +92,18 @@ func IsHex(str string) bool { return l >= 4 && l%2 == 0 && str[0:2] == "0x" } +func Bytes2Hex(d []byte) string { + return hex.EncodeToString(d) +} + +func Hex2Bytes(str string) []byte { + h, _ := hex.DecodeString(str) + return h +} + func StringToByteFunc(str string, cb func(str string) []byte) (ret []byte) { if len(str) > 1 && str[0:2] == "0x" && !strings.Contains(str, "\n") { - ret = FromHex(str[2:]) + ret = Hex2Bytes(str[2:]) } else { ret = cb(str) } @@ -110,7 +120,7 @@ func FormatData(data string) []byte { if data[0:1] == "\"" && data[len(data)-1:] == "\"" { d.SetBytes([]byte(data[1 : len(data)-1])) } else if len(data) > 1 && data[:2] == "0x" { - d.SetBytes(FromHex(data[2:])) + d.SetBytes(Hex2Bytes(data[2:])) } else { d.SetString(data, 0) } From d085133c6d9d75e9cbd016a9a597097fa2bb4345 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:57:12 +0100 Subject: [PATCH 0513/1237] move ethutil helper crypto functions to ethcrypto/crypto --- ethcrypto/crypto.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 ethcrypto/crypto.go diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go new file mode 100644 index 0000000000..9c4013d6c8 --- /dev/null +++ b/ethcrypto/crypto.go @@ -0,0 +1,27 @@ +package ethcrypto + +import ( + "code.google.com/p/go.crypto/ripemd160" + "crypto/sha256" + "github.com/obscuren/sha3" +) + +func Sha256Bin(data []byte) []byte { + hash := sha256.Sum256(data) + + return hash[:] +} + +func Ripemd160(data []byte) []byte { + ripemd := ripemd160.New() + ripemd.Write(data) + + return ripemd.Sum(nil) +} + +func Sha3Bin(data []byte) []byte { + d := sha3.NewKeccak256() + d.Write(data) + + return d.Sum(nil) +} From 1db3e2241efe2a358b9c28c21fb2cb7c2f1e55a6 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:59:35 +0100 Subject: [PATCH 0514/1237] move ethutil/mnemonic to ethcrypto - electrum word list now sourced from file --- ethcrypto/mnemonic.go | 76 + ethcrypto/mnemonic.words.lst | 1626 ++++++++++++++++++++++ {ethutil => ethcrypto}/mnemonic_test.go | 2 +- ethutil/mnemonic.go | 1690 ----------------------- 4 files changed, 1703 insertions(+), 1691 deletions(-) create mode 100644 ethcrypto/mnemonic.go create mode 100644 ethcrypto/mnemonic.words.lst rename {ethutil => ethcrypto}/mnemonic_test.go (98%) delete mode 100644 ethutil/mnemonic.go diff --git a/ethcrypto/mnemonic.go b/ethcrypto/mnemonic.go new file mode 100644 index 0000000000..6134f85f72 --- /dev/null +++ b/ethcrypto/mnemonic.go @@ -0,0 +1,76 @@ +package ethcrypto + +import ( + "fmt" + "io/ioutil" + "path" + "runtime" + "strconv" + "strings" +) + +func InitWords() []string { + _, thisfile, _, _ := runtime.Caller(1) + filename := path.Join(path.Dir(thisfile), "mnemonic.words.lst") + content, err := ioutil.ReadFile(filename) + if err != nil { + panic(fmt.Errorf("reading mnemonic word list file 'mnemonic.words.lst' failed: ", err)) + } + return strings.Split(string(content), "\n") +} + +var words = InitWords() + +// 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 { + for p, v := range slice { + if v == value { + return int64(p) + } + } + return -1 +} + +func MnemonicEncode(message string) []string { + var out []string + n := int64(len(words)) + + for i := 0; i < len(message); i += (len(message) / 8) { + x := message[i : i+8] + bit, _ := strconv.ParseInt(x, 16, 64) + w1 := (bit % n) + w2 := ((bit / n) + w1) % n + w3 := ((bit / n / n) + w2) % n + out = append(out, words[w1], words[w2], words[w3]) + } + return out +} + +func MnemonicDecode(wordsar []string) string { + var out string + n := int64(len(words)) + + for i := 0; i < len(wordsar); i += 3 { + word1 := wordsar[i] + word2 := wordsar[i+1] + word3 := wordsar[i+2] + w1 := IndexOf(words, word1) + w2 := IndexOf(words, word2) + w3 := IndexOf(words, word3) + + y := (w2 - w1) % n + z := (w3 - w2) % n + + // Golang handles modulo with negative numbers different then most languages + // The modulo can be negative, we don't want that. + if z < 0 { + z += n + } + if y < 0 { + y += n + } + x := w1 + n*(y) + n*n*(z) + out += fmt.Sprintf("%08x", x) + } + return out +} diff --git a/ethcrypto/mnemonic.words.lst b/ethcrypto/mnemonic.words.lst new file mode 100644 index 0000000000..6bf412ce1f --- /dev/null +++ b/ethcrypto/mnemonic.words.lst @@ -0,0 +1,1626 @@ +like +just +love +know +never +want +time +out +there +make +look +eye +down +only +think +heart +back +then +into +about +more +away +still +them +take +thing +even +through +long +always +world +too +friend +tell +try +hand +thought +over +here +other +need +smile +again +much +cry +been +night +ever +little +said +end +some +those +around +mind +people +girl +leave +dream +left +turn +myself +give +nothing +really +off +before +something +find +walk +wish +good +once +place +ask +stop +keep +watch +seem +everything +wait +got +yet +made +remember +start +alone +run +hope +maybe +believe +body +hate +after +close +talk +stand +own +each +hurt +help +home +god +soul +new +many +two +inside +should +true +first +fear +mean +better +play +another +gone +change +use +wonder +someone +hair +cold +open +best +any +behind +happen +water +dark +laugh +stay +forever +name +work +show +sky +break +came +deep +door +put +black +together +upon +happy +such +great +white +matter +fill +past +please +burn +cause +enough +touch +moment +soon +voice +scream +anything +stare +sound +red +everyone +hide +kiss +truth +death +beautiful +mine +blood +broken +very +pass +next +forget +tree +wrong +air +mother +understand +lip +hit +wall +memory +sleep +free +high +realize +school +might +skin +sweet +perfect +blue +kill +breath +dance +against +fly +between +grow +strong +under +listen +bring +sometimes +speak +pull +person +become +family +begin +ground +real +small +father +sure +feet +rest +young +finally +land +across +today +different +guy +line +fire +reason +reach +second +slowly +write +eat +smell +mouth +step +learn +three +floor +promise +breathe +darkness +push +earth +guess +save +song +above +along +both +color +house +almost +sorry +anymore +brother +okay +dear +game +fade +already +apart +warm +beauty +heard +notice +question +shine +began +piece +whole +shadow +secret +street +within +finger +point +morning +whisper +child +moon +green +story +glass +kid +silence +since +soft +yourself +empty +shall +angel +answer +baby +bright +dad +path +worry +hour +drop +follow +power +war +half +flow +heaven +act +chance +fact +least +tired +children +near +quite +afraid +rise +sea +taste +window +cover +nice +trust +lot +sad +cool +force +peace +return +blind +easy +ready +roll +rose +drive +held +music +beneath +hang +mom +paint +emotion +quiet +clear +cloud +few +pretty +bird +outside +paper +picture +front +rock +simple +anyone +meant +reality +road +sense +waste +bit +leaf +thank +happiness +meet +men +smoke +truly +decide +self +age +book +form +alive +carry +escape +damn +instead +able +ice +minute +throw +catch +leg +ring +course +goodbye +lead +poem +sick +corner +desire +known +problem +remind +shoulder +suppose +toward +wave +drink +jump +woman +pretend +sister +week +human +joy +crack +grey +pray +surprise +dry +knee +less +search +bleed +caught +clean +embrace +future +king +son +sorrow +chest +hug +remain +sat +worth +blow +daddy +final +parent +tight +also +create +lonely +safe +cross +dress +evil +silent +bone +fate +perhaps +anger +class +scar +snow +tiny +tonight +continue +control +dog +edge +mirror +month +suddenly +comfort +given +loud +quickly +gaze +plan +rush +stone +town +battle +ignore +spirit +stood +stupid +yours +brown +build +dust +hey +kept +pay +phone +twist +although +ball +beyond +hidden +nose +taken +fail +float +pure +somehow +wash +wrap +angry +cheek +creature +forgotten +heat +rip +single +space +special +weak +whatever +yell +anyway +blame +job +choose +country +curse +drift +echo +figure +grew +laughter +neck +suffer +worse +yeah +disappear +foot +forward +knife +mess +somewhere +stomach +storm +beg +idea +lift +offer +breeze +field +five +often +simply +stuck +win +allow +confuse +enjoy +except +flower +seek +strength +calm +grin +gun +heavy +hill +large +ocean +shoe +sigh +straight +summer +tongue +accept +crazy +everyday +exist +grass +mistake +sent +shut +surround +table +ache +brain +destroy +heal +nature +shout +sign +stain +choice +doubt +glance +glow +mountain +queen +stranger +throat +tomorrow +city +either +fish +flame +rather +shape +spin +spread +ash +distance +finish +image +imagine +important +nobody +shatter +warmth +became +feed +flesh +funny +lust +shirt +trouble +yellow +attention +bare +bite +money +protect +amaze +appear +born +choke +completely +daughter +fresh +friendship +gentle +probably +six +deserve +expect +grab +middle +nightmare +river +thousand +weight +worst +wound +barely +bottle +cream +regret +relationship +stick +test +crush +endless +fault +itself +rule +spill +art +circle +join +kick +mask +master +passion +quick +raise +smooth +unless +wander +actually +broke +chair +deal +favorite +gift +note +number +sweat +box +chill +clothes +lady +mark +park +poor +sadness +tie +animal +belong +brush +consume +dawn +forest +innocent +pen +pride +stream +thick +clay +complete +count +draw +faith +press +silver +struggle +surface +taught +teach +wet +bless +chase +climb +enter +letter +melt +metal +movie +stretch +swing +vision +wife +beside +crash +forgot +guide +haunt +joke +knock +plant +pour +prove +reveal +steal +stuff +trip +wood +wrist +bother +bottom +crawl +crowd +fix +forgive +frown +grace +loose +lucky +party +release +surely +survive +teacher +gently +grip +speed +suicide +travel +treat +vein +written +cage +chain +conversation +date +enemy +however +interest +million +page +pink +proud +sway +themselves +winter +church +cruel +cup +demon +experience +freedom +pair +pop +purpose +respect +shoot +softly +state +strange +bar +birth +curl +dirt +excuse +lord +lovely +monster +order +pack +pants +pool +scene +seven +shame +slide +ugly +among +blade +blonde +closet +creek +deny +drug +eternity +gain +grade +handle +key +linger +pale +prepare +swallow +swim +tremble +wheel +won +cast +cigarette +claim +college +direction +dirty +gather +ghost +hundred +loss +lung +orange +present +swear +swirl +twice +wild +bitter +blanket +doctor +everywhere +flash +grown +knowledge +numb +pressure +radio +repeat +ruin +spend +unknown +buy +clock +devil +early +false +fantasy +pound +precious +refuse +sheet +teeth +welcome +add +ahead +block +bury +caress +content +depth +despite +distant +marry +purple +threw +whenever +bomb +dull +easily +grasp +hospital +innocence +normal +receive +reply +rhyme +shade +someday +sword +toe +visit +asleep +bought +center +consider +flat +hero +history +ink +insane +muscle +mystery +pocket +reflection +shove +silently +smart +soldier +spot +stress +train +type +view +whether +bus +energy +explain +holy +hunger +inch +magic +mix +noise +nowhere +prayer +presence +shock +snap +spider +study +thunder +trail +admit +agree +bag +bang +bound +butterfly +cute +exactly +explode +familiar +fold +further +pierce +reflect +scent +selfish +sharp +sink +spring +stumble +universe +weep +women +wonderful +action +ancient +attempt +avoid +birthday +branch +chocolate +core +depress +drunk +especially +focus +fruit +honest +match +palm +perfectly +pillow +pity +poison +roar +shift +slightly +thump +truck +tune +twenty +unable +wipe +wrote +coat +constant +dinner +drove +egg +eternal +flight +flood +frame +freak +gasp +glad +hollow +motion +peer +plastic +root +screen +season +sting +strike +team +unlike +victim +volume +warn +weird +attack +await +awake +built +charm +crave +despair +fought +grant +grief +horse +limit +message +ripple +sanity +scatter +serve +split +string +trick +annoy +blur +boat +brave +clearly +cling +connect +fist +forth +imagination +iron +jock +judge +lesson +milk +misery +nail +naked +ourselves +poet +possible +princess +sail +size +snake +society +stroke +torture +toss +trace +wise +bloom +bullet +cell +check +cost +darling +during +footstep +fragile +hallway +hardly +horizon +invisible +journey +midnight +mud +nod +pause +relax +shiver +sudden +value +youth +abuse +admire +blink +breast +bruise +constantly +couple +creep +curve +difference +dumb +emptiness +gotta +honor +plain +planet +recall +rub +ship +slam +soar +somebody +tightly +weather +adore +approach +bond +bread +burst +candle +coffee +cousin +crime +desert +flutter +frozen +grand +heel +hello +language +level +movement +pleasure +powerful +random +rhythm +settle +silly +slap +sort +spoken +steel +threaten +tumble +upset +aside +awkward +bee +blank +board +button +card +carefully +complain +crap +deeply +discover +drag +dread +effort +entire +fairy +giant +gotten +greet +illusion +jeans +leap +liquid +march +mend +nervous +nine +replace +rope +spine +stole +terror +accident +apple +balance +boom +childhood +collect +demand +depression +eventually +faint +glare +goal +group +honey +kitchen +laid +limb +machine +mere +mold +murder +nerve +painful +poetry +prince +rabbit +shelter +shore +shower +soothe +stair +steady +sunlight +tangle +tease +treasure +uncle +begun +bliss +canvas +cheer +claw +clutch +commit +crimson +crystal +delight +doll +existence +express +fog +football +gay +goose +guard +hatred +illuminate +mass +math +mourn +rich +rough +skip +stir +student +style +support +thorn +tough +yard +yearn +yesterday +advice +appreciate +autumn +bank +beam +bowl +capture +carve +collapse +confusion +creation +dove +feather +girlfriend +glory +government +harsh +hop +inner +loser +moonlight +neighbor +neither +peach +pig +praise +screw +shield +shimmer +sneak +stab +subject +throughout +thrown +tower +twirl +wow +army +arrive +bathroom +bump +cease +cookie +couch +courage +dim +guilt +howl +hum +husband +insult +led +lunch +mock +mostly +natural +nearly +needle +nerd +peaceful +perfection +pile +price +remove +roam +sanctuary +serious +shiny +shook +sob +stolen +tap +vain +void +warrior +wrinkle +affection +apologize +blossom +bounce +bridge +cheap +crumble +decision +descend +desperately +dig +dot +flip +frighten +heartbeat +huge +lazy +lick +odd +opinion +process +puzzle +quietly +retreat +score +sentence +separate +situation +skill +soak +square +stray +taint +task +tide +underneath +veil +whistle +anywhere +bedroom +bid +bloody +burden +careful +compare +concern +curtain +decay +defeat +describe +double +dreamer +driver +dwell +evening +flare +flicker +grandma +guitar +harm +horrible +hungry +indeed +lace +melody +monkey +nation +object +obviously +rainbow +salt +scratch +shown +shy +stage +stun +third +tickle +useless +weakness +worship +worthless +afternoon +beard +boyfriend +bubble +busy +certain +chin +concrete +desk +diamond +doom +drawn +due +felicity +freeze +frost +garden +glide +harmony +hopefully +hunt +jealous +lightning +mama +mercy +peel +physical +position +pulse +punch +quit +rant +respond +salty +sane +satisfy +savior +sheep +slept +social +sport +tuck +utter +valley +wolf +aim +alas +alter +arrow +awaken +beaten +belief +brand +ceiling +cheese +clue +confidence +connection +daily +disguise +eager +erase +essence +everytime +expression +fan +flag +flirt +foul +fur +giggle +glorious +ignorance +law +lifeless +measure +mighty +muse +north +opposite +paradise +patience +patient +pencil +petal +plate +ponder +possibly +practice +slice +spell +stock +strife +strip +suffocate +suit +tender +tool +trade +velvet +verse +waist +witch +aunt +bench +bold +cap +certainly +click +companion +creator +dart +delicate +determine +dish +dragon +drama +drum +dude +everybody +feast +forehead +former +fright +fully +gas +hook +hurl +invite +juice +manage +moral +possess +raw +rebel +royal +scale +scary +several +slight +stubborn +swell +talent +tea +terrible +thread +torment +trickle +usually +vast +violence +weave +acid +agony +ashamed +awe +belly +blend +blush +character +cheat +common +company +coward +creak +danger +deadly +defense +define +depend +desperate +destination +dew +duck +dusty +embarrass +engine +example +explore +foe +freely +frustrate +generation +glove +guilty +health +hurry +idiot +impossible +inhale +jaw +kingdom +mention +mist +moan +mumble +mutter +observe +ode +pathetic +pattern +pie +prefer +puff +rape +rare +revenge +rude +scrape +spiral +squeeze +strain +sunset +suspend +sympathy +thigh +throne +total +unseen +weapon +weary \ No newline at end of file diff --git a/ethutil/mnemonic_test.go b/ethcrypto/mnemonic_test.go similarity index 98% rename from ethutil/mnemonic_test.go rename to ethcrypto/mnemonic_test.go index ccf3f98831..8bd8859ae3 100644 --- a/ethutil/mnemonic_test.go +++ b/ethcrypto/mnemonic_test.go @@ -1,4 +1,4 @@ -package ethutil +package ethcrypto import ( "testing" diff --git a/ethutil/mnemonic.go b/ethutil/mnemonic.go deleted file mode 100644 index 00f089e3bf..0000000000 --- a/ethutil/mnemonic.go +++ /dev/null @@ -1,1690 +0,0 @@ -package ethutil - -import ( - "fmt" - "strconv" -) - -// 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 { - for p, v := range slice { - if v == value { - return int64(p) - } - } - return -1 -} - -func MnemonicEncode(message string) []string { - var out []string - n := int64(len(words)) - - for i := 0; i < len(message); i += (len(message) / 8) { - x := message[i : i+8] - bit, _ := strconv.ParseInt(x, 16, 64) - w1 := (bit % n) - w2 := ((bit / n) + w1) % n - w3 := ((bit / n / n) + w2) % n - out = append(out, words[w1], words[w2], words[w3]) - } - return out -} - -func MnemonicDecode(wordsar []string) string { - var out string - n := int64(len(words)) - - for i := 0; i < len(wordsar); i += 3 { - word1 := wordsar[i] - word2 := wordsar[i+1] - word3 := wordsar[i+2] - w1 := IndexOf(words, word1) - w2 := IndexOf(words, word2) - w3 := IndexOf(words, word3) - - y := (w2 - w1) % n - z := (w3 - w2) % n - - // Golang handles modulo with negative numbers different then most languages - // The modulo can be negative, we don't want that. - if z < 0 { - z += n - } - if y < 0 { - y += n - } - x := w1 + n*(y) + n*n*(z) - out += fmt.Sprintf("%08x", x) - } - return out -} - -// Electrum word list -var words []string = []string{ - "like", - "just", - "love", - "know", - "never", - "want", - "time", - "out", - "there", - "make", - "look", - "eye", - "down", - "only", - "think", - "heart", - "back", - "then", - "into", - "about", - "more", - "away", - "still", - "them", - "take", - "thing", - "even", - "through", - "long", - "always", - "world", - "too", - "friend", - "tell", - "try", - "hand", - "thought", - "over", - "here", - "other", - "need", - "smile", - "again", - "much", - "cry", - "been", - "night", - "ever", - "little", - "said", - "end", - "some", - "those", - "around", - "mind", - "people", - "girl", - "leave", - "dream", - "left", - "turn", - "myself", - "give", - "nothing", - "really", - "off", - "before", - "something", - "find", - "walk", - "wish", - "good", - "once", - "place", - "ask", - "stop", - "keep", - "watch", - "seem", - "everything", - "wait", - "got", - "yet", - "made", - "remember", - "start", - "alone", - "run", - "hope", - "maybe", - "believe", - "body", - "hate", - "after", - "close", - "talk", - "stand", - "own", - "each", - "hurt", - "help", - "home", - "god", - "soul", - "new", - "many", - "two", - "inside", - "should", - "true", - "first", - "fear", - "mean", - "better", - "play", - "another", - "gone", - "change", - "use", - "wonder", - "someone", - "hair", - "cold", - "open", - "best", - "any", - "behind", - "happen", - "water", - "dark", - "laugh", - "stay", - "forever", - "name", - "work", - "show", - "sky", - "break", - "came", - "deep", - "door", - "put", - "black", - "together", - "upon", - "happy", - "such", - "great", - "white", - "matter", - "fill", - "past", - "please", - "burn", - "cause", - "enough", - "touch", - "moment", - "soon", - "voice", - "scream", - "anything", - "stare", - "sound", - "red", - "everyone", - "hide", - "kiss", - "truth", - "death", - "beautiful", - "mine", - "blood", - "broken", - "very", - "pass", - "next", - "forget", - "tree", - "wrong", - "air", - "mother", - "understand", - "lip", - "hit", - "wall", - "memory", - "sleep", - "free", - "high", - "realize", - "school", - "might", - "skin", - "sweet", - "perfect", - "blue", - "kill", - "breath", - "dance", - "against", - "fly", - "between", - "grow", - "strong", - "under", - "listen", - "bring", - "sometimes", - "speak", - "pull", - "person", - "become", - "family", - "begin", - "ground", - "real", - "small", - "father", - "sure", - "feet", - "rest", - "young", - "finally", - "land", - "across", - "today", - "different", - "guy", - "line", - "fire", - "reason", - "reach", - "second", - "slowly", - "write", - "eat", - "smell", - "mouth", - "step", - "learn", - "three", - "floor", - "promise", - "breathe", - "darkness", - "push", - "earth", - "guess", - "save", - "song", - "above", - "along", - "both", - "color", - "house", - "almost", - "sorry", - "anymore", - "brother", - "okay", - "dear", - "game", - "fade", - "already", - "apart", - "warm", - "beauty", - "heard", - "notice", - "question", - "shine", - "began", - "piece", - "whole", - "shadow", - "secret", - "street", - "within", - "finger", - "point", - "morning", - "whisper", - "child", - "moon", - "green", - "story", - "glass", - "kid", - "silence", - "since", - "soft", - "yourself", - "empty", - "shall", - "angel", - "answer", - "baby", - "bright", - "dad", - "path", - "worry", - "hour", - "drop", - "follow", - "power", - "war", - "half", - "flow", - "heaven", - "act", - "chance", - "fact", - "least", - "tired", - "children", - "near", - "quite", - "afraid", - "rise", - "sea", - "taste", - "window", - "cover", - "nice", - "trust", - "lot", - "sad", - "cool", - "force", - "peace", - "return", - "blind", - "easy", - "ready", - "roll", - "rose", - "drive", - "held", - "music", - "beneath", - "hang", - "mom", - "paint", - "emotion", - "quiet", - "clear", - "cloud", - "few", - "pretty", - "bird", - "outside", - "paper", - "picture", - "front", - "rock", - "simple", - "anyone", - "meant", - "reality", - "road", - "sense", - "waste", - "bit", - "leaf", - "thank", - "happiness", - "meet", - "men", - "smoke", - "truly", - "decide", - "self", - "age", - "book", - "form", - "alive", - "carry", - "escape", - "damn", - "instead", - "able", - "ice", - "minute", - "throw", - "catch", - "leg", - "ring", - "course", - "goodbye", - "lead", - "poem", - "sick", - "corner", - "desire", - "known", - "problem", - "remind", - "shoulder", - "suppose", - "toward", - "wave", - "drink", - "jump", - "woman", - "pretend", - "sister", - "week", - "human", - "joy", - "crack", - "grey", - "pray", - "surprise", - "dry", - "knee", - "less", - "search", - "bleed", - "caught", - "clean", - "embrace", - "future", - "king", - "son", - "sorrow", - "chest", - "hug", - "remain", - "sat", - "worth", - "blow", - "daddy", - "final", - "parent", - "tight", - "also", - "create", - "lonely", - "safe", - "cross", - "dress", - "evil", - "silent", - "bone", - "fate", - "perhaps", - "anger", - "class", - "scar", - "snow", - "tiny", - "tonight", - "continue", - "control", - "dog", - "edge", - "mirror", - "month", - "suddenly", - "comfort", - "given", - "loud", - "quickly", - "gaze", - "plan", - "rush", - "stone", - "town", - "battle", - "ignore", - "spirit", - "stood", - "stupid", - "yours", - "brown", - "build", - "dust", - "hey", - "kept", - "pay", - "phone", - "twist", - "although", - "ball", - "beyond", - "hidden", - "nose", - "taken", - "fail", - "float", - "pure", - "somehow", - "wash", - "wrap", - "angry", - "cheek", - "creature", - "forgotten", - "heat", - "rip", - "single", - "space", - "special", - "weak", - "whatever", - "yell", - "anyway", - "blame", - "job", - "choose", - "country", - "curse", - "drift", - "echo", - "figure", - "grew", - "laughter", - "neck", - "suffer", - "worse", - "yeah", - "disappear", - "foot", - "forward", - "knife", - "mess", - "somewhere", - "stomach", - "storm", - "beg", - "idea", - "lift", - "offer", - "breeze", - "field", - "five", - "often", - "simply", - "stuck", - "win", - "allow", - "confuse", - "enjoy", - "except", - "flower", - "seek", - "strength", - "calm", - "grin", - "gun", - "heavy", - "hill", - "large", - "ocean", - "shoe", - "sigh", - "straight", - "summer", - "tongue", - "accept", - "crazy", - "everyday", - "exist", - "grass", - "mistake", - "sent", - "shut", - "surround", - "table", - "ache", - "brain", - "destroy", - "heal", - "nature", - "shout", - "sign", - "stain", - "choice", - "doubt", - "glance", - "glow", - "mountain", - "queen", - "stranger", - "throat", - "tomorrow", - "city", - "either", - "fish", - "flame", - "rather", - "shape", - "spin", - "spread", - "ash", - "distance", - "finish", - "image", - "imagine", - "important", - "nobody", - "shatter", - "warmth", - "became", - "feed", - "flesh", - "funny", - "lust", - "shirt", - "trouble", - "yellow", - "attention", - "bare", - "bite", - "money", - "protect", - "amaze", - "appear", - "born", - "choke", - "completely", - "daughter", - "fresh", - "friendship", - "gentle", - "probably", - "six", - "deserve", - "expect", - "grab", - "middle", - "nightmare", - "river", - "thousand", - "weight", - "worst", - "wound", - "barely", - "bottle", - "cream", - "regret", - "relationship", - "stick", - "test", - "crush", - "endless", - "fault", - "itself", - "rule", - "spill", - "art", - "circle", - "join", - "kick", - "mask", - "master", - "passion", - "quick", - "raise", - "smooth", - "unless", - "wander", - "actually", - "broke", - "chair", - "deal", - "favorite", - "gift", - "note", - "number", - "sweat", - "box", - "chill", - "clothes", - "lady", - "mark", - "park", - "poor", - "sadness", - "tie", - "animal", - "belong", - "brush", - "consume", - "dawn", - "forest", - "innocent", - "pen", - "pride", - "stream", - "thick", - "clay", - "complete", - "count", - "draw", - "faith", - "press", - "silver", - "struggle", - "surface", - "taught", - "teach", - "wet", - "bless", - "chase", - "climb", - "enter", - "letter", - "melt", - "metal", - "movie", - "stretch", - "swing", - "vision", - "wife", - "beside", - "crash", - "forgot", - "guide", - "haunt", - "joke", - "knock", - "plant", - "pour", - "prove", - "reveal", - "steal", - "stuff", - "trip", - "wood", - "wrist", - "bother", - "bottom", - "crawl", - "crowd", - "fix", - "forgive", - "frown", - "grace", - "loose", - "lucky", - "party", - "release", - "surely", - "survive", - "teacher", - "gently", - "grip", - "speed", - "suicide", - "travel", - "treat", - "vein", - "written", - "cage", - "chain", - "conversation", - "date", - "enemy", - "however", - "interest", - "million", - "page", - "pink", - "proud", - "sway", - "themselves", - "winter", - "church", - "cruel", - "cup", - "demon", - "experience", - "freedom", - "pair", - "pop", - "purpose", - "respect", - "shoot", - "softly", - "state", - "strange", - "bar", - "birth", - "curl", - "dirt", - "excuse", - "lord", - "lovely", - "monster", - "order", - "pack", - "pants", - "pool", - "scene", - "seven", - "shame", - "slide", - "ugly", - "among", - "blade", - "blonde", - "closet", - "creek", - "deny", - "drug", - "eternity", - "gain", - "grade", - "handle", - "key", - "linger", - "pale", - "prepare", - "swallow", - "swim", - "tremble", - "wheel", - "won", - "cast", - "cigarette", - "claim", - "college", - "direction", - "dirty", - "gather", - "ghost", - "hundred", - "loss", - "lung", - "orange", - "present", - "swear", - "swirl", - "twice", - "wild", - "bitter", - "blanket", - "doctor", - "everywhere", - "flash", - "grown", - "knowledge", - "numb", - "pressure", - "radio", - "repeat", - "ruin", - "spend", - "unknown", - "buy", - "clock", - "devil", - "early", - "false", - "fantasy", - "pound", - "precious", - "refuse", - "sheet", - "teeth", - "welcome", - "add", - "ahead", - "block", - "bury", - "caress", - "content", - "depth", - "despite", - "distant", - "marry", - "purple", - "threw", - "whenever", - "bomb", - "dull", - "easily", - "grasp", - "hospital", - "innocence", - "normal", - "receive", - "reply", - "rhyme", - "shade", - "someday", - "sword", - "toe", - "visit", - "asleep", - "bought", - "center", - "consider", - "flat", - "hero", - "history", - "ink", - "insane", - "muscle", - "mystery", - "pocket", - "reflection", - "shove", - "silently", - "smart", - "soldier", - "spot", - "stress", - "train", - "type", - "view", - "whether", - "bus", - "energy", - "explain", - "holy", - "hunger", - "inch", - "magic", - "mix", - "noise", - "nowhere", - "prayer", - "presence", - "shock", - "snap", - "spider", - "study", - "thunder", - "trail", - "admit", - "agree", - "bag", - "bang", - "bound", - "butterfly", - "cute", - "exactly", - "explode", - "familiar", - "fold", - "further", - "pierce", - "reflect", - "scent", - "selfish", - "sharp", - "sink", - "spring", - "stumble", - "universe", - "weep", - "women", - "wonderful", - "action", - "ancient", - "attempt", - "avoid", - "birthday", - "branch", - "chocolate", - "core", - "depress", - "drunk", - "especially", - "focus", - "fruit", - "honest", - "match", - "palm", - "perfectly", - "pillow", - "pity", - "poison", - "roar", - "shift", - "slightly", - "thump", - "truck", - "tune", - "twenty", - "unable", - "wipe", - "wrote", - "coat", - "constant", - "dinner", - "drove", - "egg", - "eternal", - "flight", - "flood", - "frame", - "freak", - "gasp", - "glad", - "hollow", - "motion", - "peer", - "plastic", - "root", - "screen", - "season", - "sting", - "strike", - "team", - "unlike", - "victim", - "volume", - "warn", - "weird", - "attack", - "await", - "awake", - "built", - "charm", - "crave", - "despair", - "fought", - "grant", - "grief", - "horse", - "limit", - "message", - "ripple", - "sanity", - "scatter", - "serve", - "split", - "string", - "trick", - "annoy", - "blur", - "boat", - "brave", - "clearly", - "cling", - "connect", - "fist", - "forth", - "imagination", - "iron", - "jock", - "judge", - "lesson", - "milk", - "misery", - "nail", - "naked", - "ourselves", - "poet", - "possible", - "princess", - "sail", - "size", - "snake", - "society", - "stroke", - "torture", - "toss", - "trace", - "wise", - "bloom", - "bullet", - "cell", - "check", - "cost", - "darling", - "during", - "footstep", - "fragile", - "hallway", - "hardly", - "horizon", - "invisible", - "journey", - "midnight", - "mud", - "nod", - "pause", - "relax", - "shiver", - "sudden", - "value", - "youth", - "abuse", - "admire", - "blink", - "breast", - "bruise", - "constantly", - "couple", - "creep", - "curve", - "difference", - "dumb", - "emptiness", - "gotta", - "honor", - "plain", - "planet", - "recall", - "rub", - "ship", - "slam", - "soar", - "somebody", - "tightly", - "weather", - "adore", - "approach", - "bond", - "bread", - "burst", - "candle", - "coffee", - "cousin", - "crime", - "desert", - "flutter", - "frozen", - "grand", - "heel", - "hello", - "language", - "level", - "movement", - "pleasure", - "powerful", - "random", - "rhythm", - "settle", - "silly", - "slap", - "sort", - "spoken", - "steel", - "threaten", - "tumble", - "upset", - "aside", - "awkward", - "bee", - "blank", - "board", - "button", - "card", - "carefully", - "complain", - "crap", - "deeply", - "discover", - "drag", - "dread", - "effort", - "entire", - "fairy", - "giant", - "gotten", - "greet", - "illusion", - "jeans", - "leap", - "liquid", - "march", - "mend", - "nervous", - "nine", - "replace", - "rope", - "spine", - "stole", - "terror", - "accident", - "apple", - "balance", - "boom", - "childhood", - "collect", - "demand", - "depression", - "eventually", - "faint", - "glare", - "goal", - "group", - "honey", - "kitchen", - "laid", - "limb", - "machine", - "mere", - "mold", - "murder", - "nerve", - "painful", - "poetry", - "prince", - "rabbit", - "shelter", - "shore", - "shower", - "soothe", - "stair", - "steady", - "sunlight", - "tangle", - "tease", - "treasure", - "uncle", - "begun", - "bliss", - "canvas", - "cheer", - "claw", - "clutch", - "commit", - "crimson", - "crystal", - "delight", - "doll", - "existence", - "express", - "fog", - "football", - "gay", - "goose", - "guard", - "hatred", - "illuminate", - "mass", - "math", - "mourn", - "rich", - "rough", - "skip", - "stir", - "student", - "style", - "support", - "thorn", - "tough", - "yard", - "yearn", - "yesterday", - "advice", - "appreciate", - "autumn", - "bank", - "beam", - "bowl", - "capture", - "carve", - "collapse", - "confusion", - "creation", - "dove", - "feather", - "girlfriend", - "glory", - "government", - "harsh", - "hop", - "inner", - "loser", - "moonlight", - "neighbor", - "neither", - "peach", - "pig", - "praise", - "screw", - "shield", - "shimmer", - "sneak", - "stab", - "subject", - "throughout", - "thrown", - "tower", - "twirl", - "wow", - "army", - "arrive", - "bathroom", - "bump", - "cease", - "cookie", - "couch", - "courage", - "dim", - "guilt", - "howl", - "hum", - "husband", - "insult", - "led", - "lunch", - "mock", - "mostly", - "natural", - "nearly", - "needle", - "nerd", - "peaceful", - "perfection", - "pile", - "price", - "remove", - "roam", - "sanctuary", - "serious", - "shiny", - "shook", - "sob", - "stolen", - "tap", - "vain", - "void", - "warrior", - "wrinkle", - "affection", - "apologize", - "blossom", - "bounce", - "bridge", - "cheap", - "crumble", - "decision", - "descend", - "desperately", - "dig", - "dot", - "flip", - "frighten", - "heartbeat", - "huge", - "lazy", - "lick", - "odd", - "opinion", - "process", - "puzzle", - "quietly", - "retreat", - "score", - "sentence", - "separate", - "situation", - "skill", - "soak", - "square", - "stray", - "taint", - "task", - "tide", - "underneath", - "veil", - "whistle", - "anywhere", - "bedroom", - "bid", - "bloody", - "burden", - "careful", - "compare", - "concern", - "curtain", - "decay", - "defeat", - "describe", - "double", - "dreamer", - "driver", - "dwell", - "evening", - "flare", - "flicker", - "grandma", - "guitar", - "harm", - "horrible", - "hungry", - "indeed", - "lace", - "melody", - "monkey", - "nation", - "object", - "obviously", - "rainbow", - "salt", - "scratch", - "shown", - "shy", - "stage", - "stun", - "third", - "tickle", - "useless", - "weakness", - "worship", - "worthless", - "afternoon", - "beard", - "boyfriend", - "bubble", - "busy", - "certain", - "chin", - "concrete", - "desk", - "diamond", - "doom", - "drawn", - "due", - "felicity", - "freeze", - "frost", - "garden", - "glide", - "harmony", - "hopefully", - "hunt", - "jealous", - "lightning", - "mama", - "mercy", - "peel", - "physical", - "position", - "pulse", - "punch", - "quit", - "rant", - "respond", - "salty", - "sane", - "satisfy", - "savior", - "sheep", - "slept", - "social", - "sport", - "tuck", - "utter", - "valley", - "wolf", - "aim", - "alas", - "alter", - "arrow", - "awaken", - "beaten", - "belief", - "brand", - "ceiling", - "cheese", - "clue", - "confidence", - "connection", - "daily", - "disguise", - "eager", - "erase", - "essence", - "everytime", - "expression", - "fan", - "flag", - "flirt", - "foul", - "fur", - "giggle", - "glorious", - "ignorance", - "law", - "lifeless", - "measure", - "mighty", - "muse", - "north", - "opposite", - "paradise", - "patience", - "patient", - "pencil", - "petal", - "plate", - "ponder", - "possibly", - "practice", - "slice", - "spell", - "stock", - "strife", - "strip", - "suffocate", - "suit", - "tender", - "tool", - "trade", - "velvet", - "verse", - "waist", - "witch", - "aunt", - "bench", - "bold", - "cap", - "certainly", - "click", - "companion", - "creator", - "dart", - "delicate", - "determine", - "dish", - "dragon", - "drama", - "drum", - "dude", - "everybody", - "feast", - "forehead", - "former", - "fright", - "fully", - "gas", - "hook", - "hurl", - "invite", - "juice", - "manage", - "moral", - "possess", - "raw", - "rebel", - "royal", - "scale", - "scary", - "several", - "slight", - "stubborn", - "swell", - "talent", - "tea", - "terrible", - "thread", - "torment", - "trickle", - "usually", - "vast", - "violence", - "weave", - "acid", - "agony", - "ashamed", - "awe", - "belly", - "blend", - "blush", - "character", - "cheat", - "common", - "company", - "coward", - "creak", - "danger", - "deadly", - "defense", - "define", - "depend", - "desperate", - "destination", - "dew", - "duck", - "dusty", - "embarrass", - "engine", - "example", - "explore", - "foe", - "freely", - "frustrate", - "generation", - "glove", - "guilty", - "health", - "hurry", - "idiot", - "impossible", - "inhale", - "jaw", - "kingdom", - "mention", - "mist", - "moan", - "mumble", - "mutter", - "observe", - "ode", - "pathetic", - "pattern", - "pie", - "prefer", - "puff", - "rape", - "rare", - "revenge", - "rude", - "scrape", - "spiral", - "squeeze", - "strain", - "sunset", - "suspend", - "sympathy", - "thigh", - "throne", - "total", - "unseen", - "weapon", - "weary", -} From d87857ffdb822d0c510bcff385f7ef0328edb2ca Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 15:59:57 +0100 Subject: [PATCH 0515/1237] config Pubkey removed (unused) --- ethutil/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ethutil/config.go b/ethutil/config.go index b253aa203a..8a005670f8 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -16,7 +16,6 @@ type config struct { Debug bool Ver string ClientString string - Pubkey []byte Identifier string conf *globalconf.GlobalConf From e1ea41ee9cbe387221874fa6732b11d262a4ff12 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:01:57 +0100 Subject: [PATCH 0516/1237] remove ethutil helpers (refactored), and keypair (key management under ethcrypto package) --- ethutil/helpers.go | 64 ------------------------- ethutil/keypair.go | 115 --------------------------------------------- 2 files changed, 179 deletions(-) delete mode 100644 ethutil/helpers.go delete mode 100644 ethutil/keypair.go diff --git a/ethutil/helpers.go b/ethutil/helpers.go deleted file mode 100644 index aa0f79a044..0000000000 --- a/ethutil/helpers.go +++ /dev/null @@ -1,64 +0,0 @@ -package ethutil - -import ( - "code.google.com/p/go.crypto/ripemd160" - "crypto/sha256" - "encoding/hex" - "github.com/obscuren/sha3" - "strconv" -) - -func Uitoa(i uint32) string { - return strconv.FormatUint(uint64(i), 10) -} - -func Sha256Bin(data []byte) []byte { - hash := sha256.Sum256(data) - - return hash[:] -} - -func Ripemd160(data []byte) []byte { - ripemd := ripemd160.New() - ripemd.Write(data) - - return ripemd.Sum(nil) -} - -func Sha3Bin(data []byte) []byte { - d := sha3.NewKeccak256() - d.Write(data) - - return d.Sum(nil) -} - -// Helper function for comparing slices -func CompareIntSlice(a, b []int) bool { - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} - -// Returns the amount of nibbles that match each other from 0 ... -func MatchingNibbleLength(a, b []int) int { - i := 0 - for CompareIntSlice(a[:i+1], b[:i+1]) && i < len(b) { - i += 1 - } - - return i -} - -func Hex(d []byte) string { - return hex.EncodeToString(d) -} -func FromHex(str string) []byte { - h, _ := hex.DecodeString(str) - return h -} diff --git a/ethutil/keypair.go b/ethutil/keypair.go deleted file mode 100644 index 29fb1bac5b..0000000000 --- a/ethutil/keypair.go +++ /dev/null @@ -1,115 +0,0 @@ -package ethutil - -import ( - "github.com/obscuren/secp256k1-go" -) - -type KeyPair struct { - PrivateKey []byte - PublicKey []byte - - // The associated account - account *StateObject -} - -func GenerateNewKeyPair() (*KeyPair, error) { - _, prv := secp256k1.GenerateKeyPair() - - return NewKeyPairFromSec(prv) -} - -func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { - pubkey, err := secp256k1.GeneratePubKey(seckey) - if err != nil { - return nil, err - } - - return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil -} - -func NewKeyPairFromValue(val *Value) *KeyPair { - v, _ := NewKeyPairFromSec(val.Bytes()) - - return v -} - -func (k *KeyPair) Address() []byte { - return Sha3Bin(k.PublicKey[1:])[12:] -} - -func (k *KeyPair) RlpEncode() []byte { - return k.RlpValue().Encode() -} - -func (k *KeyPair) RlpValue() *Value { - return NewValue(k.PrivateKey) -} - -type KeyRing struct { - keys []*KeyPair -} - -func (k *KeyRing) Add(pair *KeyPair) { - k.keys = append(k.keys, pair) -} - -func (k *KeyRing) Get(i int) *KeyPair { - if len(k.keys) > i { - return k.keys[i] - } - - return nil -} - -func (k *KeyRing) Len() int { - return len(k.keys) -} - -func (k *KeyRing) NewKeyPair(sec []byte) (*KeyPair, error) { - keyPair, err := NewKeyPairFromSec(sec) - if err != nil { - return nil, err - } - - k.Add(keyPair) - Config.Db.Put([]byte("KeyRing"), k.RlpValue().Encode()) - - return keyPair, nil -} - -func (k *KeyRing) Reset() { - Config.Db.Put([]byte("KeyRing"), nil) - k.keys = nil -} - -func (k *KeyRing) RlpValue() *Value { - v := EmptyValue() - for _, keyPair := range k.keys { - v.Append(keyPair.RlpValue()) - } - - return v -} - -// The public "singleton" keyring -var keyRing *KeyRing - -func GetKeyRing() *KeyRing { - if keyRing == nil { - keyRing = &KeyRing{} - - data, _ := Config.Db.Get([]byte("KeyRing")) - it := NewValueFromBytes(data).NewIterator() - for it.Next() { - v := it.Value() - - key, err := NewKeyPairFromSec(v.Bytes()) - if err != nil { - panic(err) - } - keyRing.Add(key) - } - } - - return keyRing -} From 772e7e8c8df066a64726b23bde84b6025c5af318 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:02:23 +0100 Subject: [PATCH 0517/1237] Key Manager - keypair, keyring: -- consistent naming of methods -- error propagation -- no panic - keyManager: persist, import, export, initialize and (re)set keyring - no global public "singleton" keyring, instead interface via keyManager - keys test - KeyStore interface, DB and File store implementations --- ethcrypto/key_manager.go | 121 ++++++++++++++++++++++++++++++++++++++ ethcrypto/key_store.go | 112 +++++++++++++++++++++++++++++++++++ ethcrypto/keypair.go | 41 +++++++++++++ ethcrypto/keyring.go | 118 +++++++++++++++++++++++++++++++++++++ ethcrypto/keys_test.go | 122 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 514 insertions(+) create mode 100644 ethcrypto/key_manager.go create mode 100644 ethcrypto/key_store.go create mode 100644 ethcrypto/keypair.go create mode 100644 ethcrypto/keyring.go create mode 100644 ethcrypto/keys_test.go diff --git a/ethcrypto/key_manager.go b/ethcrypto/key_manager.go new file mode 100644 index 0000000000..dcbc7b77e2 --- /dev/null +++ b/ethcrypto/key_manager.go @@ -0,0 +1,121 @@ +package ethcrypto + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "sync" +) + +type KeyManager struct { + keyRing *KeyRing + session string + keyStore KeyStore // interface + keyRings map[string]*KeyRing // cache + keyPair *KeyPair +} + +func NewDBKeyManager(db ethutil.Database) *KeyManager { + return &KeyManager{keyStore: &DBKeyStore{db: db}, keyRings: make(map[string]*KeyRing)} +} + +func NewFileKeyManager(basedir string) *KeyManager { + return &KeyManager{keyStore: &FileKeyStore{basedir: basedir}, keyRings: make(map[string]*KeyRing)} +} + +func (k *KeyManager) KeyPair() *KeyPair { + return k.keyPair +} + +func (k *KeyManager) KeyRing() *KeyPair { + return k.keyPair +} + +func (k *KeyManager) PrivateKey() []byte { + return k.keyPair.PrivateKey +} + +func (k *KeyManager) PublicKey() []byte { + return k.keyPair.PublicKey +} + +func (k *KeyManager) Address() []byte { + return k.keyPair.Address() +} + +func (k *KeyManager) save(session string, keyRing *KeyRing) error { + err := k.keyStore.Save(session, keyRing) + if err != nil { + return err + } + k.keyRings[session] = keyRing + return nil +} + +func (k *KeyManager) load(session string) (*KeyRing, error) { + keyRing, found := k.keyRings[session] + if !found { + var err error + keyRing, err = k.keyStore.Load(session) + if err != nil { + return nil, err + } + } + return keyRing, nil +} + +func cursorError(cursor int, len int) error { + return fmt.Errorf("cursor %d out of range (0..%d)", cursor, len) +} + +func (k *KeyManager) reset(session string, cursor int, keyRing *KeyRing) error { + if cursor >= keyRing.Len() { + return cursorError(cursor, keyRing.Len()) + } + lock := &sync.Mutex{} + lock.Lock() + defer lock.Unlock() + err := k.save(session, keyRing) + if err != nil { + return err + } + k.session = session + k.keyRing = keyRing + k.keyPair = keyRing.GetKeyPair(cursor) + return nil +} + +func (k *KeyManager) SetCursor(cursor int) error { + if cursor >= k.keyRing.Len() { + return cursorError(cursor, k.keyRing.Len()) + } + k.keyPair = k.keyRing.GetKeyPair(cursor) + return nil +} + +func (k *KeyManager) Init(session string, cursor int, force bool) error { + var keyRing *KeyRing + if !force { + var err error + keyRing, err = k.load(session) + if err != nil { + return err + } + } + if keyRing == nil { + keyRing = NewGeneratedKeyRing(1) + } + return k.reset(session, cursor, keyRing) +} + +func (k *KeyManager) InitFromSecretsFile(session string, cursor int, secretsfile string) error { + keyRing, err := NewKeyRingFromFile(secretsfile) + if err != nil { + return err + } + return k.reset(session, cursor, keyRing) +} + +func (k *KeyManager) Export(dir string) error { + fileKeyStore := FileKeyStore{dir} + return fileKeyStore.Save(k.session, k.keyRing) +} diff --git a/ethcrypto/key_store.go b/ethcrypto/key_store.go new file mode 100644 index 0000000000..c8c506fda7 --- /dev/null +++ b/ethcrypto/key_store.go @@ -0,0 +1,112 @@ +package ethcrypto + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "io/ioutil" + "os" + "path" + "strings" +) + +type KeyStore interface { + Load(string) (*KeyRing, error) + Save(string, *KeyRing) error +} + +type DBKeyStore struct { + db ethutil.Database +} + +const dbKeyPrefix = "KeyRing" + +func (k *DBKeyStore) dbKey(session string) []byte { + return []byte(fmt.Sprintf("%s%s", dbKeyPrefix, session)) +} + +func (k *DBKeyStore) Save(session string, keyRing *KeyRing) error { + k.db.Put(k.dbKey(session), keyRing.RlpEncode()) + return nil +} + +func (k *DBKeyStore) Load(session string) (*KeyRing, error) { + data, err := k.db.Get(k.dbKey(session)) + if err != nil { + return nil, err + } + var keyRing *KeyRing + keyRing, err = NewKeyRingFromBytes(data) + if err != nil { + return nil, err + } + // if empty keyRing is found we return nil, no error + if keyRing.Len() == 0 { + return nil, nil + } + return keyRing, nil +} + +type FileKeyStore struct { + basedir string +} + +func (k *FileKeyStore) Save(session string, keyRing *KeyRing) error { + var content []byte + var err error + var privateKeys []string + var publicKeys []string + var mnemonics []string + var addresses []string + keyRing.Each(func(keyPair *KeyPair) { + privateKeys = append(privateKeys, ethutil.Bytes2Hex(keyPair.PrivateKey)) + publicKeys = append(publicKeys, ethutil.Bytes2Hex(keyPair.PublicKey)) + addresses = append(addresses, ethutil.Bytes2Hex(keyPair.Address())) + mnemonics = append(mnemonics, strings.Join(MnemonicEncode(ethutil.Bytes2Hex(keyPair.PrivateKey)), " ")) + }) + + basename := session + if session == "" { + basename = "default" + } + + path := path.Join(k.basedir, basename) + content = []byte(strings.Join(privateKeys, "\n")) + err = ioutil.WriteFile(path+".prv", content, 0600) + if err != nil { + return err + } + + content = []byte(strings.Join(publicKeys, "\n")) + err = ioutil.WriteFile(path+".pub", content, 0644) + if err != nil { + return err + } + + content = []byte(strings.Join(addresses, "\n")) + err = ioutil.WriteFile(path+".addr", content, 0644) + if err != nil { + return err + } + + content = []byte(strings.Join(mnemonics, "\n")) + err = ioutil.WriteFile(path+".mne", content, 0600) + if err != nil { + return err + } + + return nil +} + +func (k *FileKeyStore) Load(session string) (*KeyRing, error) { + basename := session + if session == "" { + basename = "default" + } + secfile := path.Join(k.basedir, basename+".prv") + _, err := os.Stat(secfile) + // if file is not found then we return nil, no error + if err != nil { + return nil, nil + } + return NewKeyRingFromFile(secfile) +} diff --git a/ethcrypto/keypair.go b/ethcrypto/keypair.go new file mode 100644 index 0000000000..ae9db3698e --- /dev/null +++ b/ethcrypto/keypair.go @@ -0,0 +1,41 @@ +package ethcrypto + +import ( + "github.com/ethereum/eth-go/ethutil" + "github.com/obscuren/secp256k1-go" +) + +type KeyPair struct { + PrivateKey []byte + PublicKey []byte + + // The associated account + // account *StateObject +} + +func GenerateNewKeyPair() *KeyPair { + _, prv := secp256k1.GenerateKeyPair() + keyPair, _ := NewKeyPairFromSec(prv) // swallow error, this one cannot err + return keyPair +} + +func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { + pubkey, err := secp256k1.GeneratePubKey(seckey) + if err != nil { + return nil, err + } + + return &KeyPair{PrivateKey: seckey, PublicKey: pubkey}, nil +} + +func (k *KeyPair) Address() []byte { + return Sha3Bin(k.PublicKey[1:])[12:] +} + +func (k *KeyPair) RlpEncode() []byte { + return k.RlpValue().Encode() +} + +func (k *KeyPair) RlpValue() *ethutil.Value { + return ethutil.NewValue(k.PrivateKey) +} diff --git a/ethcrypto/keyring.go b/ethcrypto/keyring.go new file mode 100644 index 0000000000..277fa2134a --- /dev/null +++ b/ethcrypto/keyring.go @@ -0,0 +1,118 @@ +package ethcrypto + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "io/ioutil" + "strings" +) + +type KeyRing struct { + keys []*KeyPair +} + +func NewKeyRing() *KeyRing { + return &KeyRing{} +} + +func (k *KeyRing) AddKeyPair(keyPair *KeyPair) { + k.keys = append(k.keys, keyPair) +} + +func (k *KeyRing) GetKeyPair(i int) *KeyPair { + if len(k.keys) > i { + return k.keys[i] + } + + return nil +} + +func (k *KeyRing) Empty() bool { + return k.Len() == 0 +} + +func (k *KeyRing) Len() int { + return len(k.keys) +} + +func (k *KeyRing) Each(f func(*KeyPair)) { + for _, keyPair := range k.keys { + f(keyPair) + } +} + +func NewGeneratedKeyRing(len int) *KeyRing { + keyRing := NewKeyRing() + for i := 0; i < len; i++ { + keyRing.AddKeyPair(GenerateNewKeyPair()) + } + return keyRing +} + +func NewKeyRingFromFile(secfile string) (*KeyRing, error) { + var content []byte + var err error + content, err = ioutil.ReadFile(secfile) + if err != nil { + return nil, err + } + keyRing, err := NewKeyRingFromString(string(content)) + if err != nil { + return nil, err + } + return keyRing, nil +} + +func NewKeyRingFromString(content string) (*KeyRing, error) { + secretStrings := strings.Split(content, "\n") + var secrets [][]byte + for _, secretString := range secretStrings { + secret := secretString + words := strings.Split(secretString, " ") + if len(words) == 24 { + secret = MnemonicDecode(words) + } else if len(words) != 1 { + return nil, fmt.Errorf("Unrecognised key format") + } + secrets = append(secrets, ethutil.Hex2Bytes(secret)) + } + return NewKeyRingFromSecrets(secrets) +} + +func NewKeyRingFromSecrets(secs [][]byte) (*KeyRing, error) { + keyRing := NewKeyRing() + for _, sec := range secs { + keyPair, err := NewKeyPairFromSec(sec) + if err != nil { + return nil, err + } + keyRing.AddKeyPair(keyPair) + } + return keyRing, nil +} + +func NewKeyRingFromBytes(data []byte) (*KeyRing, error) { + var secrets [][]byte + it := ethutil.NewValueFromBytes(data).NewIterator() + for it.Next() { + secret := it.Value().Bytes() + secrets = append(secrets, secret) + } + keyRing, err := NewKeyRingFromSecrets(secrets) + if err != nil { + return nil, err + } + return keyRing, nil +} + +func (k *KeyRing) RlpEncode() []byte { + return k.RlpValue().Encode() +} + +func (k *KeyRing) RlpValue() *ethutil.Value { + v := ethutil.EmptyValue() + k.Each(func(keyPair *KeyPair) { + v.Append(keyPair.RlpValue()) + }) + return v +} diff --git a/ethcrypto/keys_test.go b/ethcrypto/keys_test.go new file mode 100644 index 0000000000..3ebf4e8183 --- /dev/null +++ b/ethcrypto/keys_test.go @@ -0,0 +1,122 @@ +package ethcrypto + +import ( + "github.com/ethereum/eth-go/ethdb" + // "io/ioutil" + "fmt" + "os" + "path" + "testing" +) + +// test if persistence layer works +func TestDBKeyManager(t *testing.T) { + memdb, _ := ethdb.NewMemDatabase() + keyManager0 := NewDBKeyManager(memdb) + err := keyManager0.Init("", 0, false) + if err != nil { + t.Error("Unexpected error: ", err) + } + keyManager1 := NewDBKeyManager(memdb) + err = keyManager1.Init("", 0, false) + if err != nil { + t.Error("Unexpected error: ", err) + } + if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { + t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + } + err = keyManager1.Init("", 0, true) + if err != nil { + t.Error("Unexpected error: ", err) + } + if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) { + t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + } +} + +func TestFileKeyManager(t *testing.T) { + basedir0 := "/tmp/ethtest0" + os.RemoveAll(basedir0) + os.Mkdir(basedir0, 0777) + + keyManager0 := NewFileKeyManager(basedir0) + err := keyManager0.Init("", 0, false) + if err != nil { + t.Error("Unexpected error: ", err) + } + + keyManager1 := NewFileKeyManager(basedir0) + + err = keyManager1.Init("", 0, false) + if err != nil { + t.Error("Unexpected error: ", err) + } + if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { + t.Error("Expected private keys %x, %x, to be identical via db persistence", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + } + + err = keyManager1.Init("", 0, true) + if err != nil { + t.Error("Unexpected error: ", err) + } + if string(keyManager0.PrivateKey()) == string(keyManager1.PrivateKey()) { + t.Error("Expected private keys %x, %x, to be be different despite db persistence if force generate", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + } +} + +// cursor errors +func TestCursorErrors(t *testing.T) { + memdb, _ := ethdb.NewMemDatabase() + keyManager0 := NewDBKeyManager(memdb) + err := keyManager0.Init("", 0, false) + err = keyManager0.Init("", 1, false) + if err == nil { + t.Error("Expected cursor error") + } + err = keyManager0.SetCursor(1) + if err == nil { + t.Error("Expected cursor error") + } +} + +func TestExportImport(t *testing.T) { + memdb, _ := ethdb.NewMemDatabase() + keyManager0 := NewDBKeyManager(memdb) + err := keyManager0.Init("", 0, false) + basedir0 := "/tmp/ethtest0" + os.RemoveAll(basedir0) + os.Mkdir(basedir0, 0777) + keyManager0.Export(basedir0) + + keyManager1 := NewFileKeyManager(basedir0) + err = keyManager1.Init("", 0, false) + if err != nil { + t.Error("Unexpected error: ", err) + } + fmt.Printf("keyRing: %v\n", keyManager0.KeyPair()) + fmt.Printf("keyRing: %v\n", keyManager1.KeyPair()) + if string(keyManager0.PrivateKey()) != string(keyManager1.PrivateKey()) { + t.Error("Expected private keys %x, %x, to be identical via export to filestore basedir", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + } + path.Join("") + + // memdb, _ = ethdb.NewMemDatabase() + // keyManager2 := NewDBKeyManager(memdb) + // err = keyManager2.InitFromSecretsFile("", 0, path.Join(basedir0, "default.prv")) + // if err != nil { + // t.Error("Unexpected error: ", err) + // } + // if string(keyManager0.PrivateKey()) != string(keyManager2.PrivateKey()) { + // t.Error("Expected private keys %s, %s, to be identical via export/import prv", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + // } + + // memdb, _ = ethdb.NewMemDatabase() + // keyManager3 := NewDBKeyManager(memdb) + // err = keyManager3.InitFromSecretsFile("", 0, path.Join(basedir0, "default.mne")) + // if err != nil { + // t.Error("Unexpected error: ", err) + // } + // if string(keyManager0.PrivateKey()) != string(keyManager3.PrivateKey()) { + // t.Error("Expected private keys %s, %s, to be identical via export/import mnemonic file", keyManager0.PrivateKey(), keyManager1.PrivateKey()) + // } +} From 5e50b50dc379ed1db48912538034414ff94f6531 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:06:54 +0100 Subject: [PATCH 0518/1237] no strconv import needed --- ethutil/slice.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ethutil/slice.go b/ethutil/slice.go index 67f43705dc..3cedcb1894 100644 --- a/ethutil/slice.go +++ b/ethutil/slice.go @@ -1,8 +1,6 @@ package ethutil -import ( - "strconv" -) +import () // Helper function for comparing slices func CompareIntSlice(a, b []int) bool { From e3b911652dfba1475001137ba8b3687b9fec5331 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:08:33 +0100 Subject: [PATCH 0519/1237] move CreateAddress from ethutil/common to ethcrypto --- ethcrypto/crypto.go | 7 +++++++ ethutil/common.go | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index 9c4013d6c8..b341915ebd 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -25,3 +25,10 @@ func Sha3Bin(data []byte) []byte { return d.Sum(nil) } + +// Creates an ethereum address given the bytes and the nonce +func CreateAddress(b []byte, nonce *big.Int) []byte { + addrBytes := append(b, nonce.Bytes()...) + + return Sha3Bin(addrBytes)[12:] +} diff --git a/ethutil/common.go b/ethutil/common.go index f63ba5d830..6d88a1ed2a 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -52,10 +52,3 @@ var ( Big32 = big.NewInt(32) Big256 = big.NewInt(0xff) ) - -// Creates an ethereum address given the bytes and the nonce -func CreateAddress(b []byte, nonce *big.Int) []byte { - addrBytes := append(b, nonce.Bytes()...) - - return Sha3Bin(addrBytes)[12:] -} From 4be3521727698141512eb6454121302bd3b9cc6d Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:17:33 +0100 Subject: [PATCH 0520/1237] import math/big --- ethcrypto/crypto.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcrypto/crypto.go b/ethcrypto/crypto.go index b341915ebd..8cb0be88c9 100644 --- a/ethcrypto/crypto.go +++ b/ethcrypto/crypto.go @@ -4,6 +4,7 @@ import ( "code.google.com/p/go.crypto/ripemd160" "crypto/sha256" "github.com/obscuren/sha3" + "math/big" ) func Sha256Bin(data []byte) []byte { From 707d413761927f5ad95298e666e297b820ad0901 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 16:26:58 +0100 Subject: [PATCH 0521/1237] refactor ethutil/trie to ethtrie --- ethchain/state.go | 5 +-- {ethutil => ethtrie}/encoding.go | 2 +- {ethutil => ethtrie}/encoding_test.go | 2 +- {ethutil => ethtrie}/slice.go | 2 +- {ethutil => ethtrie}/trie.go | 50 ++++++++++++++------------- {ethutil => ethtrie}/trie_test.go | 2 +- 6 files changed, 33 insertions(+), 30 deletions(-) rename {ethutil => ethtrie}/encoding.go (98%) rename {ethutil => ethtrie}/encoding_test.go (99%) rename {ethutil => ethtrie}/slice.go (96%) rename {ethutil => ethtrie}/trie.go (90%) rename {ethutil => ethtrie}/trie_test.go (99%) diff --git a/ethchain/state.go b/ethchain/state.go index e28b919099..4c66a973e5 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -12,7 +13,7 @@ import ( // * Accounts type State struct { // The trie for this structure - trie *ethutil.Trie + trie *ethtrie.Trie stateObjects map[string]*StateObject @@ -20,7 +21,7 @@ type State struct { } // Create a new state from a given trie -func NewState(trie *ethutil.Trie) *State { +func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } diff --git a/ethutil/encoding.go b/ethtrie/encoding.go similarity index 98% rename from ethutil/encoding.go rename to ethtrie/encoding.go index 9fcdf3edfc..c9c3911104 100644 --- a/ethutil/encoding.go +++ b/ethtrie/encoding.go @@ -1,4 +1,4 @@ -package ethutil +package ethtrie import ( "bytes" diff --git a/ethutil/encoding_test.go b/ethtrie/encoding_test.go similarity index 99% rename from ethutil/encoding_test.go rename to ethtrie/encoding_test.go index 10e1995c02..7a48496788 100644 --- a/ethutil/encoding_test.go +++ b/ethtrie/encoding_test.go @@ -1,4 +1,4 @@ -package ethutil +package ethtrie import ( "fmt" diff --git a/ethutil/slice.go b/ethtrie/slice.go similarity index 96% rename from ethutil/slice.go rename to ethtrie/slice.go index 3cedcb1894..b9d5d12853 100644 --- a/ethutil/slice.go +++ b/ethtrie/slice.go @@ -1,4 +1,4 @@ -package ethutil +package ethtrie import () diff --git a/ethutil/trie.go b/ethtrie/trie.go similarity index 90% rename from ethutil/trie.go rename to ethtrie/trie.go index 18d0a5f0ae..c957e9b4cb 100644 --- a/ethutil/trie.go +++ b/ethtrie/trie.go @@ -1,7 +1,9 @@ -package ethutil +package ethtrie import ( "fmt" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" "reflect" "sync" ) @@ -21,11 +23,11 @@ type StateObject interface { type Node struct { Key []byte - Value *Value + Value *ethutil.Value Dirty bool } -func NewNode(key []byte, val *Value, dirty bool) *Node { +func NewNode(key []byte, val *ethutil.Value, dirty bool) *Node { return &Node{Key: key, Value: val, Dirty: dirty} } @@ -35,20 +37,20 @@ func (n *Node) Copy() *Node { type Cache struct { nodes map[string]*Node - db Database + db ethutil.Database IsDirty bool } -func NewCache(db Database) *Cache { +func NewCache(db ethutil.Database) *Cache { return &Cache{db: db, nodes: make(map[string]*Node)} } func (cache *Cache) Put(v interface{}) interface{} { - value := NewValue(v) + value := ethutil.NewValue(v) enc := value.Encode() if len(enc) >= 32 { - sha := Sha3Bin(enc) + sha := ethcrypto.Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) cache.IsDirty = true @@ -59,7 +61,7 @@ func (cache *Cache) Put(v interface{}) interface{} { return v } -func (cache *Cache) Get(key []byte) *Value { +func (cache *Cache) Get(key []byte) *ethutil.Value { // First check if the key is the cache if cache.nodes[string(key)] != nil { return cache.nodes[string(key)].Value @@ -68,7 +70,7 @@ func (cache *Cache) Get(key []byte) *Value { // Get the key of the database instead and cache it data, _ := cache.db.Get(key) // Create the cached value - value := NewValueFromBytes(data) + value := ethutil.NewValueFromBytes(data) // Create caching node cache.nodes[string(key)] = NewNode(key, value, false) @@ -128,7 +130,7 @@ type Trie struct { func copyRoot(root interface{}) interface{} { var prevRootCopy interface{} if b, ok := root.([]byte); ok { - prevRootCopy = CopyBytes(b) + prevRootCopy = ethutil.CopyBytes(b) } else { prevRootCopy = root } @@ -136,7 +138,7 @@ func copyRoot(root interface{}) interface{} { return prevRootCopy } -func NewTrie(db Database, Root interface{}) *Trie { +func NewTrie(db ethutil.Database, Root interface{}) *Trie { // Make absolute sure the root is copied r := copyRoot(Root) p := copyRoot(Root) @@ -176,7 +178,7 @@ func (t *Trie) Get(key string) string { defer t.mut.RUnlock() k := CompactHexDecode(key) - c := NewValue(t.GetState(t.Root, k)) + c := ethutil.NewValue(t.GetState(t.Root, k)) return c.Str() } @@ -186,7 +188,7 @@ func (t *Trie) Delete(key string) { } func (t *Trie) GetState(node interface{}, key []int) interface{} { - n := NewValue(node) + n := ethutil.NewValue(node) // Return the node if key is empty (= found) if len(key) == 0 || n.IsNil() || n.Len() == 0 { return node @@ -216,8 +218,8 @@ func (t *Trie) GetState(node interface{}, key []int) interface{} { return "" } -func (t *Trie) GetNode(node interface{}) *Value { - n := NewValue(node) +func (t *Trie) GetNode(node interface{}) *ethutil.Value { + n := ethutil.NewValue(node) if !n.Get(0).IsNil() { return n @@ -227,7 +229,7 @@ func (t *Trie) GetNode(node interface{}) *Value { if len(str) == 0 { return n } else if len(str) < 32 { - return NewValueFromBytes([]byte(str)) + return ethutil.NewValueFromBytes([]byte(str)) } return t.cache.Get(n.Bytes()) @@ -273,7 +275,7 @@ func (t *Trie) InsertState(node interface{}, key []int, value interface{}) inter } // New node - n := NewValue(node) + n := ethutil.NewValue(node) if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { newNode := []interface{}{CompactEncode(key), value} @@ -345,7 +347,7 @@ func (t *Trie) DeleteState(node interface{}, key []int) interface{} { } // New node - n := NewValue(node) + n := ethutil.NewValue(node) if node == nil || (n.Type() == reflect.String && (n.Str() == "" || n.Get(0).IsNil())) || n.Len() == 0 { return "" } @@ -422,7 +424,7 @@ func (t *Trie) DeleteState(node interface{}, key []int) interface{} { // Simple compare function which creates a rlp value out of the evaluated objects func (t *Trie) Cmp(trie *Trie) bool { - return NewValue(t.Root).Cmp(NewValue(trie.Root)) + return ethutil.NewValue(t.Root).Cmp(ethutil.NewValue(trie.Root)) } // Returns a copy of this trie @@ -452,7 +454,7 @@ func (t *Trie) NewIterator() *TrieIterator { // Some time in the near future this will need refactoring :-) // XXX Note to self, IsSlice == inline node. Str == sha3 to node -func (it *TrieIterator) workNode(currentNode *Value) { +func (it *TrieIterator) workNode(currentNode *ethutil.Value) { if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) @@ -495,7 +497,7 @@ func (it *TrieIterator) Collect() [][]byte { return nil } - it.getNode(NewValue(it.trie.Root).Bytes()) + it.getNode(ethutil.NewValue(it.trie.Root).Bytes()) return it.shas } @@ -516,17 +518,17 @@ func (it *TrieIterator) Value() string { return "" } -type EachCallback func(key string, node *Value) +type EachCallback func(key string, node *ethutil.Value) func (it *TrieIterator) Each(cb EachCallback) { - it.fetchNode(nil, NewValue(it.trie.Root).Bytes(), cb) + it.fetchNode(nil, ethutil.NewValue(it.trie.Root).Bytes(), cb) } func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { it.iterateNode(key, it.trie.cache.Get(node), cb) } -func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { +func (it *TrieIterator) iterateNode(key []int, currentNode *ethutil.Value, cb EachCallback) { if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) diff --git a/ethutil/trie_test.go b/ethtrie/trie_test.go similarity index 99% rename from ethutil/trie_test.go rename to ethtrie/trie_test.go index 2937b15250..284b189cba 100644 --- a/ethutil/trie_test.go +++ b/ethtrie/trie_test.go @@ -1,4 +1,4 @@ -package ethutil +package ethtrie import ( "fmt" From dabaa4cce01586fd8b1b9314073a1d26f35355c8 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 18:30:05 +0100 Subject: [PATCH 0522/1237] change all modified calls to ethtrie, ethutil and ethcrypto functions --- ethchain/block.go | 16 +++++++++------- ethchain/block_chain.go | 2 +- ethchain/dagger.go | 3 ++- ethchain/genesis.go | 7 ++++--- ethchain/state.go | 5 +++-- ethchain/state_manager.go | 4 +++- ethchain/state_object.go | 11 +++++++---- ethchain/transaction.go | 7 ++++--- ethchain/vm.go | 5 +++-- ethereum.go | 18 +++++++++++------- ethpub/pub.go | 36 ++++++++++++++++-------------------- ethpub/types.go | 38 +++++++++++++++++++------------------- ethrpc/packages.go | 2 +- peer.go | 20 ++++++++------------ 14 files changed, 91 insertions(+), 83 deletions(-) diff --git a/ethchain/block.go b/ethchain/block.go index fee4a2d59c..ed5b754f86 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -3,6 +3,8 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" "strconv" @@ -102,18 +104,18 @@ func CreateBlock(root interface{}, } block.SetUncles([]*Block{}) - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) return block } // Returns a hash of the block func (block *Block) Hash() []byte { - return ethutil.Sha3Bin(block.Value().Encode()) + return ethcrypto.Sha3Bin(block.Value().Encode()) } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, block.GasLimit, block.GasUsed, block.Time, block.Extra})) @@ -239,7 +241,7 @@ func (block *Block) SetUncles(uncles []*Block) { block.Uncles = uncles // Sha of the concatenated uncles - block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) + block.UncleSha = ethcrypto.Sha3Bin(ethutil.Encode(block.rlpUncles())) } func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { @@ -250,7 +252,7 @@ func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs - trie := ethutil.NewTrie(ethutil.Config.Db, "") + trie := ethtrie.NewTrie(ethutil.Config.Db, "") for i, tx := range txs { trie.Update(strconv.Itoa(i), string(tx.RlpEncode())) } @@ -287,7 +289,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() @@ -329,7 +331,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block { block.PrevHash = header.Get(0).Bytes() block.UncleSha = header.Get(1).Bytes() block.Coinbase = header.Get(2).Bytes() - block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) + block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6e4c72b278..7a481ed7c0 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -278,7 +278,7 @@ func AddTestNetFunds(block *Block) { "e6716f9544a56c530d868e4bfbacb172315bdead", "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { - codedAddr := ethutil.FromHex(addr) + codedAddr := ethutil.Hex2Bytes(addr) account := block.state.GetAccount(codedAddr) account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 08c4826dbf..46b1081e9d 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" @@ -40,7 +41,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { powlogger.Infoln("Hashing @", int64(hashes), "khash") } - sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) + sha := ethcrypto.Sha3Bin(big.NewInt(r.Int63()).Bytes()) if pow.Verify(hash, diff, sha) { return sha } diff --git a/ethchain/genesis.go b/ethchain/genesis.go index 359c47c261..54a3bc7665 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -11,13 +12,13 @@ import ( var ZeroHash256 = make([]byte, 32) var ZeroHash160 = make([]byte, 20) -var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{})) +var EmptyShaList = ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})) var GenesisHeader = []interface{}{ // Previous hash (none) ZeroHash256, // Sha of uncles - ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), + ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{})), // Coinbase ZeroHash160, // Root state @@ -39,7 +40,7 @@ var GenesisHeader = []interface{}{ // Extra nil, // Nonce - ethutil.Sha3Bin(big.NewInt(42).Bytes()), + ethcrypto.Sha3Bin(big.NewInt(42).Bytes()), } var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}} diff --git a/ethchain/state.go b/ethchain/state.go index 4c66a973e5..dc2d3c73b8 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -74,7 +75,7 @@ func (s *State) Purge() int { return s.trie.NewIterator().Purge() } -func (s *State) EachStorage(cb ethutil.EachCallback) { +func (s *State) EachStorage(cb ethtrie.EachCallback) { it := s.trie.NewIterator() it.Each(cb) } @@ -92,7 +93,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.stateObjects[string(addr)] = stateObject } - ethutil.Config.Db.Put(ethutil.Sha3Bin(stateObject.Script()), stateObject.Script()) + ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script()) self.trie.Update(string(addr), string(stateObject.RlpEncode())) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 312ba3084e..f199e20ece 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "container/list" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -38,6 +39,7 @@ type EthManager interface { IsMining() bool IsListening() bool Peers() *list.List + KeyManager() *ethcrypto.KeyManager } type StateManager struct { @@ -293,7 +295,7 @@ func (sm *StateManager) ValidateBlock(block *Block) error { // Verify the nonce of the block. Return an error if it's not valid if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) { - return ValidationError("Block's nonce is invalid (= %v)", ethutil.Hex(block.Nonce)) + return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce)) } return nil diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 480b4055df..e55540153c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -2,6 +2,8 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" "strings" @@ -39,7 +41,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { contract := state.NewStateObject(addr) contract.initScript = tx.Data - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) return contract } @@ -53,7 +55,7 @@ func NewStateObject(addr []byte) *StateObject { func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} - contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) + contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) return contract } @@ -246,7 +248,7 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { @@ -254,7 +256,8 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Amount = decoder.Get(1).BigInt() - c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + 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.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2ab6810304..11f786b365 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -62,7 +63,7 @@ func (self *Transaction) TotalValue() *big.Int { func (tx *Transaction) Hash() []byte { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) + return ethcrypto.Sha3Bin(ethutil.NewValue(data).Encode()) } func (tx *Transaction) CreatesContract() bool { @@ -75,7 +76,7 @@ func (tx *Transaction) IsContract() bool { } func (tx *Transaction) CreationAddress() []byte { - return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + return ethcrypto.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { @@ -111,7 +112,7 @@ func (tx *Transaction) Sender() []byte { return nil } - return ethutil.Sha3Bin(pubkey[1:])[12:] + return ethcrypto.Sha3Bin(pubkey[1:])[12:] } func (tx *Transaction) Sign(privk []byte) error { diff --git a/ethchain/vm.go b/ethchain/vm.go index 82591e2745..66b5a91827 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "math" @@ -398,7 +399,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) size, offset := stack.Popn() - data := ethutil.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) + data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) // 0x30 range @@ -594,7 +595,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro snapshot := vm.state.Copy() // Generate a new address - addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) + addr := ethcrypto.CreateAddress(closure.caller.Address(), closure.caller.N()) vm.Printf(" (*) %x", addr).Endl() diff --git a/ethereum.go b/ethereum.go index a3df23e924..b78b0658fc 100644 --- a/ethereum.go +++ b/ethereum.go @@ -4,7 +4,7 @@ import ( "container/list" "fmt" "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" @@ -74,16 +74,15 @@ type Ethereum struct { reactor *ethutil.ReactorEngine RpcServer *ethrpc.JsonRpcServer + + keyManager *ethcrypto.KeyManager } -func New(caps Caps, usePnp bool) (*Ethereum, error) { - db, err := ethdb.NewLDBDatabase("database") - //db, err := ethdb.NewMemDatabase() - if err != nil { - return nil, err - } +func New(db ethutil.Database, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { + var err error var nat NAT + if usePnp { nat, err = Discover() if err != nil { @@ -102,6 +101,7 @@ func New(caps Caps, usePnp bool) (*Ethereum, error) { Nonce: nonce, serverCaps: caps, nat: nat, + keyManager: keyManager, } ethereum.reactor = ethutil.NewReactorEngine() @@ -119,6 +119,10 @@ func (s *Ethereum) Reactor() *ethutil.ReactorEngine { return s.reactor } +func (s *Ethereum) KeyManager() *ethcrypto.KeyManager { + return s.keyManager +} + func (s *Ethereum) BlockChain() *ethchain.BlockChain { return s.blockChain } diff --git a/ethpub/pub.go b/ethpub/pub.go index 1bc9e0ce7d..cd30d02604 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -2,9 +2,9 @@ package ethpub import ( "bytes" - "encoding/hex" "encoding/json" "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -19,6 +19,7 @@ type PEthereum struct { stateManager *ethchain.StateManager blockChain *ethchain.BlockChain txPool *ethchain.TxPool + keyManager *ethcrypto.KeyManager } func NewPEthereum(manager ethchain.EthManager) *PEthereum { @@ -27,24 +28,23 @@ func NewPEthereum(manager ethchain.EthManager) *PEthereum { manager.StateManager(), manager.BlockChain(), manager.TxPool(), + manager.KeyManager(), } } func (lib *PEthereum) GetBlock(hexHash string) *PBlock { - hash := ethutil.FromHex(hexHash) + hash := ethutil.Hex2Bytes(hexHash) block := lib.blockChain.GetBlock(hash) return NewPBlock(block) } func (lib *PEthereum) GetKey() *PKey { - keyPair := ethutil.GetKeyRing().Get(0) - - return NewPKey(keyPair) + return NewPKey(lib.keyManager.KeyPair()) } func (lib *PEthereum) GetStateObject(address string) *PStateObject { - stateObject := lib.stateManager.CurrentState().GetStateObject(ethutil.FromHex(address)) + stateObject := lib.stateManager.CurrentState().GetStateObject(ethutil.Hex2Bytes(address)) if stateObject != nil { return NewPStateObject(stateObject) } @@ -79,17 +79,13 @@ func (lib *PEthereum) GetIsListening() bool { } func (lib *PEthereum) GetCoinBase() string { - data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) - keyRing := ethutil.NewValueFromBytes(data) - key := keyRing.Get(0).Bytes() - - return lib.SecretToAddress(hex.EncodeToString(key)) + return ethutil.Bytes2Hex(lib.keyManager.Address()) } func (lib *PEthereum) GetTransactionsFor(address string, asJson bool) interface{} { sBlk := lib.manager.BlockChain().LastBlockHash blk := lib.manager.BlockChain().GetBlock(sBlk) - addr := []byte(ethutil.FromHex(address)) + addr := []byte(ethutil.Hex2Bytes(address)) var txs []*PTx @@ -129,12 +125,12 @@ func (lib *PEthereum) IsContract(address string) bool { } func (lib *PEthereum) SecretToAddress(key string) string { - pair, err := ethutil.NewKeyPairFromSec(ethutil.FromHex(key)) + pair, err := ethcrypto.NewKeyPairFromSec(ethutil.Hex2Bytes(key)) if err != nil { return "" } - return ethutil.Hex(pair.Address()) + return ethutil.Bytes2Hex(pair.Address()) } func (lib *PEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) (*PReceipt, error) { @@ -145,7 +141,7 @@ func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) } -var namereg = ethutil.FromHex("bb5f186604d057c1c5240ca2ae0f6430138ac010") +var namereg = ethutil.Hex2Bytes("bb5f186604d057c1c5240ca2ae0f6430138ac010") func GetAddressFromNameReg(stateManager *ethchain.StateManager, name string) []byte { recp := new(big.Int).SetBytes([]byte(name)) @@ -169,16 +165,16 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc if len(addr) > 0 { hash = addr } else { - hash = ethutil.FromHex(recipient) + hash = ethutil.Hex2Bytes(recipient) } } - var keyPair *ethutil.KeyPair + var keyPair *ethcrypto.KeyPair var err error if key[0:2] == "0x" { - keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key[2:]))) + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:]))) } else { - keyPair, err = ethutil.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key))) } if err != nil { @@ -194,7 +190,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc var script []byte var err error if ethutil.IsHex(scriptStr) { - script = ethutil.FromHex(scriptStr) + script = ethutil.Hex2Bytes(scriptStr[2:]) } else { script, err = ethutil.Compile(scriptStr) if err != nil { diff --git a/ethpub/types.go b/ethpub/types.go index 0ced68ad17..05031dea23 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -1,10 +1,10 @@ package ethpub import ( - "encoding/hex" "encoding/json" "fmt" "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethutil" "strings" ) @@ -66,7 +66,7 @@ func NewPBlock(block *ethchain.Block) *PBlock { return nil } - return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Hex(block.Coinbase)} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), Transactions: string(txJson), Time: block.Time, Coinbase: ethutil.Bytes2Hex(block.Coinbase)} } func (self *PBlock) ToString() string { @@ -78,7 +78,7 @@ func (self *PBlock) ToString() string { } func (self *PBlock) GetTransaction(hash string) *PTx { - tx := self.ref.GetTransaction(ethutil.FromHex(hash)) + tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash)) if tx == nil { return nil } @@ -103,22 +103,22 @@ type PTx struct { } func NewPTx(tx *ethchain.Transaction) *PTx { - hash := hex.EncodeToString(tx.Hash()) - receiver := hex.EncodeToString(tx.Recipient) + hash := ethutil.Bytes2Hex(tx.Hash()) + receiver := ethutil.Bytes2Hex(tx.Recipient) if receiver == "0000000000000000000000000000000000000000" { - receiver = hex.EncodeToString(tx.CreationAddress()) + receiver = ethutil.Bytes2Hex(tx.CreationAddress()) } - sender := hex.EncodeToString(tx.Sender()) + sender := ethutil.Bytes2Hex(tx.Sender()) createsContract := tx.CreatesContract() var data string if tx.CreatesContract() { data = strings.Join(ethchain.Disassemble(tx.Data), "\n") } else { - data = hex.EncodeToString(tx.Data) + data = ethutil.Bytes2Hex(tx.Data) } - return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: hex.EncodeToString(tx.Data)} + return &PTx{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)} } func (self *PTx) ToString() string { @@ -131,8 +131,8 @@ type PKey struct { PublicKey string `json:"publicKey"` } -func NewPKey(key *ethutil.KeyPair) *PKey { - return &PKey{ethutil.Hex(key.Address()), ethutil.Hex(key.PrivateKey), ethutil.Hex(key.PublicKey)} +func NewPKey(key *ethcrypto.KeyPair) *PKey { + return &PKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)} } type PReceipt struct { @@ -145,9 +145,9 @@ type PReceipt struct { func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { return &PReceipt{ contractCreation, - ethutil.Hex(creationAddress), - ethutil.Hex(hash), - ethutil.Hex(address), + ethutil.Bytes2Hex(creationAddress), + ethutil.Bytes2Hex(hash), + ethutil.Bytes2Hex(address), } } @@ -182,7 +182,7 @@ func (c *PStateObject) Value() string { func (c *PStateObject) Address() string { if c.object != nil { - return ethutil.Hex(c.object.Address()) + return ethutil.Bytes2Hex(c.object.Address()) } return "" @@ -198,7 +198,7 @@ func (c *PStateObject) Nonce() int { func (c *PStateObject) Root() string { if c.object != nil { - return ethutil.Hex(ethutil.NewValue(c.object.State().Root()).Bytes()) + return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State().Root()).Bytes()) } return "" @@ -221,7 +221,7 @@ func (c *PStateObject) StateKeyVal(asJson bool) interface{} { var values []KeyVal if c.object != nil { c.object.State().EachStorage(func(name string, value *ethutil.Value) { - values = append(values, KeyVal{name, ethutil.Hex(value.Bytes())}) + values = append(values, KeyVal{name, ethutil.Bytes2Hex(value.Bytes())}) }) } @@ -247,7 +247,7 @@ func (c *PStateObject) Script() string { func (c *PStateObject) HexScript() string { if c.object != nil { - return ethutil.Hex(c.object.Script()) + return ethutil.Bytes2Hex(c.object.Script()) } return "" @@ -260,5 +260,5 @@ type PStorageState struct { } func NewPStorageState(storageObject *ethchain.StorageState) *PStorageState { - return &PStorageState{ethutil.Hex(storageObject.StateAddress), ethutil.Hex(storageObject.Address), storageObject.Value.String()} + return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()} } diff --git a/ethrpc/packages.go b/ethrpc/packages.go index 7102757803..0662f0edd1 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -182,7 +182,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { } else { // Convert the incoming string (which is a bigint) into hex i, _ := new(big.Int).SetString(args.Key, 10) - hx = ethutil.Hex(i.Bytes()) + hx = ethutil.Bytes2Hex(i.Bytes()) } logger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) value := state.GetStorage(hx) diff --git a/peer.go b/peer.go index e50fd43f93..ffabb8f495 100644 --- a/peer.go +++ b/peer.go @@ -146,7 +146,7 @@ type Peer struct { } func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { - pubkey := ethutil.GetKeyRing().Get(0).PublicKey[1:] + pubkey := ethereum.KeyManager().PublicKey()[1:] return &Peer{ outputQueue: make(chan *ethwire.Msg, outputBufferSize), @@ -590,16 +590,12 @@ func (p *Peer) Stop() { } func (p *Peer) pushHandshake() error { - keyRing := ethutil.GetKeyRing().Get(0) - if keyRing != nil { - pubkey := keyRing.PublicKey + pubkey := p.ethereum.KeyManager().PublicKey() + msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ + uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], + }) - msg := ethwire.NewMessage(ethwire.MsgHandshakeTy, []interface{}{ - uint32(ProtocolVersion), uint32(0), []byte(p.version), byte(p.caps), p.port, pubkey[1:], - }) - - p.QueueMessage(msg) - } + p.QueueMessage(msg) return nil } @@ -664,8 +660,8 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { p.port = uint16(c.Get(4).Uint()) // Self connect detection - keyPair := ethutil.GetKeyRing().Get(0) - if bytes.Compare(keyPair.PublicKey, p.pubkey) == 0 { + pubkey := p.ethereum.KeyManager().PublicKey() + if bytes.Compare(pubkey, p.pubkey) == 0 { p.Stop() return From a8be0d9f4849d8127d2ba36b90327097f94a91cb Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 20:26:55 +0100 Subject: [PATCH 0523/1237] add InitFromString method to be used in gui --- ethcrypto/key_manager.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ethcrypto/key_manager.go b/ethcrypto/key_manager.go index dcbc7b77e2..066a62aabb 100644 --- a/ethcrypto/key_manager.go +++ b/ethcrypto/key_manager.go @@ -115,6 +115,14 @@ func (k *KeyManager) InitFromSecretsFile(session string, cursor int, secretsfile return k.reset(session, cursor, keyRing) } +func (k *KeyManager) InitFromString(session string, cursor int, secrets string) error { + keyRing, err := NewKeyRingFromString(secrets) + if err != nil { + return err + } + return k.reset(session, cursor, keyRing) +} + func (k *KeyManager) Export(dir string) error { fileKeyStore := FileKeyStore{dir} return fileKeyStore.Save(k.session, k.keyRing) From 25314313f8eefd5ae8d13b4c687e4811703eec2a Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 20:28:04 +0100 Subject: [PATCH 0524/1237] added Mnemonic() and AsStrings() methods, added memoization for address --- ethcrypto/keypair.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ethcrypto/keypair.go b/ethcrypto/keypair.go index ae9db3698e..18fa5b788c 100644 --- a/ethcrypto/keypair.go +++ b/ethcrypto/keypair.go @@ -3,12 +3,14 @@ package ethcrypto import ( "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" + "strings" ) type KeyPair struct { PrivateKey []byte PublicKey []byte - + address []byte + mnemonic string // The associated account // account *StateObject } @@ -29,7 +31,21 @@ func NewKeyPairFromSec(seckey []byte) (*KeyPair, error) { } func (k *KeyPair) Address() []byte { - return Sha3Bin(k.PublicKey[1:])[12:] + if k.address == nil { + k.address = Sha3Bin(k.PublicKey[1:])[12:] + } + return k.address +} + +func (k *KeyPair) Mnemonic() string { + if k.mnemonic == "" { + k.mnemonic = strings.Join(MnemonicEncode(ethutil.Bytes2Hex(k.PrivateKey)), " ") + } + return k.mnemonic +} + +func (k *KeyPair) AsStrings() (string, string, string, string) { + return k.Mnemonic(), ethutil.Bytes2Hex(k.Address()), ethutil.Bytes2Hex(k.PrivateKey), ethutil.Bytes2Hex(k.PublicKey) } func (k *KeyPair) RlpEncode() []byte { From 2920795168dfe5c5f1f1d66f09026f971d5e53fd Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 20:28:54 +0100 Subject: [PATCH 0525/1237] using keyPair.Mnemonic() in file key store Save method --- ethcrypto/key_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcrypto/key_store.go b/ethcrypto/key_store.go index c8c506fda7..f14f142055 100644 --- a/ethcrypto/key_store.go +++ b/ethcrypto/key_store.go @@ -61,7 +61,7 @@ func (k *FileKeyStore) Save(session string, keyRing *KeyRing) error { privateKeys = append(privateKeys, ethutil.Bytes2Hex(keyPair.PrivateKey)) publicKeys = append(publicKeys, ethutil.Bytes2Hex(keyPair.PublicKey)) addresses = append(addresses, ethutil.Bytes2Hex(keyPair.Address())) - mnemonics = append(mnemonics, strings.Join(MnemonicEncode(ethutil.Bytes2Hex(keyPair.PrivateKey)), " ")) + mnemonics = append(mnemonics, keyPair.Mnemonic()) }) basename := session From 12972b4b65a303dc3f9e135b0e2d97f8b7a661e2 Mon Sep 17 00:00:00 2001 From: zelig Date: Sun, 29 Jun 2014 20:53:26 +0100 Subject: [PATCH 0526/1237] DBKeyStore.Load returns no error if keyring not found in db --- ethcrypto/key_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcrypto/key_store.go b/ethcrypto/key_store.go index f14f142055..460f0c978c 100644 --- a/ethcrypto/key_store.go +++ b/ethcrypto/key_store.go @@ -32,7 +32,7 @@ func (k *DBKeyStore) Save(session string, keyRing *KeyRing) error { func (k *DBKeyStore) Load(session string) (*KeyRing, error) { data, err := k.db.Get(k.dbKey(session)) if err != nil { - return nil, err + return nil, nil } var keyRing *KeyRing keyRing, err = NewKeyRingFromBytes(data) From 5a86892ecbd68c3d466cb1ef282c4cb81300abce Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:08:00 +0200 Subject: [PATCH 0527/1237] Using remote for test cases --- ethutil/trie.go | 17 +++++-- ethutil/trie_test.go | 114 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 111 insertions(+), 20 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 18d0a5f0ae..ce9c2da27c 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -43,11 +43,11 @@ func NewCache(db Database) *Cache { return &Cache{db: db, nodes: make(map[string]*Node)} } -func (cache *Cache) Put(v interface{}) interface{} { +func (cache *Cache) PutValue(v interface{}, force bool) interface{} { value := NewValue(v) enc := value.Encode() - if len(enc) >= 32 { + if len(enc) >= 32 || force { sha := Sha3Bin(enc) cache.nodes[string(sha)] = NewNode(sha, value, true) @@ -59,6 +59,10 @@ func (cache *Cache) Put(v interface{}) interface{} { return v } +func (cache *Cache) Put(v interface{}) interface{} { + return cache.PutValue(v, false) +} + func (cache *Cache) Get(key []byte) *Value { // First check if the key is the cache if cache.nodes[string(key)] != nil { @@ -168,7 +172,12 @@ func (t *Trie) Update(key string, value string) { k := CompactHexDecode(key) - t.Root = t.UpdateState(t.Root, k, value) + root := t.UpdateState(t.Root, k, value) + if _, ok := root.([]byte); !ok { + t.Root = t.cache.PutValue(root, true) + } else { + t.Root = root + } } func (t *Trie) Get(key string) string { @@ -527,6 +536,8 @@ func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { } func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { + //fmt.Println("node", currentNode) + if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 2937b15250..3ee955b114 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -1,7 +1,12 @@ package ethutil import ( + "bytes" + "encoding/hex" + "encoding/json" "fmt" + "io/ioutil" + "net/http" "reflect" "testing" ) @@ -171,23 +176,98 @@ func TestTriePurge(t *testing.T) { } } -func TestTrieIt(t *testing.T) { - _, trie := New() - - data := [][]string{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, +func h(str string) string { + d, err := hex.DecodeString(str) + if err != nil { + panic(err) } - for _, item := range data { - trie.Update(item[0], item[1]) - } - - fmt.Printf("root %x", trie.Root) + return string(d) +} + +func get(in string) (out string) { + if len(in) > 2 && in[:2] == "0x" { + out = h(in[2:]) + } else { + out = in + } + + return +} + +type Test struct { + Name string + In map[string]string + Root string +} + +func CreateTest(name string, data []byte) (Test, error) { + t := Test{Name: name} + err := json.Unmarshal(data, &t) + if err != nil { + return Test{}, fmt.Errorf("%v", err) + } + + return t, nil +} + +func CreateTests(uri string, cb func(Test)) { + resp, err := http.Get(uri) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + + var objmap map[string]*json.RawMessage + err = json.Unmarshal(data, &objmap) + if err != nil { + panic(err) + } + + for name, testData := range objmap { + test, err := CreateTest(name, *testData) + if err != nil { + panic(err) + } + + cb(test) + } +} + +func TestRemote(t *testing.T) { + CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { + _, trie := New() + for key, value := range test.In { + trie.Update(get(key), get(value)) + } + fmt.Printf("%-15s: %x\n", test.Name, trie.Root) + + a := NewValue(h(test.Root)).Bytes() + b := NewValue(trie.Root).Bytes() + if bytes.Compare(a, b) != 0 { + t.Errorf("%-10s: %x %x", test.Name, a, b) + } + }) +} + +func TestTrieReplay(t *testing.T) { + CreateTests("https://raw.githubusercontent.com/ethereum/tests/develop/trietest.json", func(test Test) { + _, trie := New() + for key, value := range test.In { + trie.Update(get(key), get(value)) + } + + _, trie2 := New() + trie.NewIterator().Each(func(key string, v *Value) { + trie2.Update(key, string(v.Str())) + }) + + a := NewValue(trie.Root).Bytes() + b := NewValue(trie2.Root).Bytes() + if bytes.Compare(a, b) != 0 { + t.Errorf("root %x %x\n", trie.Root, trie2.Root) + } + }) } From 8ddd4c4c52eef9f382a321fa880adba4a1e35ee2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:09:04 +0200 Subject: [PATCH 0528/1237] wip --- ethchain/state_manager.go | 3 ++- ethchain/state_object.go | 5 +++- ethchain/state_transition.go | 45 ++++++++++++++++++++++++++++++++++++ ethutil/value.go | 8 +++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 312ba3084e..48c6401e30 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "container/list" + "fmt" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -200,7 +201,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { } if !block.State().Cmp(state) { - statelogger.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 480b4055df..edac4f6dc9 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -48,7 +48,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - return &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + object.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + + return object } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index f84c3486bb..4b4cbeb51a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -1,7 +1,9 @@ package ethchain import ( + "bytes" "fmt" + "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -236,6 +238,8 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return nil } +var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") + func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block @@ -258,5 +262,46 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by ret, _, err = closure.Call(vm, self.data, nil) deepErr = vm.err != nil + /* + if bytes.Compare(testAddr, context.Address()) == 0 { + trie := context.state.trie + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + fmt.Println("\n\n") + } + */ + + Paranoia := true + if Paranoia { + var ( + trie = context.state.trie + trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + ) + + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + trie2.Update(key, v.Str()) + }) + + a := ethutil.NewValue(trie2.Root).Bytes() + b := ethutil.NewValue(context.state.trie.Root).Bytes() + if bytes.Compare(a, b) != 0 { + fmt.Printf("original: %x\n", trie.Root) + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + + fmt.Printf("new: %x\n", trie2.Root) + trie2.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + fmt.Printf("%x : %x\n", key, v.Str()) + }) + + return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false + } + } + return } diff --git a/ethutil/value.go b/ethutil/value.go index ddd864d8a3..b37b33c28d 100644 --- a/ethutil/value.go +++ b/ethutil/value.go @@ -116,6 +116,8 @@ func (val *Value) Bytes() []byte { return a } else if s, ok := val.Val.(byte); ok { return []byte{s} + } else if s, ok := val.Val.(string); ok { + return []byte(s) } return []byte{} @@ -196,6 +198,12 @@ func (val *Value) Encode() []byte { return Encode(val.Val) } +// Assume that the data we have is encoded +func (self *Value) Decode() { + v, _ := Decode(self.Bytes(), 0) + self.Val = v +} + func NewValueFromBytes(data []byte) *Value { if len(data) != 0 { data, _ := Decode(data, 0) From 9ed0d389b2402baf2dbc90fe12e9b4695ee22858 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 13:34:47 +0200 Subject: [PATCH 0529/1237] Generic trie --- ethutil/trie.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index ce9c2da27c..26a27a901c 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -191,7 +191,17 @@ func (t *Trie) Get(key string) string { } func (t *Trie) Delete(key string) { - t.Update(key, "") + t.mut.Lock() + defer t.mut.Unlock() + + k := CompactHexDecode(key) + + root := t.DeleteState(t.Root, k) + if _, ok := root.([]byte); !ok { + t.Root = t.cache.PutValue(root, true) + } else { + t.Root = root + } } func (t *Trie) GetState(node interface{}, key []int) interface{} { @@ -243,15 +253,7 @@ func (t *Trie) GetNode(node interface{}) *Value { } func (t *Trie) UpdateState(node interface{}, key []int, value string) interface{} { - - if value != "" { - return t.InsertState(node, key, value) - } else { - // delete it - return t.DeleteState(node, key) - } - - return t.Root + return t.InsertState(node, key, value) } func (t *Trie) Put(node interface{}) interface{} { From 82272ee08a7d72be1cc0947b6a0e8096a0353362 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 14:28:54 +0200 Subject: [PATCH 0530/1237] Iterator fix --- ethutil/trie.go | 10 ++++------ ethutil/trie_test.go | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ethutil/trie.go b/ethutil/trie.go index 26a27a901c..c669bdcb04 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -538,15 +538,13 @@ func (it *TrieIterator) fetchNode(key []int, node []byte, cb EachCallback) { } func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallback) { - //fmt.Println("node", currentNode) - if currentNode.Len() == 2 { k := CompactDecode(currentNode.Get(0).Str()) - if currentNode.Get(1).Str() == "" { - it.iterateNode(key, currentNode.Get(1), cb) + pk := append(key, k...) + if currentNode.Get(1).Len() != 0 && currentNode.Get(1).Str() == "" { + it.iterateNode(pk, currentNode.Get(1), cb) } else { - pk := append(key, k...) if k[len(k)-1] == 16 { cb(DecodeCompact(pk), currentNode.Get(1)) @@ -560,7 +558,7 @@ func (it *TrieIterator) iterateNode(key []int, currentNode *Value, cb EachCallba if i == 16 && currentNode.Get(i).Len() != 0 { cb(DecodeCompact(pk), currentNode.Get(i)) } else { - if currentNode.Get(i).Str() == "" { + if currentNode.Get(i).Len() != 0 && currentNode.Get(i).Str() == "" { it.iterateNode(pk, currentNode.Get(i), cb) } else { val := currentNode.Get(i).Str() diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 3ee955b114..d8db8a0d6a 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -261,13 +261,13 @@ func TestTrieReplay(t *testing.T) { _, trie2 := New() trie.NewIterator().Each(func(key string, v *Value) { - trie2.Update(key, string(v.Str())) + trie2.Update(key, v.Str()) }) a := NewValue(trie.Root).Bytes() b := NewValue(trie2.Root).Bytes() if bytes.Compare(a, b) != 0 { - t.Errorf("root %x %x\n", trie.Root, trie2.Root) + t.Errorf("%s %x %x\n", test.Name, trie.Root, trie2.Root) } }) } From ed276cd7c241749a9cf8add4e2fae3d3608a7ea4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 30 Jun 2014 20:03:31 +0200 Subject: [PATCH 0531/1237] Added Paranoia check for VM execution --- ethchain/state.go | 81 ------------------------------------ ethchain/state_manager.go | 8 +++- ethchain/state_test.go | 4 +- ethchain/state_transition.go | 31 +++++++------- ethchain/vm_test.go | 8 ++-- ethutil/trie.go | 18 +++++--- ethutil/trie_test.go | 21 +++++++++- 7 files changed, 57 insertions(+), 114 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index e28b919099..51d86fe2a7 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -204,84 +204,3 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } - -/* - -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, state := range s.states { - state.Reset() - } -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, state := range s.states { - state.Sync() - } - - s.trie.Sync() -} -func (s *State) GetStateObject(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - stateObject := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) - stateObject.state = cachedStateObject - } - - return stateObject -} - -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil && s.states[string(addr)] == nil { - s.states[string(addr)] = object.state - } - - ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) - - s.trie.Update(string(addr), string(object.RlpEncode())) - - s.manifest.AddObjectChange(object) -} - -func (s *State) GetAccount(addr []byte) (account *StateObject) { - data := s.trie.Get(string(addr)) - if data == "" { - account = NewAccount(addr, big.NewInt(0)) - } else { - account = NewStateObjectFromBytes(addr, []byte(data)) - } - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - account.state = cachedStateObject - } - - return -} - -func (s *State) Copy() *State { - state := NewState(s.trie.Copy()) - for k, subState := range s.states { - state.states[k] = subState.Copy() - } - - return state -} -*/ diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 48c6401e30..363aa3da74 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,7 +123,8 @@ done: break done default: - statelogger.Infoln(err) + //statelogger.Infoln(err) + return nil, nil, nil, err } } @@ -236,7 +237,10 @@ func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block - receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + if err != nil { + return nil, err + } return receipts, nil } diff --git a/ethchain/state_test.go b/ethchain/state_test.go index 503bdddb47..95be0f373c 100644 --- a/ethchain/state_test.go +++ b/ethchain/state_test.go @@ -16,12 +16,12 @@ func TestSnapshot(t *testing.T) { state.UpdateStateObject(stateObject) stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) - snapshot := state.Snapshot() + snapshot := state.Copy() stateObject = state.GetStateObject([]byte("aa")) stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) - state.Revert(snapshot) + state.Set(snapshot) stateObject = state.GetStateObject([]byte("aa")) if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 4b4cbeb51a..b180916913 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -226,20 +226,14 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) } - //if self.value.Cmp(ethutil.Big0) > 0 { // 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) - //statelogger.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) - //} - return nil } -var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") - func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error, deepErr bool) { var ( block = self.block @@ -263,6 +257,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by deepErr = vm.err != nil /* + var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") if bytes.Compare(testAddr, context.Address()) == 0 { trie := context.state.trie trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -273,7 +268,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by } */ - Paranoia := true + Paranoia := true // TODO Create a flag for this if Paranoia { var ( trie = context.state.trie @@ -287,17 +282,19 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by a := ethutil.NewValue(trie2.Root).Bytes() b := ethutil.NewValue(context.state.trie.Root).Bytes() if bytes.Compare(a, b) != 0 { - fmt.Printf("original: %x\n", trie.Root) - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) + /* + statelogger.Debugf("(o): %x\n", trie.Root) + trie.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + statelogger.Debugf("%x : %x\n", key, v.Str()) + }) - fmt.Printf("new: %x\n", trie2.Root) - trie2.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) + statelogger.Debugf("(c): %x\n", trie2.Root) + trie2.NewIterator().Each(func(key string, v *ethutil.Value) { + v.Decode() + statelogger.Debugf("%x : %x\n", key, v.Str()) + }) + */ return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false } diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index c569d89ae0..c8023cd790 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -5,9 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" - "github.com/obscuren/mutan" "math/big" - "strings" "testing" ) @@ -17,7 +15,7 @@ func TestRun4(t *testing.T) { db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - callerScript, err := mutan.Compile(strings.NewReader(` + callerScript, err := ethutil.Compile(` this.store[this.origin()] = 10**20 hello := "world" @@ -31,7 +29,7 @@ func TestRun4(t *testing.T) { this.store[to] = this.store[to] + value } } - `), false) + `) if err != nil { fmt.Println(err) } @@ -55,7 +53,7 @@ func TestRun4(t *testing.T) { vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), - BlockNumber: 1, + BlockNumber: big.NewInt(1), PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), Time: 1, diff --git a/ethutil/trie.go b/ethutil/trie.go index c669bdcb04..56f1648a6b 100644 --- a/ethutil/trie.go +++ b/ethutil/trie.go @@ -173,10 +173,13 @@ func (t *Trie) Update(key string, value string) { k := CompactHexDecode(key) root := t.UpdateState(t.Root, k, value) - if _, ok := root.([]byte); !ok { - t.Root = t.cache.PutValue(root, true) - } else { + switch root.(type) { + case string: t.Root = root + case []byte: + t.Root = root + default: + t.Root = t.cache.PutValue(root, true) } } @@ -197,10 +200,13 @@ func (t *Trie) Delete(key string) { k := CompactHexDecode(key) root := t.DeleteState(t.Root, k) - if _, ok := root.([]byte); !ok { - t.Root = t.cache.PutValue(root, true) - } else { + switch root.(type) { + case string: t.Root = root + case []byte: + t.Root = root + default: + t.Root = t.cache.PutValue(root, true) } } diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index d8db8a0d6a..542af5504a 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -242,7 +242,6 @@ func TestRemote(t *testing.T) { for key, value := range test.In { trie.Update(get(key), get(value)) } - fmt.Printf("%-15s: %x\n", test.Name, trie.Root) a := NewValue(h(test.Root)).Bytes() b := NewValue(trie.Root).Bytes() @@ -271,3 +270,23 @@ func TestTrieReplay(t *testing.T) { } }) } + +func TestIt(t *testing.T) { + _, trie := New() + + test := map[string]string{ + "0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1": "0x4e616d6552656700000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000045": "0x22b224a1420a802ab51d326e29fa98e34c4f24ea", + "0x0000000000000000000000000000000000000000000000000000000000000046": "0x67706c2076330000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6": "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", + "0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2": "0x4655474156000000000000000000000000000000000000000000000000000000", + "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000": "0x697c7b8c961b56f675d570498424ac8de1a918f6", + "0x4655474156000000000000000000000000000000000000000000000000000000": "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2", + "0x4e616d6552656700000000000000000000000000000000000000000000000000": "0xec4f34c97e43fbb2816cfd95e388353c7181dab1", + } + + for k, v := range test { + trie.Update(k, v) + } + fmt.Printf("root : %x\n", trie.Root) +} From 5f5910c603c107ceaf5f240f9ca23cbf9c951f67 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 09:55:20 +0200 Subject: [PATCH 0532/1237] Regression test for trie --- ethutil/trie_test.go | 72 +++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 542af5504a..85d81b6f4c 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -6,9 +6,11 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/rand" "net/http" "reflect" "testing" + "time" ) const LONG_WORD = "1234567890abcdefghijklmnopqrstuvwxxzABCEFGHIJKLMNOPQRSTUVWXYZ" @@ -211,7 +213,7 @@ func CreateTest(name string, data []byte) (Test, error) { return t, nil } -func CreateTests(uri string, cb func(Test)) { +func CreateTests(uri string, cb func(Test)) map[string]Test { resp, err := http.Get(uri) if err != nil { panic(err) @@ -226,14 +228,20 @@ func CreateTests(uri string, cb func(Test)) { panic(err) } + tests := make(map[string]Test) for name, testData := range objmap { test, err := CreateTest(name, *testData) if err != nil { panic(err) } - cb(test) + if cb != nil { + cb(test) + } + tests[name] = test } + + return tests } func TestRemote(t *testing.T) { @@ -271,22 +279,52 @@ func TestTrieReplay(t *testing.T) { }) } -func TestIt(t *testing.T) { - _, trie := New() - - test := map[string]string{ - "0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1": "0x4e616d6552656700000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000045": "0x22b224a1420a802ab51d326e29fa98e34c4f24ea", - "0x0000000000000000000000000000000000000000000000000000000000000046": "0x67706c2076330000000000000000000000000000000000000000000000000000", - "0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6": "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", - "0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2": "0x4655474156000000000000000000000000000000000000000000000000000000", - "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000": "0x697c7b8c961b56f675d570498424ac8de1a918f6", - "0x4655474156000000000000000000000000000000000000000000000000000000": "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2", - "0x4e616d6552656700000000000000000000000000000000000000000000000000": "0xec4f34c97e43fbb2816cfd95e388353c7181dab1", +func RandomData() [][]string { + data := [][]string{ + {"0x000000000000000000000000ec4f34c97e43fbb2816cfd95e388353c7181dab1", "0x4e616d6552656700000000000000000000000000000000000000000000000000"}, + {"0x0000000000000000000000000000000000000000000000000000000000000045", "0x22b224a1420a802ab51d326e29fa98e34c4f24ea"}, + {"0x0000000000000000000000000000000000000000000000000000000000000046", "0x67706c2076330000000000000000000000000000000000000000000000000000"}, + {"0x000000000000000000000000697c7b8c961b56f675d570498424ac8de1a918f6", "0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000"}, + {"0x0000000000000000000000007ef9e639e2733cb34e4dfc576d4b23f72db776b2", "0x4655474156000000000000000000000000000000000000000000000000000000"}, + {"0x6f6f6f6820736f2067726561742c207265616c6c6c793f000000000000000000", "0x697c7b8c961b56f675d570498424ac8de1a918f6"}, + {"0x4655474156000000000000000000000000000000000000000000000000000000", "0x7ef9e639e2733cb34e4dfc576d4b23f72db776b2"}, + {"0x4e616d6552656700000000000000000000000000000000000000000000000000", "0xec4f34c97e43fbb2816cfd95e388353c7181dab1"}, } - for k, v := range test { - trie.Update(k, v) + var c [][]string + for len(data) != 0 { + e := rand.Intn(len(data)) + c = append(c, data[e]) + + copy(data[e:], data[e+1:]) + data[len(data)-1] = nil + data = data[:len(data)-1] + } + + return c +} + +const MaxTest = 1000 + +// This test insert data in random order and seeks to find indifferences between the different tries +func TestRegression(t *testing.T) { + rand.Seed(time.Now().Unix()) + + roots := make(map[string]int) + for i := 0; i < MaxTest; i++ { + _, trie := New() + data := RandomData() + + for _, test := range data { + trie.Update(test[0], test[1]) + } + + roots[string(trie.Root.([]byte))] += 1 + } + + if len(roots) > 1 { + for root, num := range roots { + t.Errorf("%x => %d\n", root, num) + } } - fmt.Printf("root : %x\n", trie.Root) } From 39263b674c1a8a13a1c29349a48b3cdc4c5948db Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 09:56:10 +0200 Subject: [PATCH 0533/1237] Paranoia --- ethchain/state_transition.go | 2 +- ethutil/config.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index b180916913..6837f92f7a 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -268,7 +268,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by } */ - Paranoia := true // TODO Create a flag for this + Paranoia := ethutil.Config.Paranoia if Paranoia { var ( trie = context.state.trie diff --git a/ethutil/config.go b/ethutil/config.go index b253aa203a..6ebb5e8cd2 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -14,6 +14,7 @@ type config struct { ExecPath string Debug bool + Paranoia bool Ver string ClientString string Pubkey []byte @@ -44,7 +45,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier, Paranoia: true} Config.SetClientString("Ethereum(G)") } return Config From 92693e44599c44e606813d2c3259cc9f6f81a644 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 11:26:45 +0200 Subject: [PATCH 0534/1237] The dragon has been slain. Consensus reached! --- ethchain/state.go | 2 +- ethchain/state_manager.go | 5 +++-- ethchain/state_transition.go | 30 ++++++++++++++---------------- ethchain/vm.go | 29 +++++++++++++++++++++++++++-- ethutil/trie_test.go | 1 + 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/ethchain/state.go b/ethchain/state.go index 51d86fe2a7..06a185f592 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -125,7 +125,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - statelogger.Infof("(+) %x\n", addr) + //statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 363aa3da74..b0550607fa 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -123,8 +123,9 @@ done: break done default: - //statelogger.Infoln(err) - return nil, nil, nil, err + statelogger.Infoln(err) + err = nil + //return nil, nil, nil, err } } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6837f92f7a..94c3de3d94 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -253,26 +253,22 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by Value: self.value, }) vm.Verbose = true - ret, _, err = closure.Call(vm, self.data, nil) - deepErr = vm.err != nil - /* - var testAddr = ethutil.FromHex("ec4f34c97e43fbb2816cfd95e388353c7181dab1") - if bytes.Compare(testAddr, context.Address()) == 0 { - trie := context.state.trie - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - v.Decode() - fmt.Printf("%x : %x\n", key, v.Str()) - }) - fmt.Println("\n\n") - } - */ + ret, err, deepErr = Call(vm, closure, self.data) + + return +} + +func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr bool) { + ret, _, err = closure.Call(vm, data, nil) + deepErr = vm.err != nil Paranoia := ethutil.Config.Paranoia if Paranoia { var ( - trie = context.state.trie - trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + context = closure.object + trie = context.state.trie + trie2 = ethutil.NewTrie(ethutil.Config.Db, "") ) trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -282,6 +278,8 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by a := ethutil.NewValue(trie2.Root).Bytes() b := ethutil.NewValue(context.state.trie.Root).Bytes() if bytes.Compare(a, b) != 0 { + // TODO FIXME ASAP + context.state.trie = trie2 /* statelogger.Debugf("(o): %x\n", trie.Root) trie.NewIterator().Each(func(key string, v *ethutil.Value) { @@ -296,7 +294,7 @@ func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []by }) */ - return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false + //return nil, fmt.Errorf("PARANOIA: Different state object roots during copy"), false } } diff --git a/ethchain/vm.go b/ethchain/vm.go index 82591e2745..3851d0d701 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -346,6 +346,29 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigFalse) } + + case SLT: + require(2) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) + // x < y + if y.Cmp(x) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case SGT: + require(2) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case EQ: require(2) x, y := stack.Popn() @@ -660,7 +683,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Create a new callable closure closure := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) + //ret, _, err := closure.Call(vm, args, hook) + ret, err, _ := Call(vm, closure, args) if err != nil { stack.Push(ethutil.BigFalse) @@ -699,7 +723,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro return closure.Return(nil), nil default: - vmlogger.Debugf("Invalid opcode %x\n", op) + vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) + fmt.Println(Code(closure.Script)) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } diff --git a/ethutil/trie_test.go b/ethutil/trie_test.go index 85d81b6f4c..01207dbc3b 100644 --- a/ethutil/trie_test.go +++ b/ethutil/trie_test.go @@ -318,6 +318,7 @@ func TestRegression(t *testing.T) { for _, test := range data { trie.Update(test[0], test[1]) } + trie.Delete("0x4e616d6552656700000000000000000000000000000000000000000000000000") roots[string(trie.Root.([]byte))] += 1 } From 2bbc204328cf674e8ccd591bb4d08179225b396a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 11:55:50 +0200 Subject: [PATCH 0535/1237] Close pow chat. Fixes #95 --- ethminer/miner.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethminer/miner.go b/ethminer/miner.go index 66388723ec..71d4b2428a 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -130,7 +130,9 @@ out: func (self *Miner) Stop() { logger.Infoln("Stopping...") self.quitChan <- true - self.powQuitChan <- ethutil.React{} + + close(self.powQuitChan) + close(self.quitChan) } func (self *Miner) mineNewBlock() { From 0ce9003ba77c0552c9058caa55d2fea6711ac18c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 12:16:14 +0200 Subject: [PATCH 0536/1237] Fix for creating a tx from an unknown account --- ethpub/pub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index 1bc9e0ce7d..250ba71f3d 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -216,7 +216,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) } - acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) + acc := lib.stateManager.TransState().GetOrNewStateObject(keyPair.Address()) tx.Nonce = acc.Nonce acc.Nonce += 1 lib.stateManager.TransState().UpdateStateObject(acc) From e798294a4b2049dc59df6ad4a3bc67c00916cb9f Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 1 Jul 2014 15:25:57 +0200 Subject: [PATCH 0537/1237] Update min GasLimit --- ethchain/block.go | 2 +- ethchain/dagger.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ethchain/block.go b/ethchain/block.go index fee4a2d59c..1be8282fa0 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -166,7 +166,7 @@ func (block *Block) CalcGasLimit(parent *Block) *big.Int { result := new(big.Int).Add(previous, curInt) result.Div(result, big.NewInt(1024)) - min := ethutil.BigPow(10, 4) + min := big.NewInt(125000) return ethutil.BigMax(min, result) /* diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 08c4826dbf..b586657b90 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -31,6 +31,7 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: + powlogger.Infoln("Breaking from mining") return nil default: i++ From d0959063d5f67dccc214f43344d88dce25ca167f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 15:28:12 +0200 Subject: [PATCH 0538/1237] Up --- ethchain/block_chain.go | 2 +- peer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 6e4c72b278..ef56d674c6 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -271,7 +271,7 @@ func AddTestNetFunds(block *Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", "6c386a4b26f73c802f34673f7248bb118f97424a", "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", "2ef47100e0787b915105fd5e3f4ff6752079d5cb", diff --git a/peer.go b/peer.go index e50fd43f93..884e296f64 100644 --- a/peer.go +++ b/peer.go @@ -21,7 +21,7 @@ const ( // The size of the output buffer for writing messages outputBufferSize = 50 // Current protocol version - ProtocolVersion = 20 + ProtocolVersion = 21 // Interval for ping/pong message pingPongTimer = 2 * time.Second ) From ff5703fd9b089de67811af61de05637c62dc7a2c Mon Sep 17 00:00:00 2001 From: zelig Date: Tue, 1 Jul 2014 15:09:43 +0100 Subject: [PATCH 0539/1237] ethutil -> ethtrie.NewTrie --- ethchain/state_object.go | 2 +- ethchain/state_transition.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 7c9430af21..35928c8996 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -51,7 +51,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { func NewStateObject(addr []byte) *StateObject { object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} - object.state = NewState(ethutil.NewTrie(ethutil.Config.Db, "")) + object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) return object } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 94c3de3d94..c382bcd605 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -3,6 +3,7 @@ package ethchain import ( "bytes" "fmt" + "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -268,7 +269,7 @@ func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error, deepErr var ( context = closure.object trie = context.state.trie - trie2 = ethutil.NewTrie(ethutil.Config.Db, "") + trie2 = ethtrie.NewTrie(ethutil.Config.Db, "") ) trie.NewIterator().Each(func(key string, v *ethutil.Value) { From 7a9ff4f8d45e741625bc32fde59b3dfe90851492 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 16:28:17 +0200 Subject: [PATCH 0540/1237] bump --- README.md | 2 +- ethutil/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 26783d12d6..3ef9bba709 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 0.5.15". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 0.5.16". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethutil/config.go b/ethutil/config.go index 675175cdd6..d716005b50 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -44,7 +44,7 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.15", conf: g, Identifier: Identifier, Paranoia: true} + Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.16", conf: g, Identifier: Identifier, Paranoia: true} Config.SetClientString("Ethereum(G)") } return Config From 3889785017a1381d215cb1dc47fd5fb5b38add79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:08:18 +0200 Subject: [PATCH 0541/1237] Added Path utility --- ethutil/path.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 ethutil/path.go diff --git a/ethutil/path.go b/ethutil/path.go new file mode 100644 index 0000000000..97f58ab7e5 --- /dev/null +++ b/ethutil/path.go @@ -0,0 +1,20 @@ +package ethutil + +import ( + "os/user" + "strings" +) + +func ExpandHomePath(p string) (path string) { + path = p + + // Check in case of paths like "/something/~/something/" + if path[:2] == "~/" { + usr, _ := user.Current() + dir := usr.HomeDir + + path = strings.Replace(p, "~", dir, 1) + } + + return +} From 6151ae7db5251436e9ece190eb3569d4aa882671 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:08:32 +0200 Subject: [PATCH 0542/1237] Fixed key import for empty entries --- ethcrypto/keyring.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ethcrypto/keyring.go b/ethcrypto/keyring.go index 277fa2134a..d3399d13d5 100644 --- a/ethcrypto/keyring.go +++ b/ethcrypto/keyring.go @@ -74,8 +74,12 @@ func NewKeyRingFromString(content string) (*KeyRing, error) { } else if len(words) != 1 { return nil, fmt.Errorf("Unrecognised key format") } - secrets = append(secrets, ethutil.Hex2Bytes(secret)) + + if len(secret) != 0 { + secrets = append(secrets, ethutil.Hex2Bytes(secret)) + } } + return NewKeyRingFromSecrets(secrets) } From 28ef7d228c4e8e24315eb585e4e0d03a4c652ccb Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:08:48 +0200 Subject: [PATCH 0543/1237] Added Left and Right padding utility functions --- ethutil/bytes.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ethutil/bytes.go b/ethutil/bytes.go index c2817946bf..5737a75c9e 100644 --- a/ethutil/bytes.go +++ b/ethutil/bytes.go @@ -118,7 +118,8 @@ func FormatData(data string) []byte { // Simple stupid d := new(big.Int) if data[0:1] == "\"" && data[len(data)-1:] == "\"" { - d.SetBytes([]byte(data[1 : len(data)-1])) + return RightPadBytes([]byte(data), 32) + //d.SetBytes([]byte(data[1 : len(data)-1])) } else if len(data) > 1 && data[:2] == "0x" { d.SetBytes(Hex2Bytes(data[2:])) } else { @@ -127,3 +128,25 @@ func FormatData(data string) []byte { return BigToBytes(d, 256) } + +func LeftPadBytes(slice []byte, l int) []byte { + if l <= len(slice) { + return slice + } + + padded := make([]byte, l) + copy(padded[0:len(slice)], slice) + + return padded +} + +func RightPadBytes(slice []byte, l int) []byte { + if l <= len(slice) { + return slice + } + + padded := make([]byte, l) + copy(padded[l-len(slice):], slice) + + return padded +} From 7a2a63f32b209f0358fa6be1e76b49319d8f309f Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:09:21 +0200 Subject: [PATCH 0544/1237] Added utility wrapper for Ethereum Config contract Note, this utility function has to move elsewhere --- ethpub/pub.go | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/ethpub/pub.go b/ethpub/pub.go index ee41408996..5852f93be3 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -14,6 +14,31 @@ import ( var logger = ethlog.NewLogger("PUB") +// TODO this has to move elsewhere +var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") + +type helper struct { + sm *ethchain.StateManager +} + +func EthereumConfig(stateManager *ethchain.StateManager) helper { + return helper{stateManager} +} +func (self helper) obj() *ethchain.StateObject { + return self.sm.CurrentState().GetStateObject(cnfCtr) +} + +func (self helper) NameReg() *ethchain.StateObject { + if self.obj() != nil { + addr := self.obj().GetStorage(big.NewInt(0)) + if len(addr.Bytes()) > 0 { + return self.sm.CurrentState().GetStateObject(addr.Bytes()) + } + } + + return nil +} + type PEthereum struct { manager ethchain.EthManager stateManager *ethchain.StateManager @@ -141,19 +166,31 @@ func (lib *PEthereum) Create(key, valueStr, gasStr, gasPriceStr, script string) return lib.createTx(key, "", valueStr, gasStr, gasPriceStr, script) } -var namereg = ethutil.Hex2Bytes("bb5f186604d057c1c5240ca2ae0f6430138ac010") - func GetAddressFromNameReg(stateManager *ethchain.StateManager, name string) []byte { - recp := new(big.Int).SetBytes([]byte(name)) - object := stateManager.CurrentState().GetStateObject(namereg) - if object != nil { - reg := object.GetStorage(recp) + nameReg := EthereumConfig(stateManager).NameReg() + if nameReg != nil { + addr := ethutil.RightPadBytes([]byte(name), 32) + + reg := nameReg.GetStorage(ethutil.BigD(addr)) return reg.Bytes() } return nil + + /* + recp := new(big.Int).SetBytes([]byte(name)) + object := stateManager.CurrentState().GetStateObject(namereg) + if object != nil { + reg := object.GetStorage(recp) + + return reg.Bytes() + } + + return nil + */ } + func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, scriptStr string) (*PReceipt, error) { var hash []byte var contractCreation bool @@ -171,7 +208,7 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, sc var keyPair *ethcrypto.KeyPair var err error - if key[0:2] == "0x" { + if ethutil.IsHex(key) { keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:]))) } else { keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key))) From dd869064a678918544678c9cb8413d1e9a94de89 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 1 Jul 2014 20:09:37 +0200 Subject: [PATCH 0545/1237] delete? --- ethereal/Makefile | 22 - ethereal/assets/debugger/debugger.qml | 270 - ethereal/assets/ext/big.js | 380 - ethereal/assets/ext/ethereum.js | 145 - ethereal/assets/ext/pre.js | 58 - ethereal/assets/ext/string.js | 58 - ethereal/assets/facet.png | Bin 27302 -> 0 bytes ethereal/assets/heart.png | Bin 4277 -> 0 bytes ethereal/assets/muted/codemirror.css | 272 - ethereal/assets/muted/debugger.html | 53 - ethereal/assets/muted/eclipse.css | 23 - ethereal/assets/muted/index.html | 80 - ethereal/assets/muted/lib/codemirror.js | 7526 ----------------- ethereal/assets/muted/lib/go.js | 182 - ethereal/assets/muted/lib/matchbrackets.js | 117 - ethereal/assets/muted/muted.js | 61 - ethereal/assets/net.png | Bin 4669 -> 0 bytes ethereal/assets/network.png | Bin 2900 -> 0 bytes ethereal/assets/new.png | Bin 4776 -> 0 bytes ethereal/assets/qml/QmlApp.qml | 22 - ethereal/assets/qml/first_run.qml | 155 - ethereal/assets/qml/muted.qml | 74 - ethereal/assets/qml/test_app.qml | 70 - ethereal/assets/qml/transactions.qml | 9 - ethereal/assets/qml/wallet.qml | 1075 --- ethereal/assets/qml/webapp.qml | 246 - .../assets/samplecoin/bootstrap-theme.min.css | 7 - ethereal/assets/samplecoin/bootstrap.min.css | 7 - ethereal/assets/samplecoin/icon.png | Bin 86700 -> 0 bytes ethereal/assets/samplecoin/samplecoin.css | 34 - ethereal/assets/samplecoin/samplecoin.html | 68 - ethereal/assets/tx.png | Bin 4070 -> 0 bytes ethereal/assets/util/test.html | 43 - ethereal/flags.go | 99 - ethereal/main.go | 66 - ethereal/ui/debugger.go | 234 - ethereal/ui/ext_app.go | 132 - ethereal/ui/gui.go | 405 - ethereal/ui/html_container.go | 133 - ethereal/ui/qml_app.go | 59 - ethereal/ui/ui_lib.go | 100 - ethereum/cmd.go | 32 - ethereum/flags.go | 76 - ethereum/javascript_runtime.go | 231 - ethereum/js_lib.go | 53 - ethereum/main.go | 57 - ethereum/repl.go | 153 - ethereum/repl_darwin.go | 123 - ethereum/repl_linux.go | 1 - ethereum/repl_windows.go | 24 - utils/cmd.go | 253 - 51 files changed, 13288 deletions(-) delete mode 100644 ethereal/Makefile delete mode 100644 ethereal/assets/debugger/debugger.qml delete mode 100644 ethereal/assets/ext/big.js delete mode 100644 ethereal/assets/ext/ethereum.js delete mode 100644 ethereal/assets/ext/pre.js delete mode 100644 ethereal/assets/ext/string.js delete mode 100644 ethereal/assets/facet.png delete mode 100644 ethereal/assets/heart.png delete mode 100644 ethereal/assets/muted/codemirror.css delete mode 100644 ethereal/assets/muted/debugger.html delete mode 100644 ethereal/assets/muted/eclipse.css delete mode 100644 ethereal/assets/muted/index.html delete mode 100644 ethereal/assets/muted/lib/codemirror.js delete mode 100644 ethereal/assets/muted/lib/go.js delete mode 100644 ethereal/assets/muted/lib/matchbrackets.js delete mode 100644 ethereal/assets/muted/muted.js delete mode 100644 ethereal/assets/net.png delete mode 100644 ethereal/assets/network.png delete mode 100644 ethereal/assets/new.png delete mode 100644 ethereal/assets/qml/QmlApp.qml delete mode 100644 ethereal/assets/qml/first_run.qml delete mode 100644 ethereal/assets/qml/muted.qml delete mode 100644 ethereal/assets/qml/test_app.qml delete mode 100644 ethereal/assets/qml/transactions.qml delete mode 100644 ethereal/assets/qml/wallet.qml delete mode 100644 ethereal/assets/qml/webapp.qml delete mode 100755 ethereal/assets/samplecoin/bootstrap-theme.min.css delete mode 100755 ethereal/assets/samplecoin/bootstrap.min.css delete mode 100644 ethereal/assets/samplecoin/icon.png delete mode 100644 ethereal/assets/samplecoin/samplecoin.css delete mode 100644 ethereal/assets/samplecoin/samplecoin.html delete mode 100644 ethereal/assets/tx.png delete mode 100644 ethereal/assets/util/test.html delete mode 100644 ethereal/flags.go delete mode 100644 ethereal/main.go delete mode 100644 ethereal/ui/debugger.go delete mode 100644 ethereal/ui/ext_app.go delete mode 100644 ethereal/ui/gui.go delete mode 100644 ethereal/ui/html_container.go delete mode 100644 ethereal/ui/qml_app.go delete mode 100644 ethereal/ui/ui_lib.go delete mode 100644 ethereum/cmd.go delete mode 100644 ethereum/flags.go delete mode 100644 ethereum/javascript_runtime.go delete mode 100644 ethereum/js_lib.go delete mode 100644 ethereum/main.go delete mode 100644 ethereum/repl.go delete mode 100644 ethereum/repl_darwin.go delete mode 120000 ethereum/repl_linux.go delete mode 100644 ethereum/repl_windows.go delete mode 100644 utils/cmd.go diff --git a/ethereal/Makefile b/ethereal/Makefile deleted file mode 100644 index 1acf030493..0000000000 --- a/ethereal/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -UNAME = $(shell uname) -FILES=qml *.png -GOPATH=$(PWD) - - -# Default is building -all: - go get -d - cp *.go $(GOPATH)/src/github.com/ethereum/go-ethereum - cp -r ui $(GOPATH)/src/github.com/ethereum/go-ethereum - go build - -install: -# Linux build -ifeq ($(UNAME),Linux) - cp -r assets/* /usr/share/ethereal - cp go-ethereum /usr/local/bin/ethereal -endif -# OS X build -ifeq ($(UNAME),Darwin) - # Execute py script -endif diff --git a/ethereal/assets/debugger/debugger.qml b/ethereal/assets/debugger/debugger.qml deleted file mode 100644 index 3e653882c8..0000000000 --- a/ethereal/assets/debugger/debugger.qml +++ /dev/null @@ -1,270 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Controls 1.0; -import QtQuick.Layouts 1.0; -import QtQuick.Dialogs 1.0; -import QtQuick.Window 2.1; -import QtQuick.Controls.Styles 1.1 -import Ethereum 1.0 - -ApplicationWindow { - visible: false - title: "IceCREAM" - minimumWidth: 1280 - minimumHeight: 700 - width: 1290 - height: 700 - - property alias codeText: codeEditor.text - property alias dataText: rawDataField.text - - MenuBar { - Menu { - title: "Debugger" - MenuItem { - text: "Run" - shortcut: "Ctrl+r" - onTriggered: debugCurrent() - } - - MenuItem { - text: "Next" - shortcut: "Ctrl+n" - onTriggered: dbg.next() - } - } - } - - SplitView { - anchors.fill: parent - property var asmModel: ListModel { - id: asmModel - } - TableView { - id: asmTableView - width: 200 - TableViewColumn{ role: "value" ; title: "" ; width: 200 } - model: asmModel - } - - Rectangle { - color: "#00000000" - anchors.left: asmTableView.right - anchors.right: parent.right - SplitView { - orientation: Qt.Vertical - anchors.fill: parent - - Rectangle { - color: "#00000000" - height: 330 - anchors.left: parent.left - anchors.right: parent.right - - TextArea { - id: codeEditor - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: settings.left - } - - Column { - id: settings - spacing: 5 - width: 300 - height: parent.height - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - - Label { - text: "Arbitrary data" - } - TextArea { - id: rawDataField - anchors.left: parent.left - anchors.right: parent.right - height: 150 - } - - Label { - text: "Amount" - } - TextField { - id: txValue - width: 200 - placeholderText: "Amount" - validator: RegExpValidator { regExp: /\d*/ } - } - Label { - text: "Amount of gas" - } - TextField { - id: txGas - width: 200 - validator: RegExpValidator { regExp: /\d*/ } - text: "10000" - placeholderText: "Gas" - } - Label { - text: "Gas price" - } - TextField { - id: txGasPrice - width: 200 - placeholderText: "Gas price" - text: "1000000000000" - validator: RegExpValidator { regExp: /\d*/ } - } - } - } - - SplitView { - orientation: Qt.Vertical - id: inspectorPane - height: 500 - - SplitView { - orientation: Qt.Horizontal - height: 150 - - TableView { - id: stackTableView - property var stackModel: ListModel { - id: stackModel - } - height: parent.height - width: 300 - TableViewColumn{ role: "value" ; title: "Temp" ; width: 200 } - model: stackModel - } - - TableView { - id: memoryTableView - property var memModel: ListModel { - id: memModel - } - height: parent.height - width: parent.width - stackTableView.width - TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50} - TableViewColumn{ role: "value" ; title: "Memory" ; width: 750} - model: memModel - } - } - - Rectangle { - height: 100 - width: parent.width - TableView { - id: storageTableView - property var memModel: ListModel { - id: storageModel - } - height: parent.height - width: parent.width - TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2} - TableViewColumn{ role: "value" ; title: "Storage" ; width: storageTableView.width / 2} - model: storageModel - } - } - - Rectangle { - height: 200 - width: parent.width - TableView { - id: logTableView - property var logModel: ListModel { - id: logModel - } - height: parent.height - width: parent.width - TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width } - model: logModel - } - } - } - } - } - } - - toolBar: ToolBar { - RowLayout { - spacing: 5 - - Button { - property var enabled: true - id: debugStart - onClicked: { - debugCurrent() - } - text: "Debug" - } - - Button { - property var enabled: true - id: debugNextButton - onClicked: { - dbg.next() - } - text: "Next" - } - CheckBox { - id: breakEachLine - objectName: "breakEachLine" - text: "Break each instruction" - checked: true - } - } - } - - function debugCurrent() { - dbg.debug(txValue.text, txGas.text, txGasPrice.text, codeEditor.text, rawDataField.text) - } - - function setAsm(asm) { - asmModel.append({asm: asm}) - } - - function clearAsm() { - asmModel.clear() - } - - function setInstruction(num) { - asmTableView.selection.clear() - asmTableView.selection.select(num) - } - - function setMem(mem) { - memModel.append({num: mem.num, value: mem.value}) - } - function clearMem(){ - memModel.clear() - } - - function setStack(stack) { - stackModel.append({value: stack}) - } - function addDebugMessage(message){ - debuggerLog.append({value: message}) - } - - function clearStack() { - stackModel.clear() - } - - function clearStorage() { - storageModel.clear() - } - - function setStorage(storage) { - storageModel.append({key: storage.key, value: storage.value}) - } - - function setLog(msg) { - logModel.insert(0, {message: msg}) - } - - function clearLog() { - logModel.clear() - } -} diff --git a/ethereal/assets/ext/big.js b/ethereal/assets/ext/big.js deleted file mode 100644 index db633fd2f2..0000000000 --- a/ethereal/assets/ext/big.js +++ /dev/null @@ -1,380 +0,0 @@ -var bigInt = (function () { - var base = 10000000, logBase = 7; - var sign = { - positive: false, - negative: true - }; - - var normalize = function (first, second) { - var a = first.value, b = second.value; - var length = a.length > b.length ? a.length : b.length; - for (var i = 0; i < length; i++) { - a[i] = a[i] || 0; - b[i] = b[i] || 0; - } - for (var i = length - 1; i >= 0; i--) { - if (a[i] === 0 && b[i] === 0) { - a.pop(); - b.pop(); - } else break; - } - if (!a.length) a = [0], b = [0]; - first.value = a; - second.value = b; - }; - - var parse = function (text, first) { - if (typeof text === "object") return text; - text += ""; - var s = sign.positive, value = []; - if (text[0] === "-") { - s = sign.negative; - text = text.slice(1); - } - var base = 10; - if (text.slice(0, 2) == "0x") { - base = 16; - text = text.slice(2); - } - else { - var texts = text.split("e"); - if (texts.length > 2) throw new Error("Invalid integer"); - if (texts[1]) { - var exp = texts[1]; - if (exp[0] === "+") exp = exp.slice(1); - exp = parse(exp); - if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers"); - while (exp.notEquals(0)) { - texts[0] += "0"; - exp = exp.prev(); - } - } - text = texts[0]; - } - if (text === "-0") text = "0"; - text = text.toUpperCase(); - var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text); - if (!isValid) throw new Error("Invalid integer"); - if (base == 16) { - var val = bigInt(0); - while (text.length) { - v = text.charCodeAt(0) - 48; - if (v > 9) - v -= 7; - text = text.slice(1); - val = val.times(16).plus(v); - } - return val; - } - else { - while (text.length) { - var divider = text.length > logBase ? text.length - logBase : 0; - value.push(+text.slice(divider)); - text = text.slice(0, divider); - } - var val = bigInt(value, s); - if (first) normalize(first, val); - return val; - } - }; - - var goesInto = function (a, b) { - var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive); - if (a.equals(0)) throw new Error("Cannot divide by 0"); - var n = 0; - do { - var inc = 1; - var c = bigInt(a.value, sign.positive), t = c.times(10); - while (t.lesser(b)) { - c = t; - inc *= 10; - t = t.times(10); - } - while (c.lesserOrEquals(b)) { - b = b.minus(c); - n += inc; - } - } while (a.lesserOrEquals(b)); - - return { - remainder: b.value, - result: n - }; - }; - - var bigInt = function (value, s) { - var self = { - value: value, - sign: s - }; - var o = { - value: value, - sign: s, - negate: function (m) { - var first = m || self; - return bigInt(first.value, !first.sign); - }, - abs: function (m) { - var first = m || self; - return bigInt(first.value, sign.positive); - }, - add: function (n, m) { - var s, first = self, second; - if (m) (first = parse(n)) && (second = parse(m)); - else second = parse(n, first); - s = first.sign; - if (first.sign !== second.sign) { - first = bigInt(first.value, sign.positive); - second = bigInt(second.value, sign.positive); - return s === sign.positive ? - o.subtract(first, second) : - o.subtract(second, first); - } - normalize(first, second); - var a = first.value, b = second.value; - var result = [], - carry = 0; - for (var i = 0; i < a.length || carry > 0; i++) { - var sum = (a[i] || 0) + (b[i] || 0) + carry; - carry = sum >= base ? 1 : 0; - sum -= carry * base; - result.push(sum); - } - return bigInt(result, s); - }, - plus: function (n, m) { - return o.add(n, m); - }, - subtract: function (n, m) { - var first = self, second; - if (m) (first = parse(n)) && (second = parse(m)); - else second = parse(n, first); - if (first.sign !== second.sign) return o.add(first, o.negate(second)); - if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first)); - if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first)); - var a = first.value, b = second.value; - var result = [], - borrow = 0; - for (var i = 0; i < a.length; i++) { - var tmp = a[i] - borrow; - borrow = tmp < b[i] ? 1 : 0; - var minuend = (borrow * base) + tmp - b[i]; - result.push(minuend); - } - return bigInt(result, sign.positive); - }, - minus: function (n, m) { - return o.subtract(n, m); - }, - multiply: function (n, m) { - var s, first = self, second; - if (m) (first = parse(n)) && (second = parse(m)); - else second = parse(n, first); - s = first.sign !== second.sign; - var a = first.value, b = second.value; - var resultSum = []; - for (var i = 0; i < a.length; i++) { - resultSum[i] = []; - var j = i; - while (j--) { - resultSum[i].push(0); - } - } - var carry = 0; - for (var i = 0; i < a.length; i++) { - var x = a[i]; - for (var j = 0; j < b.length || carry > 0; j++) { - var y = b[j]; - var product = y ? (x * y) + carry : carry; - carry = product > base ? Math.floor(product / base) : 0; - product -= carry * base; - resultSum[i].push(product); - } - } - var max = -1; - for (var i = 0; i < resultSum.length; i++) { - var len = resultSum[i].length; - if (len > max) max = len; - } - var result = [], carry = 0; - for (var i = 0; i < max || carry > 0; i++) { - var sum = carry; - for (var j = 0; j < resultSum.length; j++) { - sum += resultSum[j][i] || 0; - } - carry = sum > base ? Math.floor(sum / base) : 0; - sum -= carry * base; - result.push(sum); - } - return bigInt(result, s); - }, - times: function (n, m) { - return o.multiply(n, m); - }, - divmod: function (n, m) { - var s, first = self, second; - if (m) (first = parse(n)) && (second = parse(m)); - else second = parse(n, first); - s = first.sign !== second.sign; - if (bigInt(first.value, first.sign).equals(0)) return { - quotient: bigInt([0], sign.positive), - remainder: bigInt([0], sign.positive) - }; - if (second.equals(0)) throw new Error("Cannot divide by zero"); - var a = first.value, b = second.value; - var result = [], remainder = []; - for (var i = a.length - 1; i >= 0; i--) { - var n = [a[i]].concat(remainder); - var quotient = goesInto(b, n); - result.push(quotient.result); - remainder = quotient.remainder; - } - result.reverse(); - return { - quotient: bigInt(result, s), - remainder: bigInt(remainder, first.sign) - }; - }, - divide: function (n, m) { - return o.divmod(n, m).quotient; - }, - over: function (n, m) { - return o.divide(n, m); - }, - mod: function (n, m) { - return o.divmod(n, m).remainder; - }, - pow: function (n, m) { - var first = self, second; - if (m) (first = parse(n)) && (second = parse(m)); - else second = parse(n, first); - var a = first, b = second; - if (b.lesser(0)) return ZERO; - if (b.equals(0)) return ONE; - var result = bigInt(a.value, a.sign); - - if (b.mod(2).equals(0)) { - var c = result.pow(b.over(2)); - return c.times(c); - } else { - return result.times(result.pow(b.minus(1))); - } - }, - next: function (m) { - var first = m || self; - return o.add(first, 1); - }, - prev: function (m) { - var first = m || self; - return o.subtract(first, 1); - }, - compare: function (n, m) { - var first = self, second; - if (m) (first = parse(n)) && (second = parse(m, first)); - else second = parse(n, first); - normalize(first, second); - if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0; - if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1; - var multiplier = first.sign === sign.positive ? 1 : -1; - var a = first.value, b = second.value; - for (var i = a.length - 1; i >= 0; i--) { - if (a[i] > b[i]) return 1 * multiplier; - if (b[i] > a[i]) return -1 * multiplier; - } - return 0; - }, - compareAbs: function (n, m) { - var first = self, second; - if (m) (first = parse(n)) && (second = parse(m, first)); - else second = parse(n, first); - first.sign = second.sign = sign.positive; - return o.compare(first, second); - }, - equals: function (n, m) { - return o.compare(n, m) === 0; - }, - notEquals: function (n, m) { - return !o.equals(n, m); - }, - lesser: function (n, m) { - return o.compare(n, m) < 0; - }, - greater: function (n, m) { - return o.compare(n, m) > 0; - }, - greaterOrEquals: function (n, m) { - return o.compare(n, m) >= 0; - }, - lesserOrEquals: function (n, m) { - return o.compare(n, m) <= 0; - }, - isPositive: function (m) { - var first = m || self; - return first.sign === sign.positive; - }, - isNegative: function (m) { - var first = m || self; - return first.sign === sign.negative; - }, - isEven: function (m) { - var first = m || self; - return first.value[0] % 2 === 0; - }, - isOdd: function (m) { - var first = m || self; - return first.value[0] % 2 === 1; - }, - toString: function (m) { - var first = m || self; - var str = "", len = first.value.length; - while (len--) { - if (first.value[len].toString().length === 8) str += first.value[len]; - else str += (base.toString() + first.value[len]).slice(-logBase); - } - while (str[0] === "0") { - str = str.slice(1); - } - if (!str.length) str = "0"; - var s = (first.sign === sign.positive || str == "0") ? "" : "-"; - return s + str; - }, - toHex: function (m) { - var first = m || self; - var str = ""; - var l = this.abs(); - while (l > 0) { - var qr = l.divmod(256); - var b = qr.remainder.toJSNumber(); - str = (b >> 4).toString(16) + (b & 15).toString(16) + str; - l = qr.quotient; - } - return (this.isNegative() ? "-" : "") + "0x" + str; - }, - toJSNumber: function (m) { - return +o.toString(m); - }, - valueOf: function (m) { - return o.toJSNumber(m); - } - }; - return o; - }; - - var ZERO = bigInt([0], sign.positive); - var ONE = bigInt([1], sign.positive); - var MINUS_ONE = bigInt([1], sign.negative); - - var fnReturn = function (a) { - if (typeof a === "undefined") return ZERO; - return parse(a); - }; - fnReturn.zero = ZERO; - fnReturn.one = ONE; - fnReturn.minusOne = MINUS_ONE; - return fnReturn; -})(); - -if (typeof module !== "undefined") { - module.exports = bigInt; -} - diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js deleted file mode 100644 index de6fb02553..0000000000 --- a/ethereal/assets/ext/ethereum.js +++ /dev/null @@ -1,145 +0,0 @@ -// Main Ethereum library -window.eth = { - prototype: Object(), - - // Retrieve block - // - // Either supply a number or a string. Type is determent for the lookup method - // string - Retrieves the block by looking up the hash - // number - Retrieves the block by looking up the block number - getBlock: function(numberOrHash, cb) { - var func; - if(typeof numberOrHash == "string") { - func = "getBlockByHash"; - } else { - func = "getBlockByNumber"; - } - postData({call: func, args: [numberOrHash]}, cb); - }, - - // Create transaction - // - // Transact between two state objects - transact: function(sec, recipient, value, gas, gasPrice, data, cb) { - postData({call: "transact", args: [sec, recipient, value, gas, gasPrice, data]}, cb); - }, - - create: function(sec, value, gas, gasPrice, init, body, cb) { - postData({call: "create", args: [sec, value, gas, gasPrice, init, body]}, cb); - }, - - getStorageAt: function(address, storageAddress, cb) { - postData({call: "getStorage", args: [address, storageAddress]}, cb); - }, - - getStateKeyVals: function(address, cb){ - postData({call: "getStateKeyVals", args: [address]}, cb); - }, - - getKey: function(cb) { - postData({call: "getKey"}, cb); - }, - - getTxCountAt: function(address, cb) { - postData({call: "getTxCountAt", args: [address]}, cb); - }, - getIsMining: function(cb){ - postData({call: "getIsMining"}, cb) - }, - getIsListening: function(cb){ - postData({call: "getIsListening"}, cb) - }, - getCoinBase: function(cb){ - postData({call: "getCoinBase"}, cb); - }, - getPeerCount: function(cb){ - postData({call: "getPeerCount"}, cb); - }, - getBalanceAt: function(address, cb) { - postData({call: "getBalance", args: [address]}, cb); - }, - getTransactionsFor: function(address, cb) { - postData({call: "getTransactionsFor", args: [address]}, cb); - }, - - getSecretToAddress: function(sec, cb) { - postData({call: "getSecretToAddress", args: [sec]}, cb); - }, - - watch: function(address, storageAddrOrCb, cb) { - var ev; - if(cb === undefined) { - cb = storageAddrOrCb; - storageAddrOrCb = ""; - ev = "object:"+address; - } else { - ev = "storage:"+address+":"+storageAddrOrCb; - } - - eth.on(ev, cb) - - postData({call: "watch", args: [address, storageAddrOrCb]}); - }, - - disconnect: function(address, storageAddrOrCb, cb) { - var ev; - if(cb === undefined) { - cb = storageAddrOrCb; - storageAddrOrCb = ""; - ev = "object:"+address; - } else { - ev = "storage:"+address+":"+storageAddrOrCb; - } - - eth.off(ev, cb) - - postData({call: "disconnect", args: [address, storageAddrOrCb]}); - }, - - set: function(props) { - postData({call: "set", args: props}); - }, - - on: function(event, cb) { - if(eth._onCallbacks[event] === undefined) { - eth._onCallbacks[event] = []; - } - - eth._onCallbacks[event].push(cb); - - return this - }, - - off: function(event, cb) { - if(eth._onCallbacks[event] !== undefined) { - var callbacks = eth._onCallbacks[event]; - for(var i = 0; i < callbacks.length; i++) { - if(callbacks[i] === cb) { - delete callbacks[i]; - } - } - } - - return this - }, - - trigger: function(event, data) { - var callbacks = eth._onCallbacks[event]; - if(callbacks !== undefined) { - for(var i = 0; i < callbacks.length; i++) { - // Figure out whether the returned data was an array - // array means multiple return arguments (multiple params) - if(data instanceof Array) { - callbacks[i].apply(this, data); - } else { - callbacks[i].call(this, data); - } - } - } - }, - - -} -window.eth._callbacks = {} -window.eth._onCallbacks = {} - diff --git a/ethereal/assets/ext/pre.js b/ethereal/assets/ext/pre.js deleted file mode 100644 index ca520f152d..0000000000 --- a/ethereal/assets/ext/pre.js +++ /dev/null @@ -1,58 +0,0 @@ -function debug(/**/) { - var args = arguments; - var msg = "" - for(var i = 0; i < args.length; i++){ - if(typeof args[i] === "object") { - msg += " " + JSON.stringify(args[i]) - } else { - msg += " " + args[i] - } - } - - postData({call:"debug", args:[msg]}) - document.getElementById("debug").innerHTML += "
" + msg -} - -// Helper function for generating pseudo callbacks and sending data to the QML part of the application -function postData(data, cb) { - data._seed = Math.floor(Math.random() * 1000000) - if(cb) { - eth._callbacks[data._seed] = cb; - } - - if(data.args === undefined) { - data.args = []; - } - - navigator.qt.postMessage(JSON.stringify(data)); -} - -navigator.qt.onmessage = function(ev) { - var data = JSON.parse(ev.data) - - if(data._event !== undefined) { - eth.trigger(data._event, data.data); - } else { - if(data._seed) { - var cb = eth._callbacks[data._seed]; - if(cb) { - // Figure out whether the returned data was an array - // array means multiple return arguments (multiple params) - if(data.data instanceof Array) { - cb.apply(this, data.data) - } else { - cb.call(this, data.data) - } - - // Remove the "trigger" callback - delete eth._callbacks[ev._seed]; - } - } - } -} - -window.onerror = function(message, file, lineNumber, column, errorObj) { - debug(file, message, lineNumber+":"+column, errorObj); - - return false; -} diff --git a/ethereal/assets/ext/string.js b/ethereal/assets/ext/string.js deleted file mode 100644 index 2473b5c36b..0000000000 --- a/ethereal/assets/ext/string.js +++ /dev/null @@ -1,58 +0,0 @@ -String.prototype.pad = function(l, r) { - if (r === undefined) { - r = l - if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this))) - l = 0 - } - var ret = this.bin(); - while (ret.length < l) - ret = "\0" + ret - while (ret.length < r) - ret = ret + "\0" - return ret; -} - -String.prototype.unpad = function() { - var i = this.length; - while (i && this[i - 1] == "\0") - --i - return this.substr(0, i) -} - -String.prototype.bin = function() { - if (this.substr(0, 2) == "0x") { - bytes = [] - var i = 2; - - // Check if it's odd - pad with a zero if so. - if (this.length % 2) - bytes.push(parseInt(this.substr(i++, 1), 16)) - - for (; i < this.length - 1; i += 2) - bytes.push(parseInt(this.substr(i, 2), 16)); - - return String.fromCharCode.apply(String, bytes); - } else if (/^\d+$/.test(this)) - return bigInt(this.substr(0)).toHex().bin() - - // Otherwise we'll return the "String" object instead of an actual string - return this.substr(0, this.length) -} - -String.prototype.unbin = function() { - var i, l, o = ''; - for(i = 0, l = this.length; i < l; i++) { - var n = this.charCodeAt(i).toString(16); - o += n.length < 2 ? '0' + n : n; - } - - return "0x" + o; -} - -String.prototype.dec = function() { - return bigInt(this.substr(0)).toString() -} - -String.prototype.hex = function() { - return bigInt(this.substr(0)).toHex() -} diff --git a/ethereal/assets/facet.png b/ethereal/assets/facet.png deleted file mode 100644 index 49a266e96a6c0322cfa927698b10efd35b97fa05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27302 zcmZ^KWmuKX_w}JuKtfvS?nY9&yFDzMeoJFeb=|;BViS6du7B6lWP-HwXj` z=lKr|B;zXq1cIt;BQCC@V(s+7$<5lynM_t(oXpwP$79EKDg@%C~1xqf1{M#a)YWGV?NqFMH+z7bOp95p?RGHADP#2K4 z$@4yk`in7~gkT_3*i z$s-5iLPWhkixojcrC*hzc{rm^NT{8WNawo$dnz(N7}BgUS5@ zA;YnVkbqbVKq@A*q9h?YY!F;ac_=?*ff>Rkt8FO*scD9EjbowJL6FfQY^o8V^bmL- zi18pLr6=T5Is{khR9oRax^Y>2MqC~fSd$D< zmL9KkLXIFV%=NQT2qgCl9$4+!gXcI#)%ZBi=Ozpz=7S%IPZXx6TaP;v<<6oI$i@f% z$wwyEdZIu9#6X9~JnAEO>-T86AFrY<>o7$dA-VfY+Gozsdn5TRzGZQ7XM1}=4l1T^ zGOX?QXw_rXrTt)k<1cuBb+O*LNfpFl7$gmUz1}l=u24uak%02abY(YA`o07I0& z0xE0TqQii@rHbwHSt29mjH8euQY?YKk9z9KeDfF69h~qlZb*%-FpSR^<`P3QxJ!9j zES(Qsn^zFXX`55`3>`9DpmoT`gvZmd$b)n)H6+kdHo*k~c`rf5qA^@AGJp($NaO}F z)Vw1;?Qc21 zOLWFy>Cya-A>@pCYl58JP1hcT0{?Ch8OMZtDFVhcN{8|@GJbmKHF>uTJa#k{*-!+o zDuw(PZW(s9C=D`A8PZcBS6KdV1F6<80)r5a;QO$4Y4)U`I#r<=^hWWP5?-QDQh8`U z%|Ebb#J$SR{OQ_2BoxE*ZSQBfHRe*Bu=oI5*KYzOPN+Q_OMkCeEgus~qS;6-MFo0! zKT(ZV1zcO?h1o={2RwF=WETn#yoVT>$?JDAItn^U3o<2SBvf24mr!_7;6ADL&{8Cp z$T!fmzPy1Fm~ya(>&P%s&SA&luwwZ{h(md)up`AeXj|f8WorvGrm&}^rX1BM_nAsF zxnzha6Ni?}?dp*DlbFaD2Sc~BwtKfZw~4pOPxVo=OhsJ^uGKf`)P`;42zRh{xONaN z(m38}=4Ys_mVDEA$sMOBR{5<-ty(p_1c&Qm2LD*dD_Qx%%Dm)hB5Qo>E1T-yA6j3o zCcjon{i!`QvM>ER^*7wP2l|UJypVwiD>}kV0we+}LJxxKG=(C<>1e_M4K`l(KWTgE znCVWMIt)z=zIb1TQIqA8X_AQOI}->dsoNojJbZNTR{D)!oKucdyI$=q$x;MqE6wHl>jx#2J-Xu5GykYH+++Gp zdg3B3g%)-T1G}=6)D)d^nR3-~=|3GjRfok{MIDlDx_3bs?*`;(4QQpU;>HoO_S6^E zSBp`LUnvT`y{KX-vnwS2)+XWc!?E}%ExYr5V77u&@tRl1-YtnA>x0IF!)@_}G`bFA zJvtTQGWs}yU>~=OlOQSU!19TzxM8oTc%ezMN$SR@FD;XT`Lj~7QkXF|{RUf9TMqpW z{rNPAG~_h$iU*2E8ET3xMf61i3IYlPW20kvV{_@;nL_OI9DA92ne&;ynvL~5^_ZGU zn!a1e)@|z*=^iz;JBI4<>lW&0>KWEcRc2LE&$U&y6~8QQQA$)Q&z`gDtvP8LYAS6e ztl3#WT&`+zX!0|$GR3!Q?yKrOO6*AVYxRqL5JGwpzKBsysz>VY*5Hc!R_pCr#`xDG z5x>6klzmn!oe8Xo1#94GB4|0uY<9mY{FTL( zgRC0&C|S)|zi3y^*EAP;lwFw|;|pI3yXI^OZwd0QajfYYjq-Li4>pe|_c~=8h5ix` zpnNia@_w3x6bDknSiwaGy$jNZy}S1ICI9hRW!>W8yO`XTcX;pOf-8e}x+}@8 z2mi)bl3(qmjei-p!3b6H|2_8;$z<0gy4N3_HZ(j`J51!WbA%4jBzr2i$K;B*+b@Y* zi4=*oOe=O}{%U49ZU*5p7F)q3-d3(wk$x6S-O*W{EFD>Uc@lmWhAJLM`_5nYhiBoN zS(|8EKKN;@gNDvt-^P2+LyKRPvS2g4O%YXyP~uDa_YRAp5q(jF@c z)=8ephy`&2hSy4`G7O5|34gz|b9+(saTYS|w0xp1jc-?Yp|G0yHv3hEJDCHA(Ay67 zkc2PsE@EZmiiu5D2Ufe5?jsczp>>aaj?vAmual96?CRqy5OkSQo5YHKYv|FgX{Pbtr496KDXA6|~<{d%19bco%9y^+vV7$&dHOsccnQDMtpC+Om}jJkz~ zz!;{5SRwd5s)@m2R=NC8JGIKcgT`CYF6e#taBz1cjNKnJP1K!GzdtMUhla{Jth&D% zO>V=oh=uVYqpEP1@l){v7U)(ycZkEChJU25BsG+lLtD%zET=5@ch{J+^)XV)Qg>4^ z9A7LhHN5zx)o^%mDY?v=I!3qL7Sbf%lK(^Sd%H#P(D;~uh(>|NxyG#q&(YLsqsjcW z+1E3w@dCZ zJ{22C({J2Ktw>pI#WGGaq%zer?(|LdTa`zJC+7~2%zR^xpj}|x;Pm^4)4Jsy9PRJg z8P#u%91cDl2tFoGD-X1NZOf=?F|cbn^6qH#vAo(R&gLCoJ@4>3dG$0mo6Rq@+HvOX zbk%ot@$1#9zboy-_(gE2P{@0yDo}BFO&$aFjyFFGsNRRV>VJdI?k_FH`S>M!N zsQ)a!OC(H8e1eBdJG(dIWL^e*lgvy;O%Vd|riMTQLm-fwC-8M20{O@WfgBh^AaBzk z5PYWuqdqAJ#As4h;+=-)(%&pEUjvJdCy@zV%U$zdwCUyvT#Cz74jk!4LxFir6pzmD zBwpf4O2D&_v6Se{z|Nx0m#_TMTz{|f5?96GdoUWleqEslOj1z#;)u$cWHf_Ktp?ER8)BVm* z-LYwqLC&FpwE*9tT>WU5v6p;TkDMrn>rF;>zVoi^Q+5txiuy3yTSxz(YV`0lI|OUH z%2Nd+mDITwhe<=ygE2_WxC0sn`T6xGwnbom7oqRO)UAZQ-BGg2ZZMoC z?57$1aheSFh*_L_hTh{6`gI6XK|F+*Y3ktK9$ghok z-n)(h%T7rpb|5BV?<`wDajk>aXB;Gtz|g_xLg--7SG#@`6d~j9n#&@G#k%>u?;Fzo z{QM+b<#nAKsv$|=w|OAFNhWZRk84JggcdDHn@m=n=hx>OL)xMD6Gt2U;%cmEVU|lYwoEVd=UH&3NKp{q>zxe^vty{ zP+*UW(J$bCzW;NKBU+p^3o9!7rQPSlDD<4^f!IhEgMA*m1Z?sw{uD3Y8Fc|eK?Zv} z=wX$zE^fw{L)uATse>759LI5e1gNJ4MsS09=!LYd`O4<8gcggj zuXlFaNls8z$q0yfe;k}K;Q4CuLk*&-j$aL&J&+qRFsJ0V3CzmV_aUuqOaBfVT9Zb8 zY;MrOKykOObqAx=)AzFH)%Y#oGxME_c}78rP6)$ zt;Ai-|Gipe`5@`|0^x$IS)OOHC(t64A$@?U=|Ro7V7ZzVI~0$me?agLXh& z*vB*1$*QMJFFX>sXznLWuJR(pFRxL(!`3j8*}Xwooyayh{AL)eH=*DQ`x*N%!Kqtc z`EJW3mkkyijhPDg@8jZPl;bfOe0IJ9qi*eN@zG>>Pzi=`A+0L!P0@IpOEKBk4~Lwe z4~*XI;*%%~OOl?{fTI1HbsW?|Wh#3s4>>2)l(4p}c=f%gZP`=+Jx*>;C2)kU~_OjKRf90N20M!3$^%hchBl!)o- zi~f%i0MeYsV;zyDVmLXcBnt{rj~&4_nFczrS2>WnE~3Ldtu5j)voOUkbmhLE`mI{E zp&SODKOrOI+mishP2K{12NSYqI*0xHZT+A07I*-$BoSJsJZ9Npm^aF^Dv%r9E>9Dl_9u4r zchrXJmKikU;n z3j0nsc6lyr5;tKwiW&RrZ=9A{c(xB&evOUl59Yd&%yR;{#XK|gSEsc7M>NK>k#B{G`386y`c<{E!5N2!bqjsV^{w7->6rrQE?_;l=GGQD-lH% zqgWU0w}TVJ7XK3dtS1s0zPLwmjhJtLhFvK$^l`y`5#RTPDKJ$#>ry#gM45ARY2~i< zeagew@64g!!$saFt!}`?YFlQA`{jsE9bJwd2cs68T|IDJFL0U$jCCQ+%O4A z!W~)-4h*O3yJ0+y#!3qt8i%bJ+DUri;@H6@# zWOfaKvu7MaooMa{8%YXa)FU~0!Bhy&TMpDPS-=#@re=Aq%bEMMIo)7#(_On9f<;Mx z&*iAz?}u6`dPWO#ZBp9J%5-+IjMEs*2Cx5RAz#;50eoZHy)?^~c`W>iL6u6{hjDNn( zOKdfqHN3Y?r`U^sNq?ex%F%>-YTB4ab#fJ};l7gb&~-fD4gF2p0d@SSn=joW%&XsS zfQuX^?e+Y^&}KX&{)u$f+Q)YtF$16Zp^SQo(;tj| zr#_9)3n7uo5b{(;%nYj|=@utBAg(hECU;ibq33VyR{Os1>;Hv_aT292o^_hvnOl|g zYNVAZ@k%`^4iZ1t<1zoj*G4=1_GSv(%iCB5-<0U=j5k=keQL$p!*lSuK`2}A1_knm zAigD|@*g|9O25uHPh6dlkfx`ddrE}LLdlgE-kShUJ}9G9y&Dr2Av@UGw#?<30s6kS z`C$){IRvQjF+AHJ*I{KPrOdRiMH6SdA>!>64P*KC$7r@KeWBRuBn7RYeb_g?w(J;R zTYx7cMs!?WEq!mG$3)x#*J=i~5bZI{IU==<_>ctj-#!8W2YxR^c`O#b)2#f)v5&1( zWz*g@kKALx2>$kRiz7$d<%~B}yxkrzwstSr#E_0Th1R37+(R`A)0Dgalk!|8jd56H z+%4QeG{CN-FYIt`40gLtsNtTvW#B=m24gjuo8QcYO{RAIS^ zcWIp=$;L^Aar@Ah4?3cjIDNinoAj+l^p+i>5_a2Y8ye@KLTAwk-fMBgzqtrYPC&@{ zqc;^iP(?$dmREz7X#E&5vOivm*L0iY$8s0~#5?#vzrsFOC$lyn-?rwtujKo>G$`0dWw{&26_4#(SNTuULA{aA%K)>W=zL4ENj-m# zE+oifk_V-J8VAjZ;Ga9w@!F(3LY=MJ-0w36EB>c%IPeBt$ro(_u4|k2XEa-!CCz6kP&{Ud__0;R& zLsH-xIaO+AZj@nsigYuN&3lyH5+@O5AiG8Ez-i;TLS<*qnN~S@9D59@ zgbp!F43joVj-+U3sfdfZ*Y?jCUX1(h+tm{EE_@ooY~h0rsfuU0S^?&u3T|K9mBg=( z3?FIMZ~B#R&IE{#3$s;gjpNM9K-VOAL~nUL@6+_h{OK^Mm}&<1;IB+BXaq6}_jGi9X1NzT)_C zXa-Q)EDu0QauUL%#*kphc=hiyCd&EfdoBOp{CWC|DJZ2_v6(1--%M8w+iv#>CaNslJoVbjWQw_2%P6jpsZ``BQ1MR%A$ zd#mj8)wF&#VH@Ed?QrpX2B3F4=clWSQ(MjR9h@4viMo5tdPaIH=Lp3=o0tw%VO%g; z^qra?2eLS}NCrIqO_aGK>EuaIW&D`msll{~$4&2S*-IH{n!e=Zk&Eam=w4+-~-EeB`c z&Rde2{AyX}uG8A@Kh1=&68k>o&Ma0nMVh{IVX4%=t{qxLdN`c~NGhOSM00~_H|lbP zr>@XH;KmIFO8r}#9MM(nHMi2GPk*DRjDz)>N4Ssteg5eT-z7qCtBRH>u`Sr;T-;+A z<2}dox~6`uR0ZFr7Dd0j?<#AYg0{wIQg?jdafbFZ$B77L%F#}#3K+KUy-JfAq%9VY z<30}S*Z>gh^fPK`Dv&992=Uee)Wr`x%hbZB8*T1km3T%W)OASV`omYPloFe|tJ`)t zC8ZQkUUGQKt^Qcy>V$ss_i$yu{(82E6v%^4&;ZCVpP45soLUQUM_xtkP#{+?)UfUC zO!are)1SsrGTWrX4XkQ^-c}RmK|V@Q2~ru(krU3eA~{-J6JQoE^x^B>BtDw&oW zVzMjKuG+?`HdP$^iQm6fnmjhUZB@H2)V6(S{Kk$|uG8?#{M}JXFfa#(Q3=W zbqv)m1ab(mkL^Smkh$55Oj71M%s!%e&QNiPYYX-Jpl6MF8+@x})%i)tP_-EFXO*zn z^>E$t#mc#oA)e<8(R>)olZ-obZv7*B8i>0+tZLC%#k7Ff{%7Ce4pgiZ{TgZ)c#mCI zCC`F%Wzy(`9Cr855*N&H&rln{g_g7Z4H+0y!0yiw6ZAf9v2Sp1Yrzo~MOHU8lwT#c zZadT2$G6%JsA8N9yZk3B9u{>erqn_`Xr*fY`TbjhUF2G90`k{CN-P8QlJqC7h=0gSFm)@w{W!+4fWsI}2Tda+dzkhT*ce)kx zj%t(PIplFoc{Z-3YbsRP31ZmiK@ai+r_i!YT@JhvP}Tq3B2udXcO&E$Hg0|iI)M>9 z;3*V=p5cQbaRweKio+iEm~`wSj@W#xprRJQTY-bq`REjO`X#z` zD5H>j`zCpIT3(yw9$ge_!7&6<=qccNY+Z%JfsTU?Wjis+(Uu(?6lq8ara9$vWC&;8Jo9qfm*>v&t|Nt~TAmVhsk6aR<<#_b}l_X6(I4j`oS}p*vq! zb&AOYd-wGc$+4DtzZ_81+|SqN$kfaIKgHn_Dc=6iu|WXbL$g9Hf5gC8wXX=-GcFXK zc>U|9NfsfZrYC=?6Imx1ITYP%C(1Pn3XzY8K6?z={{!M9+!KadU_g(O5^;s4r5T|1 zU=+$(RdRJ;IR{y&T9PU%YoR@k#b7b6R}4AQ$!oK9QGNP!^!>2NO#P)mvxKqsD88+lGF|+QcJM4-*~0m592?v|^t2~th`y`(P%M%=t`c=N z_x(Z>CXi!WEo#iga|1Enw7WC}i)fD+*JXr}JxoLHi!wbby#=8ip=G&MqkY=-Cjg`M z98k1F_uy};TT#hVzW#lpB(b$tNMfxjdKAjw+8Z^S_O#f|pc12F5k$9*#+cy1xq=jh zj**ih_LCv}x-ohSjU-GVQ#5-#_krb~m^!h<&5RWHi$%566@Jj*lq_H{ToPt9sts_X z2=q_gs0)fwsR2_70==ABHxBAQFGa{e7aGn{(QIJp@;aB6@$Iql%B&@wIeH7k-VVjm z4i}wM@$x@Z0gXCqgnoK0SE~WL)w~Khg0^_SdROC_5~~J?W|^Q{RekAYqTJxnzgrzk z$~#IMx!>*f6UsGdS=vv^i)Y^sc_$m#z7#|gh!F-ZCHsFR|B^KplZE$q11qQK*(>xx z;>rZ@Qkiuy@T@n6RcePToi}Ub^3X$pMO|28k%X61Fyi}`O&wy4UOHFmPHrIsqmM&g zMptMLSNJ{exwlv7U?3uW+$?qZyMvXJ2Y{Cl{g1YJLG+*kex2`o>TostzJtG{4`o;{ z&74)E^!jT;Rke^s8!&QS{qdo#+A>D>N+Qo;Hy`(C)F%FUwsP>?)Wv}&lQrpl)?^tw zE8|wW;(|irm~o0}bo5Etmq;41?Cps#{N?EDTZX%eCyAC#k?bi5fh;FOE}I{g#|d2N zBw@@35kgEmZu)J57l{xOEz-WDLO^2(nEwz~i*km7agsR$tgoZ|2R%LANc+EQIDXCl zW87NmLA_j%RoC=#=F}GS6RekpQYLTSVp>MBo2!Hg%BgnI$s2{TNz?x)OsN5t$Q+U1 zPG5sDG^h$0No9rt^W=Zh&XXFV62)0*G@R@hio;UhMKGrxh1g#c$&L$&-)k8iIq{)6 z8j-k{5De|FbR#chLPMXj4dkC3A7FE7nJ6zPEJlfK;io|C>GuMc$sQ1AYx!hKY(k!O z_n~lL3`pDtlGC~o1#qL z39!dd@@8s8eVV4o@;4{RCa(%mD0`wZtaS7V>Agzrk#9Hf?1OOr6{&~CCgo+r>_DdC zLQD#6A0MJ)$fMQxDn0AXBzs4V325wW0fj-jl=`*#|J39&e+|Fp-accn0cJ0A634cA zG^So@^05hHwaS)`aD6hit~C7tq4=bWmIrr#3q8cNFB1(M62a7_LIqPUbMw+Wdf_cF zX!@&gGK?E)>^bTi2k^-yLis}mmf2zVJ3}zRIhn(_IKblx?n|@!=unONvd_@6!qnLa z%~I!XSCG@cEQ?!Yt(_v!l8w%cI%yLPaI^frP*-j9g|5FOeqY3WzXCxk9~|N>>0kA! zL8IHO?~@-R{F=6y#0hp+Wm27@mfW@;>=h890%l-pp;S&a^$z0F(rd44*4-f0-EbVO zg^xefz*@5Bct-bY9cyA5iu=%a&LnBld9EHHdf2>lSWp4+#L?9x#-R>`{MEX^Ixaei zV;hMf4^i7z4tz2r*Y%pq>?zY+N5Jw zd@IXHV;~1{AZ(o)Kz&)kkVn*Cv#%q!eTwmtnKn(5v5|A4V6ZUBg2^rog-dSHvftT8 zzRlaHW%<pQaP3zbXuLJI+2%>w7#ou7K{&6M4%$F!D2Q)7%Hx@eiG2CA7hL)tD{Ct~V(Z%M10O30;%$j_b#W(ZZ zXh2uH`Y8X%)&-&%*y(4$|BYhTF!R!&8^e6*(4>?R{qF!<6vOG%q$t9wehgEUzH2H~ zTn_=8D1USwpz8N>!w$bJ{cI9~8R}!p0XI7g(;V&E7cYnfaFL#wav1l}KW2FY+IzVl z42Y?O)vJ{zqS-r_F3$M)wq&pKT-Bl|`s34o3)dw%a+}qppCpZbZP3^tT}-D4HrX-& zepfYp#Gb|+F(J1M7=cZ^QPHQDgoBGp?LwW1J1$a*;z;a~2RCq5SJOb=?%QDu`7)}i zMXlFHDRrP;aZ<8sl=2OntsN+c^O=~)NP2JUG0_$9*nlhHwW7XH*4yvioI`oT*p3wM z5E^k%fu)Mt+&c2glE2o;QXV(2ZpC)G;Ct7eW|?`qfq|a=G_YPfzG-=xD~bvV+CIj> z4353@(EHf4$4U0_3ncpu1y~PJqUi{Vn1sOyvE>j$>!9+dl2`S2$S?|0x=|*Z@{fUK z78b~FR7v1N#BX=N!M2r=Ujn&?iGEN}q4Rnb*bqm+y3kTcW5I5xPs&SBwJ$;^CNyh- zz+)UoeOhc-+nDjHa;JGkFCn>EyA=z(xMXmzaHu6ugEmxgIP1>?w3(sL-+dtOC?iuA zvyJ*`PHLG||8spa8EcY;Q9{G<j@%s9i&2;%ERwfM3pMpaHRV`sNS@=4Zai{VQK zTH|yK1>!VSnIrVabW&_K-v)@zp1MJaVT?blw42o`mE*rKeXfuPaz*zxa|ghqCt>?P z#d`hortg(vl;HXyPZjQQah$$a?7pkx;5m&?Cm~61@d7MG60l@HpvYU8*u10ubx!GInI_^7H28>x#d}L$HoQo`)G%I zy8%0Lb-H>)+t6p=SepylOWCjO@SobOnkZi&=v`L+=5cQKaje871}`v&!!7IWD6E-G zK03eF)t3)nO+$RKokYGW>iXi2c81i(e6@cGXR;+UzxKV}R8q{hZ`R`+o)VFsIpyjO zn8T3vlr~}?oPTAIb1y?q!6cIqJc`ZYQG=mCeweb5KD76zdzj_{oa|PxB}sL*awjGb zXa1dmitZgBEfVPbO3m5nTJHN@mV{^TB36@j#W}(8y!N4LmfMW8u*5V*Gq9G6=|Ka& zYPJ-rXP%b*y&j=y^^C=vkrE495d&ptLbw(9rt<}Q8&SWv^a(X zn36__kbdWJ*~`ybFXPUVNisW#l_O&?$9Mm^GJnp@k~vgpEHcDZ8|F}=0heGW%Bv{y z4}^@<@H-c?riAChchf%6`=N=I+5o`8<)R&WMcSPPR)Ne_^gNvY4fWT~#Z9J>B(*51 zBN{uYA~cYHab6qrH*#j2mt;^WH=SmA4gkb?SBF401546nYz*P`wPtf1vrj~Ihf6Ul zUx_w97`Ye4qrn8Kadn0flPZsT7S`TsmDhSRc$y;4pEiuwB^MiBd%rkEF%A~xQ1Jb` zMC`Hj`fv}bxM>L)9KsF|6=maaT=6`N6_`$;hUT>Heonm= zYt_(Wl74evO`2-tvo%fvd2RRRYfWo4#>+l+3hhlM3KopB`=G!4miHP051Q0p&=Cvy z_Q2C+U*tcnoOm_MzkVGE$`^}Yarl+G z5&C>n+&xFHKRH5l2{*MXpY-b=w_yg?)n9&}tFhoA4Cx^tf$iq2peh>hcl8OQf`JR^ zUmUtFvUJT@<76utaVHL1rbfa;Ds6qrCgmLZZmmY1 zjd^y?^dhuJ>Mh*5t6aSeeUIX^uLPQjNyhg`4vj$e$X+l@mHd~HC-XT9_Q>8w+sGOO z12VGmF+(Y&nu<8Vc(t|y{o5lr;}6tln`p2uV$UEm40M6?w+Qm0LS*M%`ER(PUpIi| z3>rcxO<$juO9(`a>ygDdLOTt9#GwfGolL@DwcgU~F0Rslj=v`wv->7z|#kbl1xZ0NYseauZ;)#vRS&OfjQ*6 zn0JU|sIXGhU+yiyAQ2C;(Asx0@WtiqNiyt3LKbx%n~|;0@1W&&G%waEQ{N2$X>E|) zs-;Q%*BmQ`;byUTg*==B^7rn52ZHH=pe%hA7rl*XOd*cw7InD6$QMJXTakqr8*OBP zWP)>!NbYSWNXGzBcylO1fD>npS0Lg2+=B7R{l3xZ}=EOP|D;wQ`J%=BV2PWZmro-)pA_W3cBn8!AHCvb^e<0VD z52rqa7Js_hJe`?4%=^hAU~j1-?9&!_8=72)mxQvRNcMgQ6y6we}QbQn+Ur;<%bimE|cq$z-=v$;=Z5Qd?4f-VQ^G z9C%J^#-vz4p}gTz{7c99#b$nEL5u$Nu^+pL^ao~yE*)F8dzg=wz?AsX<4a#%Hnmn{ zgYJVV#cE_^$*B;fpRqg>ZjO?JEqMwXNI;OtH);?~_VVOZM?7UP8biSASC#vPyWB}_ zEZ*fpr+6*v#Hd~a`UF%spM0k?q?y5lhbg9TJn*;LrViEPRyF=+5Gmmnw2VNC zgSu-u)l7ig$@2g{g?fbo+1%*fGf3aEDl{mSeF26|wF@Rw;jt7r-Bf1(92d>s2z}6K z6Cs#$a7?YxOj#}y0Ed`@z4l2-0Qv#IH>2gAH75i_)b^f{V|?pL2^h6MN++I!OUerA z6NtTGNf{KmY_E;{GXVwT^-emY?=3vr91+yrZtN3Ra2j_g%8SUQN-zRDeFdhg%tU5~ zUrh3CeWxT;gP^Cbh1Jv?Sjt)sPagA;--jamb)t*vdvZiR_#CL|n=X$sjV-#7r4Ya7 zS^5u;sQ#uJ@qN%pET3C`T(7}#FVJ>F=jNz>J;b7r}SPgowt?Oq}@h znXk;^2}2aI*enx=oM3(OoSba5k3kMjkekn30+S?C^Chf?Q%&-oWxz5I1)K27zyq7RUh<~QX-~aMRX!7bZ z{KL1pmAUeLbfnMLRuyi`zn^n5;DL~+QH-z<1d+rnndN&8?W+<^=UuZ%KanxWZ}Yds z8nl#)Kga?6Dyv(u{6PA-!^!<~!m#U|j7{y=wI<%y!w;<97Z(CQPP*e(ElG|d4S%kd zqu9{H8Ytb+${#7wo&z2+>9Q_U!NVvH4;d}Pl|)F$PA2dC0eqI*49X4JmeZjfnHefw1OsOkBQ=HaWW7pM0pEUi!9{kw{&nrMZ-&poq8dEk9%VFkulGz1pB- z)F(vf1DujWCfs7-nQsqa3@0-lcBG73GIw>6Z@Ue&+0?h7=2#7&(_)o}=O+Hky0;fq zWe!;Z*##p#rstmPI$W$i7uEg(Gab%>exLy?GE$k>sF4@IRI}KE9!ymUrx%_+g~!~Mrh7iPf?PnO z#IQanq{RY0v-fe;jqXt$bIi3}1QKFciBzWvRGW5>fkZZ-tz~{K5;?@&=jnR~>fwq3 z!!;XR+MFWtvJuKfZCiVnIlDdk3)q(=Hk|bzjLGcHgJJqY zrxf(c{w;#g8adF;#59kQ>@zwSBX%geji@J#7agz|!yGq7pwob-xv@72*i~P4a-8Ekn>BU{X2qu1^;o=BG?8jn9Z*u#!v5@{p&c4>@{@h)f z|cfB`fJ!x6xjE_ zkEZ?q)}R3=4fXhkm9!d;#4GzBX*rCY117WtF~65#V&JTK6<4|mqA=YD>^1)!ipVJ9 z>3CG{k`Qn`?v}bVWF2t>PmdPk%3AFLap0K59R{h*?8tcGcL^B#0OV%{DKp-G*QaGd z4RxG|x>#%s@&lV4nD)SVGxJ!W$ElDH7FB0LCLvGCW;qwvjOFWp>BcetSU+J|MAO3ny** z8O#Vd)JoLnZ!Cqh- zBNt;cCb-51 zJ~=X1zi}${DQAC;|F3Tg_=e-x1w&V$aEgAkt`!Fq-8F?^G3 zx>55pOn~S|IBN&69`&eb0<+}xixI|mC%5lk3MI(AmWSy5SeyjSBUaj*`}DAOid?qPDcyNZjR{y`@FO6M58iw#{ZejfElvUM!abQ4)91|6P}|57PO5 z11?O<;-)^nEBmX$fw|eIhBG6~*Rg*5jE3fZX`xiQn z2k`E52xERz(aL`U=8nFx^7)}G-=~^=M1SG8j=p3Z_VFwBC?G;J1ZZvF^B|vK%`C%{ z*NiD3nZ&n}N1llTQ5ICa?Dkb&;L|zMj7+}tjTVTBa&wr*x7(v2cy0c&=V;*~#FKi_ zI7|t$mjhu^FVx~0YeC*T4k#c8HNdvVO=IYd*^pt(0u_)|El}Q&ynt2Ca2T+(TG~0X z^k#X`C7$iii~;UHS_oV{!yjaf1B9?{6$7gB{nDP;XZa)>xG2OazbyWeGLyYalTNX? z5IG0L2;N+IB?GTIwc@(YA+)D`iu@H}hy=1}o(#q?_R&A2nK^)_O+*$yP$kdr)A~VV z(JY;?XYn!cKpD0jf2{QUn=y2-2$zl}sR*>`W;N7eSr^KDCj7wcz^es;kz5($=0QlHb;kS z&L-eO!YTmYP~!hvlc=oYvo`JLoEoE?5l4HF3NBSHz0A7MLD?O#VU>p_)& zrCW+c%TZZEMn)&UP0r{-OG{)nff+~CX!iWk0FIHdR~|>U+D^)09CjkO>j5mDP%VhG;tw8zp{w!7h`pkz* zPTM*nvD{9?E(&sqWU3V|ZpAywUc_O!?aRKu?ky!LeBZ{14{?Bi8wFoiK~C?_Gp#@$ zq^fq>m?C6jMD<*GqtYhC{ds(_rq;rB=@X~2Y0Ki&M8ZdGUF}0YqSrjb#ank48Clei z+CZW8wm+OM!sCe`_hVNq7sJEF&1MEWZ8E`0RCgs$lxrCfxpE|vRl zYbOf`83Fc2O3XV{BzIS7D){&Ogg1}?9Sb=gHFrX;xI8T@zYV+I(LhOeLIHnmajL2_ z9{y^Wms>pN1ty^ljnFG2;StwbVh~_ZjjD`cMjI53f&ajs5^BLR&n>ijF~;&?^N(v>`y;P>TwF`NZCys@C*!gtN1~;<;JLQM3Z> zl)+bVKEt;}(HmxEOOtJrnoR#_`W)`zs7jBx8XwnH7vO~YxPL6kaVk+iDoE-;K<9w~ z6<(#}eEbPnB9+=eh{N&{{4TLE#5)h{ErVA$o7Clv4gees_fm{Vh`3ccx`mg)4w7M! z^vF`>Vu?})N)ZZzq2(*scKaQ(Cm_(x!$0?*qMcFi0>1KVx?=)-uuB_*baop^;(@J; zk=o5ov2=$@P5sG2SZ(fRpdE$>JrdS{P(Ax8y1~MhaH8zxE@^~jXB_|J_ z8+(jWM!{z?*gx~~n<2<|FemwWn6Mv2S*s}5-gz~&V$U9mb^aW5{g#x40Qn>;L>LG& zm=}0lqIwwsXJV*hWQmr8ysp_sn_XRYacOM?Qn6(<58O4p-tPhN9$I>nqfzNXK_VHb z`!4WJm$QOdoK#pWXFrW1u7E{GBC|iIENz-50DNEP-^nak{JNV~*slse7Y83vAdRtL zN{pXzt%sg%bxg=pJW{ihySZjOdVuJy{>d7ErZ);&gVx}K1&S1>>rwMp{=w`TL^Q&q z1S8V-SQiEJVH^d6*f-2@_JEJO@9xQPiD+xQF9!_0b^7dz7A{08hp2F&X8e)|5?;}u z5YjG-T#@}8N;=40J!-iRhI#~fV9U2CedOHJ1+h(CqVt# z$ZL+m>pa<73qojWDjGCz=UZByOzV5Rcs0=F^cIZqsYh$Pk^xopq;ow#?7BLuJT={x3obu9f?fAtNe zO^rszu+uq>hKxcU@*ln=wN+w*x`%9&~*9CCO81%D4CFK-l2IM(i|l3X?V=@A>HO3?lS;HHQHO{Je?Ad?)oMm`=U@(9cndO_J4w3l zo33x5_P?edf@1p@o+QFzUqm{x^6LWjGYthFdU%ntT#?n|Lk$;!cqzfU(6ILU51MV$ zf!y62_v6UUtBc3gvQ?Z3Z6N(FPO+Co+3e#N`IqK_i^Ys}o`@S1@< z{+YzjCSSfGiDsoO^=|>n;qs@d;#$MnW7_PSHY!|p_veo>or3;2r*uKX*h!*icVfY~ z#)twN=D=}tQ|swed73#`GwHJ)(S(OyQq}PE@PCC}XE>FA+_y(Y_K2*^kWDtB?3trO zMjT`&Wt6Ojove(6tR#DHGBS(o6^bM~d-Htn{?D7|)$^*Wb8(&f{>|_Av)oPN=ESuE zA6yzia6~H<|4f{r@1QPe`^lnXO`2QV%Oa*T^4z=fwdc8+U}1uB?$~9-oKbfqK3Qux zxy^)K&+8L6zxmCG#&FfMYuoKr{FHv)KNL9W#}6#^>7iL5 zBz=~?tp3Hwf@2T_)Iz#@(_UU56ZSqI+3dB62jNalBmtyYmah9x4OCvC(qKx{brukH zA1h44$gx7R(zK-)`n%Yv>(iqH;H?G$Z~2`R9Yt?WcmM&ew2Q z;$-=IT-pOKO~@|HHe{&aK9h;&IzEDKysEZYfmW~Edrl>9bZZS0di++T9>!z(R-#bJ z_RZ!BX1XWn>cOq^?2+4!dSM*O=#nRqZ0}~Wsw3XMXOa93F3^|{TI;2!5-X&}zDbkbyXDvRB@xgJCu1qDnp zfXzKr%FyCp!51cj>2|Vto&Eh0>>^~BhXN- zl6Z1tfc1Cis!XfOM!rmf(R*~#Y>}teN057L4P7M%jC+3NcKta)ewF$num(CL-#7r} zo^*tAvqqbbUi(XKJni_dBYV5WPtC4^WsjdVoa*vxe=`Q_9}4rg9>#)?_GY#F}e802H zGhl=dFdqM9zJFLtE;P{i25qBUlzY_ITKLC4#~1kZW`=s-gV{k)wY5^JBo?SmtXFlC z|A9OJvE<3!T8de0Ub~fT&6Drgu)0{!ETTs7trGl}d+(dCTs0p(s7|;Z#ku*;^+)uj z22(qb@LVP@b&!^SZfhSZDAgs+AVQF1&zCDu<*Q5aw_4*qtwzSOL(NzWZOow})*PJL zqH@mSNFRGS3T+WtEzcOb0t^E9Tr5?C$ohV5mrxHTQ^oG_etymUS+?MC9%DNHq7+J& z^$5a**4F?1L>H=T7^hMwZuz_?ia3yF4I;duDiO?di>3L0t2^p-3S z$GUFB8r+T!5h4UwDuW1y$Ktc{l`X=XP2j)Kre@71rPcUgsY}<^vE-wM?HlS_M7w^X zgK4|VoGknkrpi@!V96&hLu7a6=bg;U(H9ev1^pr@CWPcGdyz z5DN8vC_N<9x4a<7(etZ+$|qy}E>uWUK;az0K|kqnb)=J5-^juL;I6;>l25_JPhY~i zipv_DAIAUe??hYZU`Uf{1JmBTf4xwTg=MDrJB&9bMdMAi%rg7*g?)a0kpufQYuzMR1w#z>qgO6T;+Sy4k&-cV(NGL6mD_(F})^?|&cAQn;z7lYkSfk&)&Fm_rU3gb= z#NXu8*CYH4lqpL;qS#HR_5K07FjEh4r3|_+6Is1=?fgULS5BkMHibwCfp4aJX#lIB zLD7JvhFNf!whA zD0AL>`jzqOHmR?JutC#pwhqw(X=T`zwuZMg`IfM=e*QYLX+nokw^l(%riQ)8W6Jh* zec|@asG+f1AIBh1IQh=mkY35j2MzSXA?`eL##jZx3^^+NsfL2koM(dHEdFdB(RjMB z%rn6NMOuwTtw=tdz4izL7DqqPLd5&!<33T(#~_)dTIgk6Sq3t0+c*1B#!XK|w-RP( z+EDcgVH}a2RFCojitm(3zDshRDK*z2tOY03);_FB8&zLbIB}nork{Uyr$O{WUnNY*p!Zx>XrwBi+5S(d|_4MzE`ZOuP*6 z@B5&a4PpBs;&i_5$4v8Kx-f&A9h9?b(E2;+9o!`+ViNs$mQIwk~nsTZl1}wD~3v`y#4Ic>Q ziwZ4I<+0ktcY8X4PCnHnY@gJX4Dma3j|gjG+5?WM{~>zv5}v&=`1W0L;esVZ8Jdk&+}-zUuw+2Ip@ zZWcUnb3uVAaV3UWG^7usf4mspZt(xl3!&Y?tzDYl;%5o1tcs{YTHRoW|A<{jVPR`Y zP-%>f%0x_j{G)TiJTYo4g!;m=9jBtg9~PDgARi%*(V>Nq`k*z3WDBH-A`Fu5eE4DE zS^th%l!B*jeJ<0Io_^D@DFsQ$=>8JQcU>wUs*n8cRI(R4IOg`ek$q8qmZB3lK)C{? zbo#S;-R(-i{noaxLzrQlVHhr&zq!PIm zt}{vk{JGqr{3V~--iYR#kjAfR=qQN!r;modg%~KZ^r5uuq~a#vu(fvU{E(FT$XIb9 zM>~uuU(SB=TI$uNXxex#_oh3uvoJ{KYu?5@s=lG+curu3I!y^&ch@Zeg~WsehbTQAu|WIHcU+*t>JQsHZ428|C;@Hd@VAh0IEPVvvx-qd zo_h|~F^AG;4sM-y*8w~)Ih0oP%QA_@(q1HB5he2sG`1=h#}XUEyEZ|jY{HxG&nuy( z1bE(o=G+}MQ)?&x;{tf2qIpbszLyd`DDe+SUdJDB`;XJ&L=bPBj!}Zo@RFSKkghJ5 zV&h8geP+f82HL?gls^buf3`U<0B$CqJ=PvzJ&2*jx~ak0r$yxo^=FlyZjvR5+APn? z6?>|My%9bypk&iX)JR3t*xjV(E?$Gm)pMFi-zGgqLU&U-6fZH>cJpTm@q>CVrG!f7 z$8%RMeoxUYm6M1plsE6!8D?6^^dWECgy%CR<+UJSBf(n1X=dk_7qPdC_atn+{@#^2 z&+=3qN-v_O@p?~Q0CP|^n^S^=uCJI-y)jPx^yku z(J^T4LIgwZ_G|BT6o_9ZP&vnW8ffZUPlOs1kEW^Dp3UX-PfDbmSj{xwS`G5pQ1&Oe zFHgR~bhlL|nT3?e&?EaKC+0a5@8=4h3j>v^!mO;8(+bkIYotMBU9LQCwCZyZo8cZa zpQNpwR7FbuSUm2rQ1kI!TvA=B=JQnr5dwdeEnhuhopN0 zm$mQ`sqv1xph|+;pox)5N&z@Zz^sAU-gXD$i(psv^oU^O%q!i*^;9YU0}+EyKu67u zq*Ffoh0y?QNAl$Eb>FUP3pj;4!E1EzEhO;xHt|8tEJ>hz{{s*plR!)cn(OH;&C!E> zUt!A5Z)>_c&yXJC?R$*Ti`BWV4~BCTX}#fQd2$mTS9eR=x~vf&kL_6PH;1GgEV2Bk zAt5ZxXYt*F)L-Qt?i9Kml>n_@-11{`Z=!&gXuW^PBB0B zRiePkxB2VGzQt@&fzTeVwr2j;>Ss{76ZjAWIG*=I5|Tg=Q>PU^-wV8ZtP%2QW6u@BpcDo&rM1E^@gJkQhqrr+x<%fi8C%TUOVzdscEphH#KUefBi?gq&NmDS zb78Ud0o$rS94GBT9+g6Hmx#bM4y9b0Gf-ma4?Z9AJhvb2E&3ylMTpy}b!a%5sf}!7 zh9D1A=#M(VQM7qv;noJ~7KH{6` zXalMWy#P8oA)H&p!cHSv-Y6)dG${TCtK5)4=pxMHH=oEazMMDRN=VZik)Yo40ZgbH z%EFI3l?$~#5(YFIw~$KAwK$K#b{wx~)I-6QRhx+YBd7II8;whHqPT&DK-1d@UCy30 zU$h|md+OZEZb~_C@!u2Gy$WOFv>xaw(J8GIxKj!=IMAFNMBb!I%Gx$f#OE1-*Y7yA z@dwzc;pnCUA_{SHZaFsRwGKfE)ZDlqbso{6!pe4h{`bX3uyhSd(-Q=BFo_P zfmcg6A<~Gl$XbRhn-^oQk**D!Ap;4fdH$nhka3{0?P&gX>}**?dWp-up=Hmmg`0(C z=U?i)!K^orc>$^P5pLie?%jq8pk6!RWIbhIlmyYhBfAtcKWGsC$i&W0K^17vYvVB@ z|A+sa6+tp@RFhax{q(zOeTww~gGSStEn~70#dnU6q^*s@IM^5YtQfN1uG^ZioZj=Uv}*W+A| zVGmjVL657R8u!!V7zR8kZU5$TRvqH4WxT|C!}jCs7<=cli%0jAN@hDfM=L>BPc(#P zRF1j)sy_(63a>d68OcQdwJ&cPw$?Ogx^rkuxJ~B-f;nCod8A|OCu?5;s^KT7MLc&1 zd`w`c?HEpvepIi!?Ks@zAq%1$9&!(-B+$tn!47kxD>M6zv!1YuI@v@B_a-3Ry@Y{q z?@i?OM1*cno>QnsCV#v74HgJ^yk9uX*3KJpc-Io5N%fsY#~t46cTPX+=ckI5NI0DK zp0JIHOTA1(Bc1){Crd#s;By>A)uUPa`4YjQg>CDYsjBV(?bz8t*uC9c@qxF{ChrkzJ@?e&b0}?8 zpfb2D6*u{Nmo+k560E=mL1C{QUs|?))_wT%7&;eEGeT3>)=wAXO3n$CQ8f=9H->Ju z^Z;rw06;+4lIG+X{QG_0{S{IxF?*KQ)T^d0uZjjLI3uqy=CKTb%Yr!MDkQcm*ZI9PfAO9cVK za^2Kvee2D01}wk<>5Cpr2Kf*?ysv9Z2+G79VhVJxZTRgX_e^$;UluwxdMvAh%=4~h zkQ!9(Dp(j?9B&yUPnd!4nxOq^*P-zGt4%@WPnS?(mk1vvvAPi9JR%M#6Us_^op6br zU&XCp_%p@G;bc_WrN&WL9-^R~BJ6QU|mwr1DZvDw5o|8|)3>=r* z{SR=L5_x~zyM^zNly`?!fCzId=5O{(T1gl8u$I-Bv~9whik25o-5WIl?9hP`T>lZJ zjL7QXj8F@F$K)hj=E7L>je|%V-LjA=Qh9c_=}JP~d@iDBKw?UGZX!uD=o07M?d3(} zgoHu4K`h*DV%Nn>XB#S~%BS#cu*jtPEtQrYZSO2eE4!chJSH>&xOfJJAt6LqL4xDg zVZOxWo~bsVOq6==Jktz5_U41^A~^ARkN}D0kIvy#S3QpO!p3ib@uMmC0!b7)Qbc{P7Y^l{pyPih?w?4?&cw%~PW(x5EiZ}$kzdviHJ78Ul?eg z>$o?KL;X)c#Fp)?=T+nxBxZT-@x;Uus*BwMvSE69D1~$kh#-+q@1VXL{WRe0H~#}o z_YfRuM1n0Y?sy!64SII3g83^K!Hte&;ix*496yD2^(`EgBzSf4KiLzMXK8QstVx?~ z{BY1{u}7|@Yj>W3?)5PUaLo>wAXbA0e^<2+y-@iTqAW^5@^0tR1Eb?_|uUUFl!Y3@$~p5FO|SxqDQI19?- z&EcOELZMJLA9ZW}0^x!3dwYjhw4O4ZQ%lrX&Jw-}Tu%&MmhM7mTzRkHt1aZMxsZ$3 zyk_zr>dOSa=YnGD8P>B*S`;T}i}@7X%JuSiuf!nN0&}A%^Q>(;_yfeD?OPAq*?moXTF|y+mz6u$Jb!+@%$gauV^A#4%+O>{^@sDhEUSiMoz2!1?z@MDVmi) z*)tBv^7m*KL0jJ%!3$&5^1)3a@KCu!G=^)QT`THEs3D+8)QS9DvTX}%Ds;1qHK`8d zv)v#g;lb7eF3kHa*VoLm^Q)-7Ukf3Yx(3L7oP*^|g?H>;K_;TeN2#8nM1BtE)Yp4x z-$>hrS0IYz$4^f3jZ$DgAA4y;f0q%pvw~zcSo|l?th1 z`4?~ok(<{nz=I2BpGK%jFz^yDT-nGC*!+3$2qC@CChQqR57j?yqGX<>tx<#wCa*s- zt=~Ru$be3Ueh350>wgIz$FOc;mVTEk^U>R$I@b9?QFOOrJ=`^)w<2lE_pvJ^yIs2W zmmephpk=>Ag{q5{L1neyuc49G(t6PWXC2vb7rVdG`NDq=RSt8ouToDbp-4I-lqvBB zreI;n$~nssVZFc~xN(B*5v1r#zTr6jud8?kn*WH%0c42_;w!Nsvm=Ewz&UkZ3MRrsX^#iCKfSiZOuTuF>LrJ~PW{)PIL znN309gbO`Uvz6)$xIby11}Nqa`4;m=Jp(0JRq&0k2}2CeAUz116$b)Ab|BNI$$Tw- zGU$d5q&qY~W5h+VVy+Q0#Uco1@f+`*Ur9okcm?8>Dl-R6WWi)oK+$rJUW z-+x^_>tU9!qaw_{vT1M}0Q$9Aux9ZU!W#vQ*_RJu=P8Q#Z0*n8>*=EEryuBZ2DX$E z?|7ory=C(^eJO8D0zUQ$?wu1Sh*R_{>}=Iwo|ULk+)b$cvzM)V%-fE+nl7jfQ@>{OIk(F&a&FbHfF+@jx-C~#wgC-YA8!gyO1O0%CUXz`r ziFJ6z>dV9ZSjhHq$mY$;&(eQ?<8eg>)ct$Evu&?bEzD7%a)etJxSv6bavfJ0)knT(Q!Qh?NRoj)76c&oz-0E)SD~zhaR3%Fk96Uk$3T z_q?E|$Aw{33rL7>Jsms8!&Uomg(-polQQY~4wB*|{oNsY^bxWS+{|+km!?+gg&X#8 z!#q{`))aSS)2{T1Z5&gIF!Osr^cz9u9B8wQk3*3_=6BmS*^53XSx+@g#6!(Z!tNb` zHK=vxB_r;g01nMx4p_0i$|r~Uq?FQVYkYr0_@>cuR{CFBRm8|GT}`6&#<;SY#KE6JI2c2=H|5PGHf8;*lx4fqa=8?edl#lP;H0)9W~O}Z~YHJ$?271X$@SO(~p zozx2*%}5}^0>lM^pkRxq4H8I+`N$0$dIgzo9F^ZhWDayIrQ3C0lA?z<0RgeEdY*mop82~FDgFodS*#8l7 zuc9`Plj)bLsjac4zP}kj+4-dGDT>(SA|_OENO^pRhv>yl3fTP1;0Fu3SZsD`t?QL}aArJl?~>TuT-Yg1n77fCO8sG)nF<&sb%Q@>k(_BkJ zlCQxSZ!kRH%fBJs18K3_to{98q+)ZKn(J;;J*my4{rrFT66gz?|Fv=!0qv; z0W)v280pla>$Qna<*s7B_k5yqcwN6J3(?pj!%zqP^z4G%%p`_1@iP$JQW|`ku~?4^ z#}=jRMAitukyyEqoU;{dz{DJ5*x2#vNQfg`Bk$qD=!bl}Z5f9o@eM@`vDZJzy;oX% zEv#i&9}sef{Jj2R?zP4qz7oh2v4w^?l|oJ>jT`6pm_CFXT$sX)8-^m0sA1__P R{2>4=4K-cW!fRGf{|D(@9S8sb diff --git a/ethereal/assets/heart.png b/ethereal/assets/heart.png deleted file mode 100644 index 3c874ab7f36da5f25e7295ee5572738941dfe2e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4277 zcmZ`*2{@GN`yNboQnpB?$&zBmF56fJV?>BBvdu6U`!Wp4nk9^63zH>OvMY*cNcMCL z*%g`?OGwJGCV$lL9RIG)T-P`AefM+U@AKTx`##q`aIucb(FKKWsUY22MxOg%}a`- zBM`o>MceD`D@guwWUdZMU>W#*U!ju96FwZJO z_=8iybp{N{6hQ<~*Ut9!t!L>2B)Kwe-^_^Qxy4FrbMbwS{Ynd9Ol?to;lm!kq3E0g z2zcl;6$gw(pdTI?%D_@*I~+Hct4ub~Qs+~f4JbDQ^vNsLthXe2!zw)QXwwKI-7}q& z7Rv+{7mZCzOwSs>?V5ORHfNFPo zbtXQ|Avbfpg;Ut5AafiycfL{(EKHv z7Yl0`T%9?(>7pdfcsQ0Z;tL0NzDDtFp8JP0H3vD4TQUa1G>k5A(Y3;2Z*wH8Z}f;f zI(F_xaURS_b>$3>zmC!R#^ybS9zj|9ZJOZ7BN?=PD7In1v#^m$WdTO`tF8}P0o+*( zyf5ET^lEva>@}}=DaXG6#G`Cqr7)^@Fw*tvSTG)6*3!IfAw+ZJv}+RRK5daU@izPY z9@=De? z{E;CJ6wMLXVucoad}~ar~jNm{{r!4Ps3#u zybw#C|nhT4w*K%EGDOQdKvnbu##>f<}#1jR{`U@FK(l zVq0Onlm|7=Ez7;%2yeU^`ub&$;HX`^#@(hzd2xA-s2o%Q#r{ljQc3T*0?PvBwhQ*p zyyKRklUGG5W3v&-h=fi9li~hxQ@c8HHJR0Q+F3-lM6SL)zw$j2S*kO5PqA60<9b2h z-Hr1ss__=_**s%Bw&IK8CKB`Fr;uXELl*AUpDH(-M_Y)l*7m{e(JqtrRoxHArk|D- zNlf@RE(R+Ttt-cP>MzxkSJ_uVTOwOh45~2!F(mf2VVwWj`pDpcBlEMA+U{k-B!g&> z=;J;_;Y2pFTdbR{yMTq2_X}^o#4(>W5+vj*Ha44ldW-EE7?fgu_vh_OVdlE1` z@=0W`R(gwdtUaO}!Ht-tHPm?e!S9Lf*YK&L)Z3{AVlqX&MSo!|Q369BqZT#lQ z^vV=*%A@N<=eN$S5IILVyq{Bp|BvYJO>&=I*~_8^%dOr$zl67Ls-yhfFrVly=&n2R zrAwzP0dsu9BW}Fk_?~fPgPn8L(sY~Vb4_CkNuv8IyIZRpx7*^FV^x{UyL6CE@89UI zk8vLjh2JO7PauQMH^$zqMlO;btUlPnfAD9-zaN{c`(}}eM%s+@lz*@;qrUl?|Fx#x ze4)V%b=BMMFgDR4v0D1k6Ovwq3w)sP)BR83{E5VA(x;%B#q81ccSDU6?xB4&33ROt z(34yOFG4%kj9kk!+*?uaDW%Qi`TS3HjZUGqp<0W&%SmK-6#PN^t3cznB;q3E!U z+M8<^ww<@_7bf#XnGMh76swhO53CP47LisK?hV(-Uiv-?pTc zkRiMODVe-Xg!a!fi-qRh7a_~fBzya=FyKDeJB|vHS z)*XXG2?n^kdH5;?sDkzxO1t-aFa#vHPr&7(qF(ELai*Wfl|^RPk|e zRJyFC^Gm+_qzZDz;k=X}5Ii0a#>;>`eViatii(O5Nok0*w8Sn$!Z*+ZhYFDJ@ICW$ zk^iluh4Hob!Fu7ao*sgG>!Q$}emGSSXfM$}pPzN&u#W#`^6>p-Yu6xTF9MMQOG5r6 z!vtXeL$(+BPnm=LKd!v|eBAauIoLxmZWwor2hMj_C-uj4yS@EK`2UIwKzaR4w%^2` z-cp*wYrz!{EDkEAvTx{j_}`BFRKYymy?ijfzPmE0+%L&N?03G!ziFTf z(!T@;!QTajKG0{!Bvd8Qdwl6sV{m$M`gZ!^F2LcC#4)#jEerOkrJ?_A6?e5wB+1ErlK@Pww zkUz3jc29zmfu{r3F;EMI!$74arDP=}cCLkYCwGprG@Tt%HhApSGvKWN3?Bfdg9Y+Dk(+B%Pm@wXldM0n?UX&~iu zmqx37-Da|8aQ>$oHx~l8f$TaKO99cdzEJe_jj7uMQ z%*Das9zv&9?%MHXMeC1zOz5TU=YD#GUgjCsQj?MxOcLNaKBvZqyw)fEY__`Rq`DO+ zy|;k}{U)od9x2>=Y(pS}2isL|sdwk;0F4pX^$H&H)!-PuEn;L_ndqr|?#g^U&r z#%3!y`Yxg=QA?8b9f#~?#+dU1_-uGa*j+&PTOq6XAc@O%v@3f#Y)xsk zZ