From b724d1aadac483984e7ea19931298dea43e3d280 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 27 Apr 2018 11:13:23 +0200 Subject: [PATCH 01/18] core/state: cache missing storage entries (#16584) --- core/state/state_object.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 3c40c20415..5d203fddd8 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -178,9 +178,7 @@ func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { } value.SetBytes(content) } - if (value != common.Hash{}) { - self.cachedStorage[key] = value - } + self.cachedStorage[key] = value return value } @@ -197,7 +195,6 @@ func (self *stateObject) SetState(db Database, key, value common.Hash) { func (self *stateObject) setState(key, value common.Hash) { self.cachedStorage[key] = value self.dirtyStorage[key] = value - } // updateTrie writes cached storage modifications into the object's storage trie. From 852aa143ac42907f6f9ed427a2ee1f85ffe7f524 Mon Sep 17 00:00:00 2001 From: Martin Klepsch Date: Fri, 27 Apr 2018 11:32:06 +0200 Subject: [PATCH 02/18] cmd/utils: point users to --syncmode under DEPRECATED (#16572) Indicate that --light and --fast options are replaced by --syncmode --- cmd/utils/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ba8378ef2d..ef5f6a9f08 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -158,11 +158,11 @@ var ( } FastSyncFlag = cli.BoolFlag{ Name: "fast", - Usage: "Enable fast syncing through state downloads", + Usage: "Enable fast syncing through state downloads (replaced by --syncmode)", } LightModeFlag = cli.BoolFlag{ Name: "light", - Usage: "Enable light client mode", + Usage: "Enable light client mode (replaced by --syncmode)", } defaultSyncMode = eth.DefaultConfig.SyncMode SyncModeFlag = TextMarshalerFlag{ From cfe8f5fd948954ccedd975b6630e455a4e5653db Mon Sep 17 00:00:00 2001 From: xincaosu Date: Fri, 27 Apr 2018 17:45:02 +0800 Subject: [PATCH 03/18] trie: remove unused `buf` parameter (#16583) --- trie/node.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trie/node.go b/trie/node.go index a7697fc0c6..02815042c6 100644 --- a/trie/node.go +++ b/trie/node.go @@ -123,17 +123,17 @@ func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { } switch c, _ := rlp.CountValues(elems); c { case 2: - n, err := decodeShort(hash, buf, elems, cachegen) + n, err := decodeShort(hash, elems, cachegen) return n, wrapError(err, "short") case 17: - n, err := decodeFull(hash, buf, elems, cachegen) + n, err := decodeFull(hash, elems, cachegen) return n, wrapError(err, "full") default: return nil, fmt.Errorf("invalid number of list elements: %v", c) } } -func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { +func decodeShort(hash, elems []byte, cachegen uint16) (node, error) { kbuf, rest, err := rlp.SplitString(elems) if err != nil { return nil, err @@ -155,7 +155,7 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { return &shortNode{key, r, flag}, nil } -func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) { +func decodeFull(hash, elems []byte, cachegen uint16) (*fullNode, error) { n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}} for i := 0; i < 16; i++ { cld, rest, err := decodeRef(elems, cachegen) From 7a7428a027de03ad9e80e89a70818c692193e60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Apr 2018 14:27:33 +0300 Subject: [PATCH 04/18] core, eth: fix tracer dirty finalization --- core/state/statedb.go | 21 --------------------- core/vm/evm.go | 5 +++++ eth/api_tracer.go | 5 +++-- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3ae6843d87..a952027d6d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -572,27 +572,6 @@ func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) { self.txIndex = ti } -// DeleteSuicides flags the suicided objects for deletion so that it -// won't be referenced again when called / queried up on. -// -// DeleteSuicides should not be used for consensus related updates -// under any circumstances. -func (s *StateDB) DeleteSuicides() { - // Reset refund so that any used-gas calculations can use this method. - s.clearJournalAndRefund() - - for addr := range s.stateObjectsDirty { - stateObject := s.stateObjects[addr] - - // If the object has been removed by a suicide - // flag the object as deleted. - if stateObject.suicided { - stateObject.deleted = true - } - delete(s.stateObjectsDirty, addr) - } -} - func (s *StateDB) clearJournalAndRefund() { s.journal = newJournal() s.validRevisions = s.validRevisions[:0] diff --git a/core/vm/evm.go b/core/vm/evm.go index 96676c314a..ea46209742 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -160,6 +160,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas precompiles = PrecompiledContractsByzantium } if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { + // Calling a non existing account, don't do antything, but ping the tracer + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + } return nil, gas, nil } evm.StateDB.CreateAccount(addr) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 07c4457bc3..80a3ab719d 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -201,7 +201,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } - task.statedb.DeleteSuicides() + task.statedb.Finalise(true) task.results[i] = &txTraceResult{Result: res} } // Stream the result back to the user or abort on teardown @@ -640,7 +640,8 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } - statedb.DeleteSuicides() + // Ensure any modifications are committed to the state + statedb.Finalise(true) } return nil, vm.Context{}, nil, fmt.Errorf("tx index %d out of range for block %x", txIndex, blockHash) } From ea171d5bd90b9102cffdb6de440025db9e808cdc Mon Sep 17 00:00:00 2001 From: Domino Valdano Date: Tue, 1 May 2018 11:28:14 -0700 Subject: [PATCH 05/18] travis.yml: remove obsolete brew-cask install --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2ba6f18f26..194ca63969 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,6 @@ matrix: script: - unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703 - brew update - - brew install caskroom/cask/brew-cask - brew cask install osxfuse - go run build/ci.go install - go run build/ci.go test -coverage $TEST_PACKAGES From 9f6af6f812453f7ba30822606bb2a04ba8872ccb Mon Sep 17 00:00:00 2001 From: Eli Date: Tue, 1 May 2018 23:17:17 -0700 Subject: [PATCH 06/18] whisper: Golint fixes in whisper packages (#16637) --- whisper/shhclient/client.go | 3 +- whisper/whisperv5/api.go | 4 +- whisper/whisperv5/doc.go | 2 +- whisper/whisperv5/message.go | 6 +-- whisper/whisperv5/peer.go | 52 +++++++++++------------ whisper/whisperv5/peer_test.go | 6 +-- whisper/whisperv5/topic.go | 2 +- whisper/whisperv5/whisper.go | 77 ++++++++++++++++------------------ 8 files changed, 74 insertions(+), 78 deletions(-) diff --git a/whisper/shhclient/client.go b/whisper/shhclient/client.go index bbe694baaa..7b25e739e1 100644 --- a/whisper/shhclient/client.go +++ b/whisper/shhclient/client.go @@ -67,7 +67,6 @@ func (sc *Client) SetMaxMessageSize(ctx context.Context, size uint32) error { } // SetMinimumPoW (experimental) sets the minimal PoW required by this node. - // This experimental function was introduced for the future dynamic adjustment of // PoW requirement. If the node is overwhelmed with messages, it should raise the // PoW requirement and notify the peers. The new value should be set relative to @@ -77,7 +76,7 @@ func (sc *Client) SetMinimumPoW(ctx context.Context, pow float64) error { return sc.c.CallContext(ctx, &ignored, "shh_setMinPoW", pow) } -// Marks specific peer trusted, which will allow it to send historic (expired) messages. +// MarkTrustedPeer marks specific peer trusted, which will allow it to send historic (expired) messages. // Note This function is not adding new nodes, the node needs to exists as a peer. func (sc *Client) MarkTrustedPeer(ctx context.Context, enode string) error { var ignored bool diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go index 9fb22aa752..c56d139499 100644 --- a/whisper/whisperv5/api.go +++ b/whisper/whisperv5/api.go @@ -89,7 +89,7 @@ func (api *PublicWhisperAPI) SetMaxMessageSize(ctx context.Context, size uint32) return true, api.w.SetMaxMessageSize(size) } -// SetMinPow sets the minimum PoW for a message before it is accepted. +// SetMinPoW sets the minimum PoW for a message before it is accepted. func (api *PublicWhisperAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error) { return true, api.w.SetMinimumPoW(pow) } @@ -142,7 +142,7 @@ func (api *PublicWhisperAPI) GetPublicKey(ctx context.Context, id string) (hexut return crypto.FromECDSAPub(&key.PublicKey), nil } -// GetPublicKey returns the private key associated with the given key. The key is the hex +// GetPrivateKey returns the private key associated with the given key. The key is the hex // encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. func (api *PublicWhisperAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) { key, err := api.w.GetPrivateKey(id) diff --git a/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go index 7a57488bd7..8161db8ed6 100644 --- a/whisper/whisperv5/doc.go +++ b/whisper/whisperv5/doc.go @@ -15,7 +15,7 @@ // along with the go-ethereum library. If not, see . /* -Package whisper implements the Whisper protocol (version 5). +Package whisperv5 implements the Whisper protocol (version 5). Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP). As such it may be likened and compared to both, not dissimilar to the diff --git a/whisper/whisperv5/message.go b/whisper/whisperv5/message.go index 34ce52e64f..35711d724b 100644 --- a/whisper/whisperv5/message.go +++ b/whisper/whisperv5/message.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// Options specifies the exact way a message should be wrapped into an Envelope. +// MessageParams specifies the exact way a message should be wrapped into an Envelope. type MessageParams struct { TTL uint32 Src *ecdsa.PrivateKey @@ -86,7 +86,7 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool { return msg.Dst != nil } -// NewMessage creates and initializes a non-signed, non-encrypted Whisper message. +// NewSentMessage creates and initializes a non-signed, non-encrypted Whisper message. func NewSentMessage(params *MessageParams) (*sentMessage, error) { msg := sentMessage{} msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) @@ -330,7 +330,7 @@ func (msg *ReceivedMessage) extractPadding(end int) (int, bool) { return paddingSize, true } -// Recover retrieves the public key of the message signer. +// SigToPubKey retrieves the public key of the message signer. func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { defer func() { recover() }() // in case of invalid signature diff --git a/whisper/whisperv5/peer.go b/whisper/whisperv5/peer.go index 179c931795..da07631992 100644 --- a/whisper/whisperv5/peer.go +++ b/whisper/whisperv5/peer.go @@ -27,7 +27,7 @@ import ( set "gopkg.in/fatih/set.v0" ) -// peer represents a whisper protocol peer connection. +// Peer represents a whisper protocol peer connection. type Peer struct { host *Whisper peer *p2p.Peer @@ -53,51 +53,51 @@ func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { // start initiates the peer updater, periodically broadcasting the whisper packets // into the network. -func (p *Peer) start() { - go p.update() - log.Trace("start", "peer", p.ID()) +func (peer *Peer) start() { + go peer.update() + log.Trace("start", "peer", peer.ID()) } // stop terminates the peer updater, stopping message forwarding to it. -func (p *Peer) stop() { - close(p.quit) - log.Trace("stop", "peer", p.ID()) +func (peer *Peer) stop() { + close(peer.quit) + log.Trace("stop", "peer", peer.ID()) } // handshake sends the protocol initiation status message to the remote peer and // verifies the remote status too. -func (p *Peer) handshake() error { +func (peer *Peer) handshake() error { // Send the handshake status message asynchronously errc := make(chan error, 1) go func() { - errc <- p2p.Send(p.ws, statusCode, ProtocolVersion) + errc <- p2p.Send(peer.ws, statusCode, ProtocolVersion) }() // Fetch the remote status packet and verify protocol match - packet, err := p.ws.ReadMsg() + packet, err := peer.ws.ReadMsg() if err != nil { return err } if packet.Code != statusCode { - return fmt.Errorf("peer [%x] sent packet %x before status packet", p.ID(), packet.Code) + return fmt.Errorf("peer [%x] sent packet %x before status packet", peer.ID(), packet.Code) } s := rlp.NewStream(packet.Payload, uint64(packet.Size)) peerVersion, err := s.Uint() if err != nil { - return fmt.Errorf("peer [%x] sent bad status message: %v", p.ID(), err) + return fmt.Errorf("peer [%x] sent bad status message: %v", peer.ID(), err) } if peerVersion != ProtocolVersion { - return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", p.ID(), peerVersion, ProtocolVersion) + return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", peer.ID(), peerVersion, ProtocolVersion) } // Wait until out own status is consumed too if err := <-errc; err != nil { - return fmt.Errorf("peer [%x] failed to send status packet: %v", p.ID(), err) + return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err) } return nil } // update executes periodic operations on the peer, including message transmission // and expiration. -func (p *Peer) update() { +func (peer *Peer) update() { // Start the tickers for the updates expire := time.NewTicker(expirationCycle) transmit := time.NewTicker(transmissionCycle) @@ -106,15 +106,15 @@ func (p *Peer) update() { for { select { case <-expire.C: - p.expire() + peer.expire() case <-transmit.C: - if err := p.broadcast(); err != nil { - log.Trace("broadcast failed", "reason", err, "peer", p.ID()) + if err := peer.broadcast(); err != nil { + log.Trace("broadcast failed", "reason", err, "peer", peer.ID()) return } - case <-p.quit: + case <-peer.quit: return } } @@ -148,16 +148,16 @@ func (peer *Peer) expire() { // broadcast iterates over the collection of envelopes and transmits yet unknown // ones over the network. -func (p *Peer) broadcast() error { +func (peer *Peer) broadcast() error { var cnt int - envelopes := p.host.Envelopes() + envelopes := peer.host.Envelopes() for _, envelope := range envelopes { - if !p.marked(envelope) { - err := p2p.Send(p.ws, messagesCode, envelope) + if !peer.marked(envelope) { + err := p2p.Send(peer.ws, messagesCode, envelope) if err != nil { return err } else { - p.mark(envelope) + peer.mark(envelope) cnt++ } } @@ -168,7 +168,7 @@ func (p *Peer) broadcast() error { return nil } -func (p *Peer) ID() []byte { - id := p.peer.ID() +func (peer *Peer) ID() []byte { + id := peer.peer.ID() return id[:] } diff --git a/whisper/whisperv5/peer_test.go b/whisper/whisperv5/peer_test.go index bae2adb6f5..051b52dcf8 100644 --- a/whisper/whisperv5/peer_test.go +++ b/whisper/whisperv5/peer_test.go @@ -32,7 +32,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" ) -var keys []string = []string{ +var keys = []string{ "d49dcf37238dc8a7aac57dc61b9fee68f0a97f062968978b9fafa7d1033d03a9", "73fd6143c48e80ed3c56ea159fe7494a0b6b393a392227b422f4c3e8f1b54f98", "119dd32adb1daa7a4c7bf77f847fb28730785aa92947edf42fdd997b54de40dc", @@ -84,9 +84,9 @@ type TestNode struct { var result TestData var nodes [NumNodes]*TestNode -var sharedKey []byte = []byte("some arbitrary data here") +var sharedKey = []byte("some arbitrary data here") var sharedTopic TopicType = TopicType{0xF, 0x1, 0x2, 0} -var expectedMessage []byte = []byte("per rectum ad astra") +var expectedMessage = []byte("per rectum ad astra") // This test does the following: // 1. creates a chain of whisper nodes, diff --git a/whisper/whisperv5/topic.go b/whisper/whisperv5/topic.go index c4ea67eefa..c4eda1db42 100644 --- a/whisper/whisperv5/topic.go +++ b/whisper/whisperv5/topic.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ) -// Topic represents a cryptographically secure, probabilistic partial +// TopicType represents a cryptographically secure, probabilistic partial // classifications of a message, determined as the first (left) 4 bytes of the // SHA3 hash of some arbitrary data given by the original author of the message. type TopicType [TopicLength]byte diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go index 85849ccce4..62bd1ce179 100644 --- a/whisper/whisperv5/whisper.go +++ b/whisper/whisperv5/whisper.go @@ -469,18 +469,18 @@ func (w *Whisper) Stop() error { // HandlePeer is called by the underlying P2P layer when the whisper sub-protocol // connection is negotiated. -func (wh *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { +func (w *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { // Create the new peer and start tracking it - whisperPeer := newPeer(wh, peer, rw) + whisperPeer := newPeer(w, peer, rw) - wh.peerMu.Lock() - wh.peers[whisperPeer] = struct{}{} - wh.peerMu.Unlock() + w.peerMu.Lock() + w.peers[whisperPeer] = struct{}{} + w.peerMu.Unlock() defer func() { - wh.peerMu.Lock() - delete(wh.peers, whisperPeer) - wh.peerMu.Unlock() + w.peerMu.Lock() + delete(w.peers, whisperPeer) + w.peerMu.Unlock() }() // Run the peer handshake and state updates @@ -490,11 +490,11 @@ func (wh *Whisper) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { whisperPeer.start() defer whisperPeer.stop() - return wh.runMessageLoop(whisperPeer, rw) + return w.runMessageLoop(whisperPeer, rw) } // runMessageLoop reads and processes inbound messages directly to merge into client-global state. -func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { +func (w *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { for { // fetch the next packet packet, err := rw.ReadMsg() @@ -502,7 +502,7 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { log.Warn("message loop", "peer", p.peer.ID(), "err", err) return err } - if packet.Size > wh.MaxMessageSize() { + if packet.Size > w.MaxMessageSize() { log.Warn("oversized message received", "peer", p.peer.ID()) return errors.New("oversized message received") } @@ -518,7 +518,7 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err) return errors.New("invalid envelope") } - cached, err := wh.add(&envelope) + cached, err := w.add(&envelope) if err != nil { log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err) return errors.New("invalid envelope") @@ -537,17 +537,17 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { log.Warn("failed to decode direct message, peer will be disconnected", "peer", p.peer.ID(), "err", err) return errors.New("invalid direct message") } - wh.postEvent(&envelope, true) + w.postEvent(&envelope, true) } case p2pRequestCode: // Must be processed if mail server is implemented. Otherwise ignore. - if wh.mailServer != nil { + if w.mailServer != nil { var request Envelope if err := packet.Decode(&request); err != nil { log.Warn("failed to decode p2p request message, peer will be disconnected", "peer", p.peer.ID(), "err", err) return errors.New("invalid p2p request") } - wh.mailServer.DeliverMail(p, &request) + w.mailServer.DeliverMail(p, &request) } default: // New message types might be implemented in the future versions of Whisper. @@ -561,29 +561,27 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { // add inserts a new envelope into the message pool to be distributed within the // whisper network. It also inserts the envelope into the expiration pool at the // appropriate time-stamp. In case of error, connection should be dropped. -func (wh *Whisper) add(envelope *Envelope) (bool, error) { +func (w *Whisper) add(envelope *Envelope) (bool, error) { now := uint32(time.Now().Unix()) sent := envelope.Expiry - envelope.TTL if sent > now { if sent-SynchAllowance > now { return false, fmt.Errorf("envelope created in the future [%x]", envelope.Hash()) - } else { - // recalculate PoW, adjusted for the time difference, plus one second for latency - envelope.calculatePoW(sent - now + 1) } + // recalculate PoW, adjusted for the time difference, plus one second for latency + envelope.calculatePoW(sent - now + 1) } if envelope.Expiry < now { if envelope.Expiry+SynchAllowance*2 < now { return false, fmt.Errorf("very old message") - } else { - log.Debug("expired envelope dropped", "hash", envelope.Hash().Hex()) - return false, nil // drop envelope without error } + log.Debug("expired envelope dropped", "hash", envelope.Hash().Hex()) + return false, nil // drop envelope without error } - if uint32(envelope.size()) > wh.MaxMessageSize() { + if uint32(envelope.size()) > w.MaxMessageSize() { return false, fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash()) } @@ -598,36 +596,36 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) { return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash()) } - if envelope.PoW() < wh.MinPow() { + if envelope.PoW() < w.MinPow() { log.Debug("envelope with low PoW dropped", "PoW", envelope.PoW(), "hash", envelope.Hash().Hex()) return false, nil // drop envelope without error } hash := envelope.Hash() - wh.poolMu.Lock() - _, alreadyCached := wh.envelopes[hash] + w.poolMu.Lock() + _, alreadyCached := w.envelopes[hash] if !alreadyCached { - wh.envelopes[hash] = envelope - if wh.expirations[envelope.Expiry] == nil { - wh.expirations[envelope.Expiry] = set.NewNonTS() + w.envelopes[hash] = envelope + if w.expirations[envelope.Expiry] == nil { + w.expirations[envelope.Expiry] = set.NewNonTS() } - if !wh.expirations[envelope.Expiry].Has(hash) { - wh.expirations[envelope.Expiry].Add(hash) + if !w.expirations[envelope.Expiry].Has(hash) { + w.expirations[envelope.Expiry].Add(hash) } } - wh.poolMu.Unlock() + w.poolMu.Unlock() if alreadyCached { log.Trace("whisper envelope already cached", "hash", envelope.Hash().Hex()) } else { log.Trace("cached whisper envelope", "hash", envelope.Hash().Hex()) - wh.statsMu.Lock() - wh.stats.memoryUsed += envelope.size() - wh.statsMu.Unlock() - wh.postEvent(envelope, false) // notify the local node about the new message - if wh.mailServer != nil { - wh.mailServer.Archive(envelope) + w.statsMu.Lock() + w.stats.memoryUsed += envelope.size() + w.statsMu.Unlock() + w.postEvent(envelope, false) // notify the local node about the new message + if w.mailServer != nil { + w.mailServer.Archive(envelope) } } return true, nil @@ -838,9 +836,8 @@ func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error // because it's a once in a session experience derivedKey := pbkdf2.Key(key, nil, 65356, aesKeyLength, sha256.New) return derivedKey, nil - } else { - return nil, unknownVersionError(version) } + return nil, unknownVersionError(version) } // GenerateRandomID generates a random string, which is then returned to be used as a key id From a1949d0788ecb1d890677bdd26c0e711ddf639b2 Mon Sep 17 00:00:00 2001 From: timothy Date: Tue, 1 May 2018 19:00:12 +0200 Subject: [PATCH 07/18] vendor: fix leveldb crash when bigger than 1 TiB --- .../goleveldb/leveldb/storage/mem_storage.go | 8 ++- .../syndtr/goleveldb/leveldb/util.go | 2 +- vendor/vendor.json | 52 +++++++++---------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go index 9b0421f035..838f1bee1b 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/mem_storage.go @@ -12,7 +12,11 @@ import ( "sync" ) -const typeShift = 3 +const typeShift = 4 + +// Verify at compile-time that typeShift is large enough to cover all FileType +// values by confirming that 0 == 0. +var _ [0]struct{} = [TypeAll >> typeShift]struct{}{} type memStorageLock struct { ms *memStorage @@ -143,7 +147,7 @@ func (ms *memStorage) Remove(fd FileDesc) error { } func (ms *memStorage) Rename(oldfd, newfd FileDesc) error { - if FileDescOk(oldfd) || FileDescOk(newfd) { + if !FileDescOk(oldfd) || !FileDescOk(newfd) { return ErrInvalidFile } if oldfd == newfd { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/util.go b/vendor/github.com/syndtr/goleveldb/leveldb/util.go index e572a329e9..0e2b519e5c 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/util.go @@ -20,7 +20,7 @@ func shorten(str string) string { return str[:3] + ".." + str[len(str)-3:] } -var bunits = [...]string{"", "Ki", "Mi", "Gi"} +var bunits = [...]string{"", "Ki", "Mi", "Gi", "Ti"} func shortenb(bytes int) string { i := 0 diff --git a/vendor/vendor.json b/vendor/vendor.json index e083a363ba..fdc7789364 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -418,76 +418,76 @@ "revisionTime": "2017-07-05T02:17:15Z" }, { - "checksumSHA1": "3QsnhPTXGytTbW3uDvQLgSo9s9M=", + "checksumSHA1": "k13cCuMJO7+KhR8ZXx5oUqDKGQA=", "path": "github.com/syndtr/goleveldb/leveldb", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=", "path": "github.com/syndtr/goleveldb/leveldb/cache", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=", "path": "github.com/syndtr/goleveldb/leveldb/comparer", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=", "path": "github.com/syndtr/goleveldb/leveldb/errors", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=", "path": "github.com/syndtr/goleveldb/leveldb/filter", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "weSsccMav4BCerDpSLzh3mMxAYo=", "path": "github.com/syndtr/goleveldb/leveldb/iterator", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=", "path": "github.com/syndtr/goleveldb/leveldb/journal", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "MtYY1b2234y/MlS+djL8tXVAcQs=", "path": "github.com/syndtr/goleveldb/leveldb/memdb", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=", "path": "github.com/syndtr/goleveldb/leveldb/opt", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { - "checksumSHA1": "QCSae2ub87f8awH+PKMpd8ZYOtg=", + "checksumSHA1": "7H3fa12T7WoMAeXq1+qG5O7LD0w=", "path": "github.com/syndtr/goleveldb/leveldb/storage", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "gWFPMz8OQeul0t54RM66yMTX49g=", "path": "github.com/syndtr/goleveldb/leveldb/table", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "V/Dh7NV0/fy/5jX1KaAjmGcNbzI=", "path": "github.com/syndtr/goleveldb/leveldb/util", - "revision": "169b1b37be738edb2813dab48c97a549bcf99bb5", - "revisionTime": "2018-03-07T11:33:52Z" + "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", + "revisionTime": "2018-05-02T07:23:49Z" }, { "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", From 0afd7675372798bd1a71c6a78472835a54d60b54 Mon Sep 17 00:00:00 2001 From: Crispin Flowerday Date: Thu, 26 Apr 2018 16:43:18 -0700 Subject: [PATCH 08/18] core: ensure local transactions aren't discarded as underpriced This fixes an issue where local transactions are discarded as underpriced when the pool and queue are full. --- core/tx_pool.go | 2 +- core/tx_pool_test.go | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index b21384458a..388b40058f 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -618,7 +618,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { // If the transaction pool is full, discard underpriced transactions if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it - if pool.priced.Underpriced(tx, pool.locals) { + if !local && pool.priced.Underpriced(tx, pool.locals) { log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) underpricedTxCounter.Inc(1) return false, ErrUnderpriced diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 0cb14cb6a4..f0f86415d4 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -1346,7 +1346,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { defer sub.Unsubscribe() // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 3) + keys := make([]*ecdsa.PrivateKey, 4) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) @@ -1406,18 +1406,22 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding local transactions can push out even higher priced ones - tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2]) - if err := pool.AddLocal(tx); err != nil { - t.Fatalf("failed to add underpriced local transaction: %v", err) + ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2]) + if err := pool.AddLocal(ltx); err != nil { + t.Fatalf("failed to append underpriced local transaction: %v", err) + } + ltx = pricedTransaction(0, 100000, big.NewInt(0), keys[3]) + if err := pool.AddLocal(ltx); err != nil { + t.Fatalf("failed to add new underpriced local transaction: %v", err) } pending, queued = pool.Stats() - if pending != 2 { - t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) + if pending != 3 { + t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 3) } - if queued != 2 { - t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) + if queued != 1 { + t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) } - if err := validateEvents(events, 1); err != nil { + if err := validateEvents(events, 2); err != nil { t.Fatalf("local event firing failed: %v", err) } if err := validateTxPoolInternals(pool); err != nil { From 8dfa4f46a95c3755396c9be84704cfdf7102ff8e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 26 Apr 2018 10:30:23 +0200 Subject: [PATCH 09/18] evm/main: use blocknumber from genesis --- cmd/evm/runner.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 2d9d31fb08..99919304ae 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -21,12 +21,12 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/big" "os" + goruntime "runtime" "runtime/pprof" "time" - goruntime "runtime" - "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" @@ -86,6 +86,7 @@ func runCmd(ctx *cli.Context) error { chainConfig *params.ChainConfig sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) + blockNumber uint64 ) if ctx.GlobalBool(MachineFlag.Name) { tracer = NewJSONLogger(logconfig, os.Stdout) @@ -101,6 +102,7 @@ func runCmd(ctx *cli.Context) error { genesis := gen.ToBlock(db) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) chainConfig = gen.Config + blockNumber = gen.Number } else { db, _ := ethdb.NewMemDatabase() statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) @@ -156,11 +158,12 @@ func runCmd(ctx *cli.Context) error { initialGas := ctx.GlobalUint64(GasFlag.Name) runtimeConfig := runtime.Config{ - Origin: sender, - State: statedb, - GasLimit: initialGas, - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), + Origin: sender, + State: statedb, + GasLimit: initialGas, + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + BlockNumber: new(big.Int).SetUint64(blockNumber), EVMConfig: vm.Config{ Tracer: tracer, Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), From c1ea52757358d2e9d87c636a9519ffdc74ea8ac0 Mon Sep 17 00:00:00 2001 From: kiel barry Date: Wed, 2 May 2018 01:17:52 -0700 Subject: [PATCH 10/18] accounts: golint updates for this or self warning (#16627) --- accounts/abi/event.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/abi/event.go b/accounts/abi/event.go index 595f169f3a..a3f6be9732 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -33,15 +33,15 @@ type Event struct { Inputs Arguments } -func (event Event) String() string { - inputs := make([]string, len(event.Inputs)) - for i, input := range event.Inputs { +func (e Event) String() string { + inputs := make([]string, len(e.Inputs)) + for i, input := range e.Inputs { inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) if input.Indexed { inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type) } } - return fmt.Sprintf("event %v(%v)", event.Name, strings.Join(inputs, ", ")) + return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", ")) } // Id returns the canonical representation of the event's signature used by the From d76c5ca532bfeba5469ed42985630116a1f41ebe Mon Sep 17 00:00:00 2001 From: Eli Date: Wed, 2 May 2018 01:20:19 -0700 Subject: [PATCH 11/18] tests: golint fixes for tests directory (#16640) --- tests/block_test_util.go | 2 +- tests/init.go | 2 +- tests/init_test.go | 11 +++++------ tests/transaction_test_util.go | 3 +-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index beba484833..579e783b10 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -104,7 +104,7 @@ func (t *BlockTest) Run() error { return err } if gblock.Hash() != t.json.Genesis.Hash { - return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x\n", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) + return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) } if gblock.Root() != t.json.Genesis.StateRoot { return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6]) diff --git a/tests/init.go b/tests/init.go index ff8ee7da18..0bea5ccd63 100644 --- a/tests/init.go +++ b/tests/init.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// This table defines supported forks and their chain config. +// Forks table defines supported forks and their chain config. var Forks = map[string]*params.ChainConfig{ "Frontier": { ChainId: big.NewInt(1), diff --git a/tests/init_test.go b/tests/init_test.go index fbb214b08c..26e919d24b 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -42,7 +42,7 @@ var ( difficultyTestDir = filepath.Join(baseDir, "BasicTests") ) -func readJson(reader io.Reader, value interface{}) error { +func readJSON(reader io.Reader, value interface{}) error { data, err := ioutil.ReadAll(reader) if err != nil { return fmt.Errorf("error reading JSON file: %v", err) @@ -57,14 +57,14 @@ func readJson(reader io.Reader, value interface{}) error { return nil } -func readJsonFile(fn string, value interface{}) error { +func readJSONFile(fn string, value interface{}) error { file, err := os.Open(fn) if err != nil { return err } defer file.Close() - err = readJson(file, value) + err = readJSON(file, value) if err != nil { return fmt.Errorf("%s in file %s", err.Error(), fn) } @@ -169,9 +169,8 @@ func (tm *testMatcher) checkFailure(t *testing.T, name string, err error) error if err != nil { t.Logf("error: %v", err) return nil - } else { - return fmt.Errorf("test succeeded unexpectedly") } + return fmt.Errorf("test succeeded unexpectedly") } return err } @@ -213,7 +212,7 @@ func (tm *testMatcher) runTestFile(t *testing.T, path, name string, runTest inte // Load the file as map[string]. m := makeMapFromTestFunc(runTest) - if err := readJsonFile(path, m.Addr().Interface()); err != nil { + if err := readJSONFile(path, m.Addr().Interface()); err != nil { t.Fatal(err) } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 2028d2a278..8c3dac088c 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -72,9 +72,8 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { if err := rlp.DecodeBytes(tt.json.RLP, tx); err != nil { if tt.json.Transaction == nil { return nil - } else { - return fmt.Errorf("RLP decoding failed: %v", err) } + return fmt.Errorf("RLP decoding failed: %v", err) } // Check sender derivation. signer := types.MakeSigner(config, new(big.Int).SetUint64(uint64(tt.json.BlockNumber))) From 4a8d5d2b1e6e78550ebc3495d9d87787dedadb20 Mon Sep 17 00:00:00 2001 From: Eli Date: Wed, 2 May 2018 01:24:34 -0700 Subject: [PATCH 12/18] trie: golint iterator fixes (#16639) --- trie/iterator.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/trie/iterator.go b/trie/iterator.go index 76146c0d64..3bae8e186b 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -303,7 +303,7 @@ func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path [] it.path = path it.stack = append(it.stack, state) if parentIndex != nil { - *parentIndex += 1 + *parentIndex++ } } @@ -380,7 +380,7 @@ func (it *differenceIterator) Next(bool) bool { if !it.b.Next(true) { return false } - it.count += 1 + it.count++ if it.eof { // a has reached eof, so we just return all elements from b @@ -395,7 +395,7 @@ func (it *differenceIterator) Next(bool) bool { it.eof = true return true } - it.count += 1 + it.count++ case 1: // b is before a return true @@ -405,12 +405,12 @@ func (it *differenceIterator) Next(bool) bool { if !it.b.Next(hasHash) { return false } - it.count += 1 + it.count++ if !it.a.Next(hasHash) { it.eof = true return true } - it.count += 1 + it.count++ } } } @@ -504,14 +504,14 @@ func (it *unionIterator) Next(descend bool) bool { skipped := heap.Pop(it.items).(NodeIterator) // Skip the whole subtree if the nodes have hashes; otherwise just skip this node if skipped.Next(skipped.Hash() == common.Hash{}) { - it.count += 1 + it.count++ // If there are more elements, push the iterator back on the heap heap.Push(it.items, skipped) } } if least.Next(descend) { - it.count += 1 + it.count++ heap.Push(it.items, least) } From 670bae4cd3e6b34d6db008b22b6f5c2afcb07e0a Mon Sep 17 00:00:00 2001 From: kiel barry Date: Wed, 2 May 2018 01:26:21 -0700 Subject: [PATCH 13/18] internal: golint updates for this or self warning (#16634) --- internal/jsre/jsre.go | 54 +++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index f05865eca6..4c7664f1cc 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -102,8 +102,8 @@ func randomSource() *rand.Rand { // call the functions of the otto vm directly to circumvent the queue. These // functions should be used if and only if running a routine that was already // called from JS through an RPC call. -func (self *JSRE) runEventLoop() { - defer close(self.closed) +func (re *JSRE) runEventLoop() { + defer close(re.closed) vm := otto.New() r := randomSource() @@ -202,14 +202,14 @@ loop: break loop } } - case req := <-self.evalQueue: + case req := <-re.evalQueue: // run the code, send the result back req.fn(vm) close(req.done) if waitForCallbacks && (len(registry) == 0) { break loop } - case waitForCallbacks = <-self.stopEventLoop: + case waitForCallbacks = <-re.stopEventLoop: if !waitForCallbacks || (len(registry) == 0) { break loop } @@ -223,31 +223,31 @@ loop: } // Do executes the given function on the JS event loop. -func (self *JSRE) Do(fn func(*otto.Otto)) { +func (re *JSRE) Do(fn func(*otto.Otto)) { done := make(chan bool) req := &evalReq{fn, done} - self.evalQueue <- req + re.evalQueue <- req <-done } // stops the event loop before exit, optionally waits for all timers to expire -func (self *JSRE) Stop(waitForCallbacks bool) { +func (re *JSRE) Stop(waitForCallbacks bool) { select { - case <-self.closed: - case self.stopEventLoop <- waitForCallbacks: - <-self.closed + case <-re.closed: + case re.stopEventLoop <- waitForCallbacks: + <-re.closed } } // Exec(file) loads and runs the contents of a file // if a relative path is given, the jsre's assetPath is used -func (self *JSRE) Exec(file string) error { - code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file)) +func (re *JSRE) Exec(file string) error { + code, err := ioutil.ReadFile(common.AbsolutePath(re.assetPath, file)) if err != nil { return err } var script *otto.Script - self.Do(func(vm *otto.Otto) { + re.Do(func(vm *otto.Otto) { script, err = vm.Compile(file, code) if err != nil { return @@ -259,36 +259,36 @@ func (self *JSRE) Exec(file string) error { // Bind assigns value v to a variable in the JS environment // This method is deprecated, use Set. -func (self *JSRE) Bind(name string, v interface{}) error { - return self.Set(name, v) +func (re *JSRE) Bind(name string, v interface{}) error { + return re.Set(name, v) } // Run runs a piece of JS code. -func (self *JSRE) Run(code string) (v otto.Value, err error) { - self.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) +func (re *JSRE) Run(code string) (v otto.Value, err error) { + re.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) return v, err } // Get returns the value of a variable in the JS environment. -func (self *JSRE) Get(ns string) (v otto.Value, err error) { - self.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) +func (re *JSRE) Get(ns string) (v otto.Value, err error) { + re.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) return v, err } // Set assigns value v to a variable in the JS environment. -func (self *JSRE) Set(ns string, v interface{}) (err error) { - self.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) +func (re *JSRE) Set(ns string, v interface{}) (err error) { + re.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) return err } // loadScript executes a JS script from inside the currently executing JS code. -func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { +func (re *JSRE) loadScript(call otto.FunctionCall) otto.Value { file, err := call.Argument(0).ToString() if err != nil { // TODO: throw exception return otto.FalseValue() } - file = common.AbsolutePath(self.assetPath, file) + file = common.AbsolutePath(re.assetPath, file) source, err := ioutil.ReadFile(file) if err != nil { // TODO: throw exception @@ -305,10 +305,10 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { // Evaluate executes code and pretty prints the result to the specified output // stream. -func (self *JSRE) Evaluate(code string, w io.Writer) error { +func (re *JSRE) Evaluate(code string, w io.Writer) error { var fail error - self.Do(func(vm *otto.Otto) { + re.Do(func(vm *otto.Otto) { val, err := vm.Run(code) if err != nil { prettyError(vm, err, w) @@ -321,8 +321,8 @@ func (self *JSRE) Evaluate(code string, w io.Writer) error { } // Compile compiles and then runs a piece of JS code. -func (self *JSRE) Compile(filename string, src interface{}) (err error) { - self.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) +func (re *JSRE) Compile(filename string, src interface{}) (err error) { + re.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) return err } From a7720b592687706e4de954b7ee9e586ff21e455c Mon Sep 17 00:00:00 2001 From: kiel barry Date: Wed, 2 May 2018 01:27:59 -0700 Subject: [PATCH 14/18] core: golint updates for this or self warning (#16633) --- core/vm/contract.go | 14 +++++++------- core/vm/logger.go | 4 ++-- core/vm/memory.go | 12 ++++++------ core/vm/opcodes.go | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index 66748e8215..b466681dbd 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -139,15 +139,15 @@ func (c *Contract) Value() *big.Int { } // SetCode sets the code to the contract -func (self *Contract) SetCode(hash common.Hash, code []byte) { - self.Code = code - self.CodeHash = hash +func (c *Contract) SetCode(hash common.Hash, code []byte) { + c.Code = code + c.CodeHash = hash } // SetCallCode sets the code of the contract and address of the backing data // object -func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { - self.Code = code - self.CodeHash = hash - self.CodeAddr = addr +func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { + c.Code = code + c.CodeHash = hash + c.CodeAddr = addr } diff --git a/core/vm/logger.go b/core/vm/logger.go index dde1903bf2..c32a7b4044 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -31,9 +31,9 @@ import ( type Storage map[common.Hash]common.Hash -func (self Storage) Copy() Storage { +func (s Storage) Copy() Storage { cpy := make(Storage) - for key, value := range self { + for key, value := range s { cpy[key] = value } diff --git a/core/vm/memory.go b/core/vm/memory.go index 99a84d2271..d5cc7870bc 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -51,14 +51,14 @@ func (m *Memory) Resize(size uint64) { } // Get returns offset + size as a new slice -func (self *Memory) Get(offset, size int64) (cpy []byte) { +func (m *Memory) Get(offset, size int64) (cpy []byte) { if size == 0 { return nil } - if len(self.store) > int(offset) { + if len(m.store) > int(offset) { cpy = make([]byte, size) - copy(cpy, self.store[offset:offset+size]) + copy(cpy, m.store[offset:offset+size]) return } @@ -67,13 +67,13 @@ func (self *Memory) Get(offset, size int64) (cpy []byte) { } // GetPtr returns the offset + size -func (self *Memory) GetPtr(offset, size int64) []byte { +func (m *Memory) GetPtr(offset, size int64) []byte { if size == 0 { return nil } - if len(self.store) > int(offset) { - return self.store[offset : offset+size] + if len(m.store) > int(offset) { + return m.store[offset : offset+size] } return nil diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 7fe55b72f6..e3568eb000 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -375,10 +375,10 @@ var opCodeToString = map[OpCode]string{ SWAP: "SWAP", } -func (o OpCode) String() string { - str := opCodeToString[o] +func (op OpCode) String() string { + str := opCodeToString[op] if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) + return fmt.Sprintf("Missing opcode 0x%x", int(op)) } return str From 58c4e033f4791696da7cb1de633b55af337fd976 Mon Sep 17 00:00:00 2001 From: ligi Date: Wed, 2 May 2018 11:07:44 +0200 Subject: [PATCH 15/18] build: Add ldflags -s -w when building aar Smaller size on mobile is always good. Might also solve our maven central upload problem --- build/ci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 5fce3c8e60..204c206752 100644 --- a/build/ci.go +++ b/build/ci.go @@ -731,7 +731,7 @@ func doAndroidArchive(cmdline []string) { // Build the Android archive and Maven resources build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK"))) - build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) + build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) if *local { // If we're building locally, copy bundle to build dir and skip Maven @@ -852,7 +852,7 @@ func doXCodeFramework(cmdline []string) { // Build the iOS XCode framework build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) build.MustRun(gomobileTool("init")) - bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") + bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") if *local { // If we're building locally, use the build folder and stop afterwards From 5d4d79ae2672b295a539cf3ce0163b2cb10eb2b2 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 2 May 2018 12:31:05 +0200 Subject: [PATCH 16/18] cmd/clef: documentation about setup (#16568) clef: documentation about setup --- cmd/clef/README.md | 15 +- cmd/clef/docs/qubes/clef_qubes_http.png | Bin 0 -> 14302 bytes cmd/clef/docs/qubes/clef_qubes_qrexec.png | Bin 0 -> 20261 bytes cmd/clef/docs/qubes/qrexec-example.png | Bin 0 -> 19109 bytes cmd/clef/docs/qubes/qubes-client.py | 23 +++ cmd/clef/docs/qubes/qubes.Clefsign | 16 ++ cmd/clef/docs/qubes/qubes_newaccount-1.png | Bin 0 -> 25142 bytes cmd/clef/docs/qubes/qubes_newaccount-2.png | Bin 0 -> 42747 bytes cmd/clef/docs/setup.md | 198 +++++++++++++++++++++ 9 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 cmd/clef/docs/qubes/clef_qubes_http.png create mode 100644 cmd/clef/docs/qubes/clef_qubes_qrexec.png create mode 100644 cmd/clef/docs/qubes/qrexec-example.png create mode 100644 cmd/clef/docs/qubes/qubes-client.py create mode 100644 cmd/clef/docs/qubes/qubes.Clefsign create mode 100644 cmd/clef/docs/qubes/qubes_newaccount-1.png create mode 100644 cmd/clef/docs/qubes/qubes_newaccount-2.png create mode 100644 cmd/clef/docs/setup.md diff --git a/cmd/clef/README.md b/cmd/clef/README.md index 93799a7610..027c22c98f 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -12,6 +12,11 @@ synchronised with the chain or a particular Ethereum node that has no built-in ( Clef can run as a daemon on the same machine, or off a usb-stick like [usb armory](https://inversepath.com/usbarmory), or a separate VM in a [QubesOS](https://www.qubes-os.org/) type os setup. +Check out + +* the [tutorial](tutorial.md) for some concrete examples on how the signer works. +* the [setup docs](docs/setup.md) for some information on how to configure it to work on QubesOS or USBArmory. + ## Command line flags Clef accepts the following command line options: @@ -49,7 +54,6 @@ Example: signer -keystore /my/keystore -chainid 4 ``` -Check out the [tutorial](tutorial.md) for some concrete examples on how the signer works. ## Security model @@ -862,3 +866,12 @@ A UI should conform to the following rules. along with the UI. +### UI Implementations + +There are a couple of implementation for a UI. We'll try to keep this list up to date. + +| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters| +| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- | +| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)| +| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: | +| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: | diff --git a/cmd/clef/docs/qubes/clef_qubes_http.png b/cmd/clef/docs/qubes/clef_qubes_http.png new file mode 100644 index 0000000000000000000000000000000000000000..a641e1987fdf691d3af2ae44fa3d61835b5c5f08 GIT binary patch literal 14302 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 Mr>mdKI;Vst0G+;|cK`qY literal 0 HcmV?d00001 diff --git a/cmd/clef/docs/qubes/qubes-client.py b/cmd/clef/docs/qubes/qubes-client.py new file mode 100644 index 0000000000..93a74b899b --- /dev/null +++ b/cmd/clef/docs/qubes/qubes-client.py @@ -0,0 +1,23 @@ +""" +This implements a dispatcher which listens to localhost:8550, and proxies +requests via qrexec to the service qubes.EthSign on a target domain +""" + +import http.server +import socketserver,subprocess + +PORT=8550 +TARGET_DOMAIN= 'debian-work' + +class Dispatcher(http.server.BaseHTTPRequestHandler): + def do_POST(self): + post_data = self.rfile.read(int(self.headers['Content-Length'])) + p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output = p.communicate(post_data)[0] + self.wfile.write(output) + + +with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: + print("Serving at port", PORT) + httpd.serve_forever() + diff --git a/cmd/clef/docs/qubes/qubes.Clefsign b/cmd/clef/docs/qubes/qubes.Clefsign new file mode 100644 index 0000000000..9b5af7b4fe --- /dev/null +++ b/cmd/clef/docs/qubes/qubes.Clefsign @@ -0,0 +1,16 @@ +#!/bin/bash + +SIGNER_BIN="/home/user/tools/clef/clef" +SIGNER_CMD="/home/user/tools/gtksigner/gtkui.py -s $SIGNER_BIN" + +# Start clef if not already started +if [ ! -S /home/user/.clef/clef.ipc ]; then + $SIGNER_CMD & + sleep 1 +fi + +# Should be started by now +if [ -S /home/user/.clef/clef.ipc ]; then + # Post incoming request to HTTP channel + curl -H "Content-Type: application/json" -X POST -d @- http://localhost:8550 2>/dev/null +fi diff --git a/cmd/clef/docs/qubes/qubes_newaccount-1.png b/cmd/clef/docs/qubes/qubes_newaccount-1.png new file mode 100644 index 0000000000000000000000000000000000000000..598dbbee7a9916087584b55898f678271d65625e GIT binary patch literal 25142 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 It`Clpk&}NF7Dgs| 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 literal 0 HcmV?d00001 diff --git a/cmd/clef/docs/qubes/qubes_newaccount-2.png b/cmd/clef/docs/qubes/qubes_newaccount-2.png new file mode 100644 index 0000000000000000000000000000000000000000..cd762a1934a8034fe41d4a6cfd6e47978e298365 GIT binary patch literal 42747 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 r5CYwJA2=}oz2Ms||Bp@Gnl/dev/null +fi + +``` +This RPC service is not complete (see notes about HTTP headers below), but works as a proof-of-concept. +It will forward the data received on `stdin` (forwarded by the OS) to Clef's HTTP channel. + +It would have been possible to send data directly to the `/home/user/.clef/.clef.ipc` +socket via e.g `nc -U /home/user/.clef/clef.ipc`, but the reason for sending the request +data over `HTTP` instead of `IPC` is that we want the ability to forward `HTTP` headers. + +To enable the service: + +``` bash +sudo cp qubes.Clefsign /etc/qubes-rpc/ +sudo chmod +x /etc/qubes-rpc/ qubes.Clefsign +``` + +This setup uses [gtksigner](https://github.com/holiman/gtksigner), which is a very minimal GTK-based UI that works well +with minimal requirements. + +##### Client + + +On the `client` qube, we need to create a listener which will receive the request from the Dapp, and proxy it. + + +[qubes-client.py](qubes/client/qubes-client.py): + +```python + +""" +This implements a dispatcher which listens to localhost:8550, and proxies +requests via qrexec to the service qubes.EthSign on a target domain +""" + +import http.server +import socketserver,subprocess + +PORT=8550 +TARGET_DOMAIN= 'debian-work' + +class Dispatcher(http.server.BaseHTTPRequestHandler): + def do_POST(self): + post_data = self.rfile.read(int(self.headers['Content-Length'])) + p = subprocess.Popen(['/usr/bin/qrexec-client-vm',TARGET_DOMAIN,'qubes.Clefsign'],stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output = p.communicate(post_data)[0] + self.wfile.write(output) + + +with socketserver.TCPServer(("",PORT), Dispatcher) as httpd: + print("Serving at port", PORT) + httpd.serve_forever() + + +``` + +#### Testing + +To test the flow, if we have set up `debian-work` as the `target`, we can do + +```bash +$ cat newaccnt.json +{ "id": 0, "jsonrpc": "2.0","method": "account_new","params": []} + +$ cat newaccnt.json| qrexec-client-vm debian-work qubes.Clefsign +``` + +This should pop up first a dialog to allow the IPC call: + +![one](qubes/qubes_newaccount-1.png) + +Followed by a GTK-dialog to approve the operation + +![two](qubes/qubes_newaccount-2.png) + +To test the full flow, we use the client wrapper. Start it on the `client` qube: +``` +[user@work qubes]$ python3 qubes-client.py +``` + +Make the request over http (`client` qube): +``` +[user@work clef]$ cat newaccnt.json | curl -X POST -d @- http://localhost:8550 +``` +And it should show the same popups again. + +##### Pros and cons + +The benefits of this setup are: + +- This is the qubes-os intended model for inter-qube communication, +- and thus benefits from qubes-os dialogs and policies for user approval + +However, it comes with a couple of drawbacks: + +- The `qubes-gpg-client` must forward the http request via RPC to the `target` qube. When doing so, the proxy + will either drop important headers, or replace them. + - The `Host` header is most likely `localhost` + - The `Origin` header must be forwarded + - Information about the remote ip must be added as a `X-Forwarded-For`. However, Clef cannot always trust an `XFF` header, + since malicious clients may lie about `XFF` in order to fool the http server into believing it comes from another address. +- Even with a policy in place to allow rpc-calls between `caller` and `target`, there will be several popups: + - One qubes-specific where the user specifies the `target` vm + - One clef-specific to approve the transaction + + +#### 2. Network integrated + +The second way to set up Clef on a qubes system is to allow networking, and have Clef listen to a port which is accessible +form other qubes. + +![Clef via http](qubes/clef_qubes_http.png) + + + + +## USBArmory + +The [USB armory](https://inversepath.com/usbarmory) is an open source hardware design with an 800 Mhz ARM processor. It is a pocket-size +computer. When inserted into a laptop, it identifies itself as a USB network interface, basically adding another network +to your computer. Over this new network interface, you can SSH into the device. + +Running Clef off a USB armory means that you can use the armory as a very versatile offline computer, which only +ever connects to a local network between your computer and the device itself. + +Needless to say, the while this model should be fairly secure against remote attacks, an attacker with physical access +to the USB Armory would trivially be able to extract the contents of the device filesystem. + From 66432f3821badf24d526f2d9205f36c0543219de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 2 May 2018 14:01:38 +0300 Subject: [PATCH 17/18] params: release geth 1.8.7 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index fae1d5a88f..dd84368249 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 8 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 8 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 577d375a0df08710e52b1c38720f98a7f25d206a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 2 May 2018 14:04:09 +0300 Subject: [PATCH 18/18] VERSION, params: begin v1.8.8 release cycle --- VERSION | 2 +- params/version.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 88d3ee7900..1790d35988 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.7 +1.8.8 diff --git a/params/version.go b/params/version.go index dd84368249..8b96f25167 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 8 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 8 // Minor version component of the current release + VersionPatch = 8 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string.