Update go-ethereum to 1.8.5 (#854)
* Rebase on 1.8.5 * Remove outdated patches and apply all others * Use shh_post that returns hash * Use bloom filter for request to mailserver * Remove tests for sending messages without subbing first * Fix deadlock in ethdb * Expect null if receipt is not yet created * Subscribe to messages before sending them in whisper test
This commit is contained in:
parent
75471f2c27
commit
b37fda7731
345 changed files with 22817 additions and 15610 deletions
18
Gopkg.lock
generated
18
Gopkg.lock
generated
|
@ -91,6 +91,8 @@
|
|||
"core/vm",
|
||||
"crypto",
|
||||
"crypto/bn256",
|
||||
"crypto/bn256/cloudflare",
|
||||
"crypto/bn256/google",
|
||||
"crypto/ecies",
|
||||
"crypto/randentropy",
|
||||
"crypto/secp256k1",
|
||||
|
@ -114,6 +116,7 @@
|
|||
"log",
|
||||
"log/term",
|
||||
"metrics",
|
||||
"metrics/exp",
|
||||
"miner",
|
||||
"node",
|
||||
"p2p",
|
||||
|
@ -126,11 +129,10 @@
|
|||
"rpc",
|
||||
"trie",
|
||||
"whisper/mailserver",
|
||||
"whisper/whisperv5",
|
||||
"whisper/whisperv6"
|
||||
]
|
||||
revision = "1e67410e88d2685bc54611a7c9f75c327b553ccc"
|
||||
version = "v1.8.1"
|
||||
revision = "cbdaa0ca2a955012274bd2c47bd52b24b2beb66c"
|
||||
version = "v1.8.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ole/go-ole"
|
||||
|
@ -284,14 +286,6 @@
|
|||
packages = ["util/flock"]
|
||||
revision = "3101606756c53221ed58ba94ecba6b26adf89dcc"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rcrowley/go-metrics"
|
||||
packages = [
|
||||
".",
|
||||
"exp"
|
||||
]
|
||||
revision = "1f30fe9094a513ce4c700b9a54458bbb0c96996c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rjeczalik/notify"
|
||||
packages = ["."]
|
||||
|
@ -489,6 +483,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "aee11795bbc6edceede45c682bef1deaf1c8166377c53632fc1fd23003e2a784"
|
||||
inputs-digest = "bc797975b48cf461eb29215dfd5870a3f74a1f4cf1172bdd11372d1d693461ea"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -27,7 +27,7 @@ ignored = [ "github.com/ethereum/go-ethereum/ethapi" ]
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/ethereum/go-ethereum"
|
||||
version = "1.8.1"
|
||||
version = "v1.8.5"
|
||||
|
||||
[[constraint]]
|
||||
# used only to embed web3js code with particular version
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
diff --git a/whisper/whisperv2/whisper.go b/whisper/whisperv2/whisper.go
|
||||
index 61c36918d..908346999 100644
|
||||
--- a/whisper/whisperv2/whisper.go
|
||||
+++ b/whisper/whisperv2/whisper.go
|
||||
@@ -134,6 +134,13 @@ func (self *Whisper) NewIdentity() *ecdsa.PrivateKey {
|
||||
return key
|
||||
}
|
||||
|
||||
+// AddIdentity adds identity into the known identities list (for message decryption).
|
||||
+func (self *Whisper) AddIdentity(key *ecdsa.PrivateKey) {
|
||||
+ self.keysMu.Lock()
|
||||
+ self.keys[string(crypto.FromECDSAPub(&key.PublicKey))] = key
|
||||
+ self.keysMu.Unlock()
|
||||
+}
|
||||
+
|
||||
// HasIdentity checks if the the whisper node is configured with the private key
|
||||
// of the specified public pair.
|
||||
func (self *Whisper) HasIdentity(key *ecdsa.PublicKey) bool {
|
||||
diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go
|
||||
index 96c4b0e6c..e3c2f4a97 100644
|
||||
--- a/whisper/whisperv5/api.go
|
||||
+++ b/whisper/whisperv5/api.go
|
||||
@@ -313,6 +313,16 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
||||
return true, api.w.Send(env)
|
||||
}
|
||||
|
||||
+// UninstallFilter is alias for Unsubscribe
|
||||
+func (api *PublicWhisperAPI) UninstallFilter(id string) {
|
||||
+ api.w.Unsubscribe(id)
|
||||
+}
|
||||
+
|
||||
+// Unsubscribe disables and removes an existing filter.
|
||||
+func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
||||
+ api.w.Unsubscribe(id)
|
||||
+}
|
||||
+
|
||||
//go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go
|
||||
|
||||
// Criteria holds various filter options for inbound messages.
|
||||
diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go
|
||||
index 85849ccce..c39e8b3e0 100644
|
||||
--- a/whisper/whisperv5/whisper.go
|
||||
+++ b/whisper/whisperv5/whisper.go
|
||||
@@ -250,9 +256,9 @@ func (w *Whisper) NewKeyPair() (string, error) {
|
||||
return "", fmt.Errorf("failed to generate valid key")
|
||||
}
|
||||
|
||||
- id, err := GenerateRandomID()
|
||||
+ id, err := toDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIdSize)
|
||||
if err != nil {
|
||||
- return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||
+ return "", err
|
||||
}
|
||||
|
||||
w.keyMu.Lock()
|
||||
@@ -265,45 +271,94 @@ func (w *Whisper) NewKeyPair() (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
-// DeleteKeyPair deletes the specified key if it exists.
|
||||
-func (w *Whisper) DeleteKeyPair(key string) bool {
|
||||
+// AddIdentity adds cryptographic identity into the known
|
||||
+// identities list (for message decryption).
|
||||
+func (w *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
|
||||
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIdSize)
|
||||
+ if err != nil {
|
||||
+ return "", err
|
||||
+ }
|
||||
+ if w.HasKeyPair(id) {
|
||||
+ return id, nil // no need to re-inject
|
||||
+ }
|
||||
+
|
||||
w.keyMu.Lock()
|
||||
defer w.keyMu.Unlock()
|
||||
|
||||
- if w.privateKeys[key] != nil {
|
||||
- delete(w.privateKeys, key)
|
||||
- return true
|
||||
- }
|
||||
- return false
|
||||
+ w.privateKeys[id] = key
|
||||
+ log.Info("Whisper identity added", "id", id, "pubkey", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
||||
+
|
||||
+ return id, nil
|
||||
}
|
||||
|
||||
-// AddKeyPair imports a asymmetric private key and returns it identifier.
|
||||
-func (w *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
|
||||
- id, err := GenerateRandomID()
|
||||
+// SelectKeyPair adds cryptographic identity, and makes sure
|
||||
+// that it is the only private key known to the node.
|
||||
+func (w *Whisper) SelectKeyPair(key *ecdsa.PrivateKey) error {
|
||||
+ id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIdSize)
|
||||
if err != nil {
|
||||
- return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||
+ return err
|
||||
}
|
||||
|
||||
w.keyMu.Lock()
|
||||
+ defer w.keyMu.Unlock()
|
||||
+
|
||||
+ w.privateKeys = make(map[string]*ecdsa.PrivateKey) // reset key store
|
||||
w.privateKeys[id] = key
|
||||
- w.keyMu.Unlock()
|
||||
|
||||
- return id, nil
|
||||
+ log.Info("Whisper identity selected", "id", id, "key", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+// DeleteKeyPairs removes all cryptographic identities known to the node
|
||||
+func (w *Whisper) DeleteKeyPairs() error {
|
||||
+ w.keyMu.Lock()
|
||||
+ defer w.keyMu.Unlock()
|
||||
+
|
||||
+ w.privateKeys = make(map[string]*ecdsa.PrivateKey)
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+// DeleteKeyPair deletes the specified key if it exists.
|
||||
+func (w *Whisper) DeleteKeyPair(id string) bool {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIdSize)
|
||||
+ if err != nil {
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
+ w.keyMu.Lock()
|
||||
+ defer w.keyMu.Unlock()
|
||||
+
|
||||
+ if w.privateKeys[deterministicID] != nil {
|
||||
+ delete(w.privateKeys, deterministicID)
|
||||
+ return true
|
||||
+ }
|
||||
+ return false
|
||||
}
|
||||
|
||||
// HasKeyPair checks if the the whisper node is configured with the private key
|
||||
// of the specified public pair.
|
||||
func (w *Whisper) HasKeyPair(id string) bool {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIdSize)
|
||||
+ if err != nil {
|
||||
+ return false
|
||||
+ }
|
||||
+
|
||||
w.keyMu.RLock()
|
||||
defer w.keyMu.RUnlock()
|
||||
- return w.privateKeys[id] != nil
|
||||
+ return w.privateKeys[deterministicID] != nil
|
||||
}
|
||||
|
||||
// GetPrivateKey retrieves the private key of the specified identity.
|
||||
func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIdSize)
|
||||
+ if err != nil {
|
||||
+ return nil, err
|
||||
+ }
|
||||
+
|
||||
w.keyMu.RLock()
|
||||
defer w.keyMu.RUnlock()
|
||||
- key := w.privateKeys[id]
|
||||
+ key := w.privateKeys[deterministicID]
|
||||
if key == nil {
|
||||
return nil, fmt.Errorf("invalid id")
|
||||
}
|
||||
@@ -336,6 +391,23 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
+// AddSymKey stores the key with a given id.
|
||||
+func (w *Whisper) AddSymKey(id string, key []byte) (string, error) {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIdSize)
|
||||
+ if err != nil {
|
||||
+ return "", err
|
||||
+ }
|
||||
+
|
||||
+ w.keyMu.Lock()
|
||||
+ defer w.keyMu.Unlock()
|
||||
+
|
||||
+ if w.symKeys[deterministicID] != nil {
|
||||
+ return "", fmt.Errorf("key already exists: %v", id)
|
||||
+ }
|
||||
+ w.symKeys[deterministicID] = key
|
||||
+ return deterministicID, nil
|
||||
+}
|
||||
+
|
||||
// AddSymKeyDirect stores the key, and returns its id.
|
||||
func (w *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||
if len(key) != aesKeyLength {
|
||||
@@ -856,3 +941,30 @@ func GenerateRandomID() (id string, err error) {
|
||||
id = common.Bytes2Hex(buf)
|
||||
return id, err
|
||||
}
|
||||
+
|
||||
+// makeDeterministicID generates a deterministic ID, based on a given input
|
||||
+func makeDeterministicID(input string, keyLen int) (id string, err error) {
|
||||
+ buf := pbkdf2.Key([]byte(input), nil, 4096, keyLen, sha256.New)
|
||||
+ if !validateSymmetricKey(buf) {
|
||||
+ return "", fmt.Errorf("error in GenerateDeterministicID: failed to generate key")
|
||||
+ }
|
||||
+ id = common.Bytes2Hex(buf)
|
||||
+ return id, err
|
||||
+}
|
||||
+
|
||||
+// toDeterministicID reviews incoming id, and transforms it to format
|
||||
+// expected internally be private key store. Originally, public keys
|
||||
+// were used as keys, now random keys are being used. And in order to
|
||||
+// make it easier to consume, we now allow both random IDs and public
|
||||
+// keys to be passed.
|
||||
+func toDeterministicID(id string, expectedLen int) (string, error) {
|
||||
+ if len(id) != (expectedLen * 2) { // we received hex key, so number of chars in id is doubled
|
||||
+ var err error
|
||||
+ id, err = makeDeterministicID(id, expectedLen)
|
||||
+ if err != nil {
|
||||
+ return "", err
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return id, nil
|
||||
+}
|
|
@ -1,111 +0,0 @@
|
|||
diff --git a/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go
|
||||
index a6c9e610d..eb2b75210 100644
|
||||
--- a/whisper/whisperv5/doc.go
|
||||
+++ b/whisper/whisperv5/doc.go
|
||||
@@ -85,3 +85,40 @@ type MailServer interface {
|
||||
Archive(env *Envelope)
|
||||
DeliverMail(whisperPeer *Peer, request *Envelope)
|
||||
}
|
||||
+
|
||||
+type envelopeSource int
|
||||
+
|
||||
+const (
|
||||
+ _ = iota
|
||||
+ // peerSource indicates a source as a regular peer.
|
||||
+ peerSource envelopeSource = iota
|
||||
+ // p2pSource indicates that envelop was received from a trusted peer.
|
||||
+ p2pSource
|
||||
+)
|
||||
+
|
||||
+// EnvelopeMeta keeps metadata of received envelopes.
|
||||
+type EnvelopeMeta struct {
|
||||
+ Hash string
|
||||
+ Topic TopicType
|
||||
+ Size uint32
|
||||
+ Source envelopeSource
|
||||
+ IsNew bool
|
||||
+ Peer string
|
||||
+}
|
||||
+
|
||||
+// SourceString converts source to string.
|
||||
+func (m *EnvelopeMeta) SourceString() string {
|
||||
+ switch m.Source {
|
||||
+ case peerSource:
|
||||
+ return "peer"
|
||||
+ case p2pSource:
|
||||
+ return "p2p"
|
||||
+ default:
|
||||
+ return "unknown"
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// EnvelopeTracer tracks received envelopes.
|
||||
+type EnvelopeTracer interface {
|
||||
+ Trace(*EnvelopeMeta)
|
||||
+}
|
||||
diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go
|
||||
index c39e8b3e0..631676328 100644
|
||||
--- a/whisper/whisperv5/whisper.go
|
||||
+++ b/whisper/whisperv5/whisper.go
|
||||
@@ -77,7 +77,8 @@ type Whisper struct {
|
||||
statsMu sync.Mutex // guard stats
|
||||
stats Statistics // Statistics of whisper node
|
||||
|
||||
- mailServer MailServer // MailServer interface
|
||||
+ mailServer MailServer // MailServer interface
|
||||
+ envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
}
|
||||
|
||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||
@@ -156,6 +157,12 @@ func (w *Whisper) RegisterServer(server MailServer) {
|
||||
w.mailServer = server
|
||||
}
|
||||
|
||||
+// RegisterEnvelopeTracer registers an EnveloperTracer to collect information
|
||||
+// about received envelopes.
|
||||
+func (w *Whisper) RegisterEnvelopeTracer(tracer EnvelopeTracer) {
|
||||
+ w.envelopeTracer = tracer
|
||||
+}
|
||||
+
|
||||
// Protocols returns the whisper sub-protocols ran by this particular client.
|
||||
func (w *Whisper) Protocols() []p2p.Protocol {
|
||||
return []p2p.Protocol{w.protocol}
|
||||
@@ -584,6 +591,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")
|
||||
}
|
||||
+ wh.traceEnvelope(&envelope, !wh.isEnvelopeCached(envelope.Hash()), peerSource, p)
|
||||
cached, err := wh.add(&envelope)
|
||||
if err != nil {
|
||||
log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
@@ -604,6 +612,7 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
return errors.New("invalid direct message")
|
||||
}
|
||||
wh.postEvent(&envelope, true)
|
||||
+ wh.traceEnvelope(&envelope, false, p2pSource, p)
|
||||
}
|
||||
case p2pRequestCode:
|
||||
// Must be processed if mail server is implemented. Otherwise ignore.
|
||||
@@ -699,6 +708,22 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
+// traceEnvelope collects basic metadata about an envelope and sender peer.
|
||||
+func (w *Whisper) traceEnvelope(envelope *Envelope, isNew bool, source envelopeSource, peer *Peer) {
|
||||
+ if w.envelopeTracer == nil {
|
||||
+ return
|
||||
+ }
|
||||
+
|
||||
+ w.envelopeTracer.Trace(&EnvelopeMeta{
|
||||
+ Hash: envelope.Hash().String(),
|
||||
+ Topic: BytesToTopic(envelope.Topic[:]),
|
||||
+ Size: uint32(envelope.size()),
|
||||
+ Source: source,
|
||||
+ IsNew: isNew,
|
||||
+ Peer: peer.peer.Info().ID,
|
||||
+ })
|
||||
+}
|
||||
+
|
||||
// postEvent queues the message for further processing.
|
||||
func (w *Whisper) postEvent(envelope *Envelope, isP2P bool) {
|
||||
// if the version of incoming message is higher than
|
|
@ -1,32 +0,0 @@
|
|||
diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go
|
||||
index e3c2f4a97..96d895fdc 100644
|
||||
--- a/whisper/whisperv5/api.go
|
||||
+++ b/whisper/whisperv5/api.go
|
||||
@@ -33,7 +33,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
- filterTimeout = 300 // filters are considered timeout out after filterTimeout seconds
|
||||
+ // HACK: make the filter essentially never timeout (1 year of timeout time)
|
||||
+ // It's a hack, but that simplifies rebasing process, because the patch consists
|
||||
+ // only of 1 LoC change (excluding this comment).
|
||||
+ filterTimeout = 525600 * 60 // filters are considered timeout out after filterTimeout seconds
|
||||
)
|
||||
|
||||
var (
|
||||
diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go
|
||||
index a2c75a41c..4d3662880 100644
|
||||
--- a/whisper/whisperv6/api.go
|
||||
+++ b/whisper/whisperv6/api.go
|
||||
@@ -33,7 +33,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
- filterTimeout = 300 // filters are considered timeout out after filterTimeout seconds
|
||||
+ // HACK: make the filter essentially never timeout (1 year of timeout time)
|
||||
+ // It's a hack, but that simplifies rebasing process, because the patch consists
|
||||
+ // only of 1 LoC change (excluding this comment).
|
||||
+ filterTimeout = 525600 * 60 // filters are considered timeout out after filterTimeout seconds
|
||||
)
|
||||
|
||||
// List of errors
|
|
@ -1,11 +1,11 @@
|
|||
diff --git a/whisper/whisperv6/api.go b/whisper/whisperv6/api.go
|
||||
index 8ae2882e1..7c97f0680 100644
|
||||
--- a/whisper/whisperv6/api.go
|
||||
+++ b/whisper/whisperv6/api.go
|
||||
@@ -319,6 +319,16 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
||||
return true, api.w.Send(env)
|
||||
diff --git i/whisper/whisperv6/api.go w/whisper/whisperv6/api.go
|
||||
index c60bc46a1..2de99f293 100644
|
||||
--- i/whisper/whisperv6/api.go
|
||||
+++ w/whisper/whisperv6/api.go
|
||||
@@ -317,6 +317,16 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.
|
||||
return result, err
|
||||
}
|
||||
|
||||
|
||||
+// UninstallFilter is alias for Unsubscribe
|
||||
+func (api *PublicWhisperAPI) UninstallFilter(id string) {
|
||||
+ api.w.Unsubscribe(id)
|
||||
|
@ -17,26 +17,26 @@ index 8ae2882e1..7c97f0680 100644
|
|||
+}
|
||||
+
|
||||
//go:generate gencodec -type Criteria -field-override criteriaOverride -out gen_criteria_json.go
|
||||
|
||||
|
||||
// Criteria holds various filter options for inbound messages.
|
||||
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
|
||||
index d75ad04ac..54d7d0f24 100644
|
||||
--- a/whisper/whisperv6/whisper.go
|
||||
+++ b/whisper/whisperv6/whisper.go
|
||||
@@ -380,9 +386,9 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
||||
diff --git i/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go
|
||||
index 880cced09..702556079 100644
|
||||
--- i/whisper/whisperv6/whisper.go
|
||||
+++ w/whisper/whisperv6/whisper.go
|
||||
@@ -382,9 +382,9 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
||||
return "", fmt.Errorf("failed to generate valid key")
|
||||
}
|
||||
|
||||
|
||||
- id, err := GenerateRandomID()
|
||||
+ id, err := toDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize)
|
||||
if err != nil {
|
||||
- return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||
+ return "", err
|
||||
}
|
||||
|
||||
|
||||
whisper.keyMu.Lock()
|
||||
@@ -397,11 +403,16 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
||||
|
||||
@@ -399,11 +399,16 @@ func (whisper *Whisper) NewKeyPair() (string, error) {
|
||||
|
||||
// DeleteKeyPair deletes the specified key if it exists.
|
||||
func (whisper *Whisper) DeleteKeyPair(key string) bool {
|
||||
+ deterministicID, err := toDeterministicID(key, keyIDSize)
|
||||
|
@ -46,7 +46,7 @@ index d75ad04ac..54d7d0f24 100644
|
|||
+
|
||||
whisper.keyMu.Lock()
|
||||
defer whisper.keyMu.Unlock()
|
||||
|
||||
|
||||
- if whisper.privateKeys[key] != nil {
|
||||
- delete(whisper.privateKeys, key)
|
||||
+ if whisper.privateKeys[deterministicID] != nil {
|
||||
|
@ -54,8 +54,8 @@ index d75ad04ac..54d7d0f24 100644
|
|||
return true
|
||||
}
|
||||
return false
|
||||
@@ -409,31 +420,73 @@ func (whisper *Whisper) DeleteKeyPair(key string) bool {
|
||||
|
||||
@@ -411,31 +416,73 @@ func (whisper *Whisper) DeleteKeyPair(key string) bool {
|
||||
|
||||
// AddKeyPair imports a asymmetric private key and returns it identifier.
|
||||
func (whisper *Whisper) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
|
||||
- id, err := GenerateRandomID()
|
||||
|
@ -67,15 +67,15 @@ index d75ad04ac..54d7d0f24 100644
|
|||
+ if whisper.HasKeyPair(id) {
|
||||
+ return id, nil // no need to re-inject
|
||||
}
|
||||
|
||||
|
||||
whisper.keyMu.Lock()
|
||||
whisper.privateKeys[id] = key
|
||||
whisper.keyMu.Unlock()
|
||||
+ log.Info("Whisper identity added", "id", id, "pubkey", common.ToHex(crypto.FromECDSAPub(&key.PublicKey)))
|
||||
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
||||
+// SelectKeyPair adds cryptographic identity, and makes sure
|
||||
+// that it is the only private key known to the node.
|
||||
+func (whisper *Whisper) SelectKeyPair(key *ecdsa.PrivateKey) error {
|
||||
|
@ -117,7 +117,7 @@ index d75ad04ac..54d7d0f24 100644
|
|||
- return whisper.privateKeys[id] != nil
|
||||
+ return whisper.privateKeys[deterministicID] != nil
|
||||
}
|
||||
|
||||
|
||||
// GetPrivateKey retrieves the private key of the specified identity.
|
||||
func (whisper *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIDSize)
|
||||
|
@ -132,10 +132,10 @@ index d75ad04ac..54d7d0f24 100644
|
|||
if key == nil {
|
||||
return nil, fmt.Errorf("invalid id")
|
||||
}
|
||||
@@ -465,6 +518,23 @@ func (whisper *Whisper) GenerateSymKey() (string, error) {
|
||||
@@ -467,6 +514,23 @@ func (whisper *Whisper) GenerateSymKey() (string, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
||||
+// AddSymKey stores the key with a given id.
|
||||
+func (whisper *Whisper) AddSymKey(id string, key []byte) (string, error) {
|
||||
+ deterministicID, err := toDeterministicID(id, keyIDSize)
|
||||
|
@ -156,10 +156,10 @@ index d75ad04ac..54d7d0f24 100644
|
|||
// AddSymKeyDirect stores the key, and returns its id.
|
||||
func (whisper *Whisper) AddSymKeyDirect(key []byte) (string, error) {
|
||||
if len(key) != aesKeyLength {
|
||||
@@ -1035,6 +1118,33 @@ func GenerateRandomID() (id string, err error) {
|
||||
@@ -1013,6 +1077,33 @@ func GenerateRandomID() (id string, err error) {
|
||||
return id, err
|
||||
}
|
||||
|
||||
|
||||
+// makeDeterministicID generates a deterministic ID, based on a given input
|
||||
+func makeDeterministicID(input string, keyLen int) (id string, err error) {
|
||||
+ buf := pbkdf2.Key([]byte(input), nil, 4096, keyLen, sha256.New)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
diff --git a/whisper/whisperv6/doc.go b/whisper/whisperv6/doc.go
|
||||
index 5ad660616..9659e6c46 100644
|
||||
--- a/whisper/whisperv6/doc.go
|
||||
+++ b/whisper/whisperv6/doc.go
|
||||
diff --git i/whisper/whisperv6/doc.go w/whisper/whisperv6/doc.go
|
||||
index 066a9766d..4bbf5546b 100644
|
||||
--- i/whisper/whisperv6/doc.go
|
||||
+++ w/whisper/whisperv6/doc.go
|
||||
@@ -95,3 +95,40 @@ type MailServer interface {
|
||||
Archive(env *Envelope)
|
||||
DeliverMail(whisperPeer *Peer, request *Envelope)
|
||||
|
@ -43,21 +43,21 @@ index 5ad660616..9659e6c46 100644
|
|||
+type EnvelopeTracer interface {
|
||||
+ Trace(*EnvelopeMeta)
|
||||
+}
|
||||
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
|
||||
index 54d7d0f24..ce9405dff 100644
|
||||
--- a/whisper/whisperv6/whisper.go
|
||||
+++ b/whisper/whisperv6/whisper.go
|
||||
@@ -85,7 +85,8 @@ type Whisper struct {
|
||||
diff --git i/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go
|
||||
index 702556079..9aaf5687c 100644
|
||||
--- i/whisper/whisperv6/whisper.go
|
||||
+++ w/whisper/whisperv6/whisper.go
|
||||
@@ -87,7 +87,8 @@ type Whisper struct {
|
||||
statsMu sync.Mutex // guard stats
|
||||
stats Statistics // Statistics of whisper node
|
||||
|
||||
|
||||
- mailServer MailServer // MailServer interface
|
||||
+ mailServer MailServer // MailServer interface
|
||||
+ envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
+ mailServer MailServer // MailServer interface
|
||||
+ envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
}
|
||||
|
||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||
@@ -209,6 +210,12 @@ func (whisper *Whisper) RegisterServer(server MailServer) {
|
||||
@@ -211,6 +212,12 @@ func (whisper *Whisper) RegisterServer(server MailServer) {
|
||||
whisper.mailServer = server
|
||||
}
|
||||
|
||||
|
@ -70,15 +70,15 @@ index 54d7d0f24..ce9405dff 100644
|
|||
// Protocols returns the whisper sub-protocols ran by this particular client.
|
||||
func (whisper *Whisper) Protocols() []p2p.Protocol {
|
||||
return []p2p.Protocol{whisper.protocol}
|
||||
@@ -737,6 +744,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
|
||||
@@ -736,6 +743,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
|
||||
trouble := false
|
||||
for _, env := range envelopes {
|
||||
+ whisper.traceEnvelope(env, !whisper.isEnvelopeCached(env.Hash()), peerSource, p)
|
||||
cached, err := whisper.add(env)
|
||||
cached, err := whisper.add(env, whisper.lightClient)
|
||||
if err != nil {
|
||||
trouble = true
|
||||
@@ -787,6 +795,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
@@ -786,6 +794,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
return errors.New("invalid direct message")
|
||||
}
|
||||
whisper.postEvent(&envelope, true)
|
||||
|
@ -86,7 +86,7 @@ index 54d7d0f24..ce9405dff 100644
|
|||
}
|
||||
case p2pRequestCode:
|
||||
// Must be processed if mail server is implemented. Otherwise ignore.
|
||||
@@ -883,6 +892,22 @@ func (whisper *Whisper) add(envelope *Envelope) (bool, error) {
|
||||
@@ -883,6 +892,22 @@ func (whisper *Whisper) add(envelope *Envelope, isP2P bool) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
diff --git a/whisper/whisperv6/peer.go b/whisper/whisperv6/peer.go
|
||||
index 4ef0f3c4..6a7ab358 100644
|
||||
--- a/whisper/whisperv6/peer.go
|
||||
+++ b/whisper/whisperv6/peer.go
|
||||
@@ -19,6 +19,7 @@ package whisperv6
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
+ "sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -38,6 +39,7 @@ type Peer struct {
|
||||
powRequirement float64
|
||||
+ bloomMu sync.Mutex
|
||||
bloomFilter []byte
|
||||
fullNode bool
|
||||
|
||||
known *set.Set // Messages already known by the peer to avoid wasting bandwidth
|
||||
|
||||
@@ -225,10 +227,14 @@ func (peer *Peer) notifyAboutBloomFilterChange(bloom []byte) error {
|
||||
}
|
||||
|
||||
func (peer *Peer) bloomMatch(env *Envelope) bool {
|
||||
+ peer.bloomMu.Lock()
|
||||
+ defer peer.bloomMu.Unlock()
|
||||
return peer.fullNode || bloomFilterMatch(peer.bloomFilter, env.Bloom())
|
||||
}
|
||||
|
||||
func (peer *Peer) setBloomFilter(bloom []byte) {
|
||||
+ peer.bloomMu.Lock()
|
||||
+ defer peer.bloomMu.Unlock()
|
||||
peer.bloomFilter = bloom
|
||||
peer.fullNode = isFullNode(bloom)
|
||||
if peer.fullNode && peer.bloomFilter == nil {
|
|
@ -1,54 +0,0 @@
|
|||
diff --git a/whisper/whisperv6/doc.go b/whisper/whisperv6/doc.go
|
||||
index a98760b9..06736e55 100644
|
||||
--- a/whisper/whisperv6/doc.go
|
||||
+++ b/whisper/whisperv6/doc.go
|
||||
@@ -104,6 +104,9 @@ const (
|
||||
peerSource envelopeSource = iota
|
||||
// p2pSource indicates that envelop was received from a trusted peer.
|
||||
p2pSource
|
||||
+
|
||||
+ forwarded = true
|
||||
+ inHouse = false
|
||||
)
|
||||
|
||||
// EnvelopeMeta keeps metadata of received envelopes.
|
||||
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
|
||||
index a9e12d4a..8bd991a9 100644
|
||||
--- a/whisper/whisperv6/whisper.go
|
||||
+++ b/whisper/whisperv6/whisper.go
|
||||
@@ -658,7 +658,7 @@ func (whisper *Whisper) Unsubscribe(id string) error {
|
||||
// Send injects a message into the whisper send queue, to be distributed in the
|
||||
// network in the coming cycles.
|
||||
func (whisper *Whisper) Send(envelope *Envelope) error {
|
||||
- ok, err := whisper.add(envelope)
|
||||
+ ok, err := whisper.add(envelope, inHouse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -745,7 +745,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
||||
trouble := false
|
||||
for _, env := range envelopes {
|
||||
whisper.traceEnvelope(env, !whisper.isEnvelopeCached(env.Hash()), peerSource, p)
|
||||
- cached, err := whisper.add(env)
|
||||
+ cached, err := whisper.add(env, forwarded)
|
||||
if err != nil {
|
||||
trouble = true
|
||||
log.Error("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
@@ -819,7 +819,7 @@ func (whisper *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 (whisper *Whisper) add(envelope *Envelope) (bool, error) {
|
||||
+func (whisper *Whisper) add(envelope *Envelope, isForwarded bool) (bool, error) {
|
||||
now := uint32(time.Now().Unix())
|
||||
sent := envelope.Expiry - envelope.TTL
|
||||
|
||||
@@ -852,7 +852,7 @@ func (whisper *Whisper) add(envelope *Envelope) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
- if !bloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) {
|
||||
+ if isForwarded && !bloomFilterMatch(whisper.BloomFilter(), envelope.Bloom()) {
|
||||
// maybe the value was recently changed, and the peers did not adjust yet.
|
||||
// in this case the previous value is retrieved by BloomFilterTolerance()
|
||||
// for a short period of peer synchronization.
|
|
@ -9,8 +9,8 @@ index 000000000..1092935cf
|
|||
+import "github.com/ethereum/go-ethereum/metrics"
|
||||
+
|
||||
+var (
|
||||
+ ingressTrafficMeter = metrics.NewMeter("discv5/InboundTraffic")
|
||||
+ egressTrafficMeter = metrics.NewMeter("discv5/OutboundTraffic")
|
||||
+ ingressTrafficMeter = metrics.NewRegisteredMeter("discv5/InboundTraffic", nil)
|
||||
+ egressTrafficMeter = metrics.NewRegisteredMeter("discv5/OutboundTraffic", nil)
|
||||
+)
|
||||
diff --git c/p2p/discv5/udp.go w/p2p/discv5/udp.go
|
||||
index 6ce72d2c1..308cf8637 100644
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
diff --git a/node/node.go b/node/node.go
|
||||
index b02aecfa..7913e93d 100644
|
||||
--- a/node/node.go
|
||||
+++ b/node/node.go
|
||||
diff --git i/node/node.go w/node/node.go
|
||||
index 83b6c4c07..fe42b8bbd 100644
|
||||
--- i/node/node.go
|
||||
+++ w/node/node.go
|
||||
@@ -51,8 +51,9 @@ type Node struct {
|
||||
serviceFuncs []ServiceConstructor // Service constructors (in dependency order)
|
||||
services map[reflect.Type]Service // Currently running services
|
||||
|
||||
|
||||
- rpcAPIs []rpc.API // List of APIs currently provided by the node
|
||||
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
|
||||
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
|
||||
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
|
||||
+ inprocPublicHandler *rpc.Server // In-process RPC request handler to process the public API requests
|
||||
|
||||
|
||||
ipcEndpoint string // IPC endpoint to listen at (empty = IPC disabled)
|
||||
ipcListener net.Listener // IPC RPC listener socket to serve API requests
|
||||
@@ -259,18 +260,25 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
|
||||
|
@ -43,7 +43,7 @@ index b02aecfa..7913e93d 100644
|
|||
@@ -301,6 +309,36 @@ func (n *Node) stopInProc() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+// startPublicInProc initializes an in-process RPC endpoint for public APIs.
|
||||
+func (n *Node) startPublicInProc(apis []rpc.API, modules []string) error {
|
||||
+ // Generate the whitelist based on the allowed modules
|
||||
|
@ -76,11 +76,11 @@ index b02aecfa..7913e93d 100644
|
|||
+
|
||||
// startIPC initializes and starts the IPC RPC endpoint.
|
||||
func (n *Node) startIPC(apis []rpc.API) error {
|
||||
// Short circuit if the IPC endpoint isn't being exposed
|
||||
@@ -562,6 +600,18 @@ func (n *Node) Attach() (*rpc.Client, error) {
|
||||
if n.ipcEndpoint == "" {
|
||||
@@ -487,6 +525,18 @@ func (n *Node) Attach() (*rpc.Client, error) {
|
||||
return rpc.DialInProc(n.inprocHandler), nil
|
||||
}
|
||||
|
||||
|
||||
+// AttachPublic creates an RPC client attached to an in-process Public API handler.
|
||||
+func (n *Node) AttachPublic() (*rpc.Client, error) {
|
||||
+ n.lock.RLock()
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
diff --git c/whisper/whisperv6/api.go w/whisper/whisperv6/api.go
|
||||
index 16db034e1..25c072355 100644
|
||||
--- c/whisper/whisperv6/api.go
|
||||
+++ w/whisper/whisperv6/api.go
|
||||
@@ -246,6 +246,29 @@ type newMessageOverride struct {
|
||||
|
||||
// Post a message on the Whisper network.
|
||||
func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, error) {
|
||||
+ env, err := MakeEnvelope(api.w, req)
|
||||
+ if err != nil {
|
||||
+ return false, err
|
||||
+ }
|
||||
+ // send to specific node (skip PoW check)
|
||||
+ if len(req.TargetPeer) > 0 {
|
||||
+ n, err := discover.ParseNode(req.TargetPeer)
|
||||
+ if err != nil {
|
||||
+ return false, fmt.Errorf("failed to parse target peer: %s", err)
|
||||
+ }
|
||||
+ return true, api.w.SendP2PMessage(n.ID[:], env)
|
||||
+ }
|
||||
+
|
||||
+ // ensure that the message PoW meets the node's minimum accepted PoW
|
||||
+ if req.PowTarget < api.w.MinPow() {
|
||||
+ return false, ErrTooLowPoW
|
||||
+ }
|
||||
+
|
||||
+ return true, api.w.Send(env)
|
||||
+}
|
||||
+
|
||||
+// MakeEnvelope create envelopes from request.
|
||||
+func MakeEnvelope(w *Whisper, req NewMessage) (*Envelope, error) {
|
||||
var (
|
||||
symKeyGiven = len(req.SymKeyID) > 0
|
||||
pubKeyGiven = len(req.PublicKey) > 0
|
||||
@@ -254,7 +277,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
||||
|
||||
// user must specify either a symmetric or an asymmetric key
|
||||
if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) {
|
||||
- return false, ErrSymAsym
|
||||
+ return nil, ErrSymAsym
|
||||
}
|
||||
|
||||
params := &MessageParams{
|
||||
@@ -268,21 +291,21 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
||||
|
||||
// Set key that is used to sign the message
|
||||
if len(req.Sig) > 0 {
|
||||
- if params.Src, err = api.w.GetPrivateKey(req.Sig); err != nil {
|
||||
- return false, err
|
||||
+ if params.Src, err = w.GetPrivateKey(req.Sig); err != nil {
|
||||
+ return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Set symmetric key that is used to encrypt the message
|
||||
if symKeyGiven {
|
||||
if params.Topic == (TopicType{}) { // topics are mandatory with symmetric encryption
|
||||
- return false, ErrNoTopics
|
||||
+ return nil, ErrNoTopics
|
||||
}
|
||||
- if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil {
|
||||
- return false, err
|
||||
+ if params.KeySym, err = w.GetSymKey(req.SymKeyID); err != nil {
|
||||
+ return nil, err
|
||||
}
|
||||
if !validateDataIntegrity(params.KeySym, aesKeyLength) {
|
||||
- return false, ErrInvalidSymmetricKey
|
||||
+ return nil, ErrInvalidSymmetricKey
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,36 +313,21 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
||||
if pubKeyGiven {
|
||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
- return false, ErrInvalidPublicKey
|
||||
+ return nil, ErrInvalidPublicKey
|
||||
}
|
||||
}
|
||||
|
||||
// encrypt and sent message
|
||||
whisperMsg, err := NewSentMessage(params)
|
||||
if err != nil {
|
||||
- return false, err
|
||||
+ return nil, err
|
||||
}
|
||||
|
||||
env, err := whisperMsg.Wrap(params)
|
||||
if err != nil {
|
||||
- return false, err
|
||||
+ return nil, err
|
||||
}
|
||||
-
|
||||
- // send to specific node (skip PoW check)
|
||||
- if len(req.TargetPeer) > 0 {
|
||||
- n, err := discover.ParseNode(req.TargetPeer)
|
||||
- if err != nil {
|
||||
- return false, fmt.Errorf("failed to parse target peer: %s", err)
|
||||
- }
|
||||
- return true, api.w.SendP2PMessage(n.ID[:], env)
|
||||
- }
|
||||
-
|
||||
- // ensure that the message PoW meets the node's minimum accepted PoW
|
||||
- if req.PowTarget < api.w.MinPow() {
|
||||
- return false, ErrTooLowPoW
|
||||
- }
|
||||
-
|
||||
- return true, api.w.Send(env)
|
||||
+ return env, nil
|
||||
}
|
||||
|
||||
// UninstallFilter is alias for Unsubscribe
|
||||
diff --git c/whisper/whisperv6/events.go w/whisper/whisperv6/events.go
|
||||
new file mode 100644
|
||||
index 000000000..4f204ab5d
|
||||
--- /dev/null
|
||||
+++ w/whisper/whisperv6/events.go
|
||||
@@ -0,0 +1,23 @@
|
||||
+package whisperv6
|
||||
+
|
||||
+import (
|
||||
+ "github.com/ethereum/go-ethereum/common"
|
||||
+ "github.com/ethereum/go-ethereum/p2p/discover"
|
||||
+)
|
||||
+
|
||||
+// EventType used to define known envelope events.
|
||||
+type EventType string
|
||||
+
|
||||
+const (
|
||||
+ // EventEnvelopeSent fires when envelope was sent to a peer.
|
||||
+ EventEnvelopeSent EventType = "envelope.sent"
|
||||
+ // EventEnvelopeExpired fires when envelop expired
|
||||
+ EventEnvelopeExpired EventType = "envelope.expired"
|
||||
+)
|
||||
+
|
||||
+// EnvelopeEvent used for envelopes events.
|
||||
+type EnvelopeEvent struct {
|
||||
+ Event EventType
|
||||
+ Hash common.Hash
|
||||
+ Peer discover.NodeID
|
||||
+}
|
||||
diff --git c/whisper/whisperv6/peer.go w/whisper/whisperv6/peer.go
|
||||
index 6d75290fd..120767c33 100644
|
||||
--- c/whisper/whisperv6/peer.go
|
||||
+++ w/whisper/whisperv6/peer.go
|
||||
@@ -204,6 +204,11 @@ func (peer *Peer) broadcast() error {
|
||||
// mark envelopes only if they were successfully sent
|
||||
for _, e := range bundle {
|
||||
peer.mark(e)
|
||||
+ peer.host.envelopeFeed.Send(EnvelopeEvent{
|
||||
+ Event: EventEnvelopeSent,
|
||||
+ Hash: e.Hash(),
|
||||
+ Peer: peer.peer.ID(), // specifically discover.NodeID because it can be pretty printed
|
||||
+ })
|
||||
}
|
||||
|
||||
log.Trace("broadcast", "num. messages", len(bundle))
|
||||
diff --git c/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go
|
||||
index 8bd991a9b..98115b20f 100644
|
||||
--- c/whisper/whisperv6/whisper.go
|
||||
+++ w/whisper/whisperv6/whisper.go
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
+ "github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -85,8 +86,10 @@ type Whisper struct {
|
||||
statsMu sync.Mutex // guard stats
|
||||
stats Statistics // Statistics of whisper node
|
||||
|
||||
- mailServer MailServer // MailServer interface
|
||||
- envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
+ mailServer MailServer // MailServer interface
|
||||
+ envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
+
|
||||
+ envelopeFeed event.Feed
|
||||
}
|
||||
|
||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||
@@ -131,6 +134,12 @@ func New(cfg *Config) *Whisper {
|
||||
return whisper
|
||||
}
|
||||
|
||||
+// SubscribeEnvelopeEvents subscribes to envelopes feed.
|
||||
+// In order to prevent blocking whisper producers events must be amply buffered.
|
||||
+func (whisper *Whisper) SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) event.Subscription {
|
||||
+ return whisper.envelopeFeed.Subscribe(events)
|
||||
+}
|
||||
+
|
||||
// MinPow returns the PoW value required by this node.
|
||||
func (whisper *Whisper) MinPow() float64 {
|
||||
val, exist := whisper.settings.Load(minPowIdx)
|
||||
@@ -986,6 +995,10 @@ func (whisper *Whisper) expire() {
|
||||
hashSet.Each(func(v interface{}) bool {
|
||||
sz := whisper.envelopes[v.(common.Hash)].size()
|
||||
delete(whisper.envelopes, v.(common.Hash))
|
||||
+ whisper.envelopeFeed.Send(EnvelopeEvent{
|
||||
+ Hash: v.(common.Hash),
|
||||
+ Event: EventEnvelopeExpired,
|
||||
+ })
|
||||
whisper.stats.messagesCleared++
|
||||
whisper.stats.memoryCleared += sz
|
||||
whisper.stats.memoryUsed -= sz
|
|
@ -1,41 +0,0 @@
|
|||
diff --git c/les/peer.go w/les/peer.go
|
||||
index caf568077..5eb41cff9 100644
|
||||
--- c/les/peer.go
|
||||
+++ w/les/peer.go
|
||||
@@ -543,19 +543,24 @@ func (ps *peerSet) notify(n peerSetNotify) {
|
||||
// Register injects a new peer into the working set, or returns an error if the
|
||||
// peer is already known.
|
||||
func (ps *peerSet) Register(p *peer) error {
|
||||
- ps.lock.Lock()
|
||||
- if ps.closed {
|
||||
- return errClosed
|
||||
+ peers, err := func() ([]peerSetNotify, error) {
|
||||
+ ps.lock.Lock()
|
||||
+ defer ps.lock.Unlock()
|
||||
+ if ps.closed {
|
||||
+ return nil, errClosed
|
||||
+ }
|
||||
+ if _, ok := ps.peers[p.id]; ok {
|
||||
+ return nil, errAlreadyRegistered
|
||||
+ }
|
||||
+ ps.peers[p.id] = p
|
||||
+ p.sendQueue = newExecQueue(100)
|
||||
+ peers := make([]peerSetNotify, len(ps.notifyList))
|
||||
+ copy(peers, ps.notifyList)
|
||||
+ return peers, nil
|
||||
+ }()
|
||||
+ if err != nil {
|
||||
+ return err
|
||||
}
|
||||
- if _, ok := ps.peers[p.id]; ok {
|
||||
- return errAlreadyRegistered
|
||||
- }
|
||||
- ps.peers[p.id] = p
|
||||
- p.sendQueue = newExecQueue(100)
|
||||
- peers := make([]peerSetNotify, len(ps.notifyList))
|
||||
- copy(peers, ps.notifyList)
|
||||
- ps.lock.Unlock()
|
||||
-
|
||||
for _, n := range peers {
|
||||
n.registerPeer(p)
|
||||
}
|
90
_assets/patches/geth/0025-whisper-confirmations.patch
Normal file
90
_assets/patches/geth/0025-whisper-confirmations.patch
Normal file
|
@ -0,0 +1,90 @@
|
|||
diff --git c/whisper/whisperv6/events.go w/whisper/whisperv6/events.go
|
||||
new file mode 100644
|
||||
index 000000000..4f204ab5d
|
||||
--- /dev/null
|
||||
+++ w/whisper/whisperv6/events.go
|
||||
@@ -0,0 +1,23 @@
|
||||
+package whisperv6
|
||||
+
|
||||
+import (
|
||||
+ "github.com/ethereum/go-ethereum/common"
|
||||
+ "github.com/ethereum/go-ethereum/p2p/discover"
|
||||
+)
|
||||
+
|
||||
+// EventType used to define known envelope events.
|
||||
+type EventType string
|
||||
+
|
||||
+const (
|
||||
+ // EventEnvelopeSent fires when envelope was sent to a peer.
|
||||
+ EventEnvelopeSent EventType = "envelope.sent"
|
||||
+ // EventEnvelopeExpired fires when envelop expired
|
||||
+ EventEnvelopeExpired EventType = "envelope.expired"
|
||||
+)
|
||||
+
|
||||
+// EnvelopeEvent used for envelopes events.
|
||||
+type EnvelopeEvent struct {
|
||||
+ Event EventType
|
||||
+ Hash common.Hash
|
||||
+ Peer discover.NodeID
|
||||
+}
|
||||
diff --git i/whisper/whisperv6/peer.go w/whisper/whisperv6/peer.go
|
||||
index 2bf1c905b..427127290 100644
|
||||
--- i/whisper/whisperv6/peer.go
|
||||
+++ w/whisper/whisperv6/peer.go
|
||||
@@ -204,6 +204,11 @@ func (peer *Peer) broadcast() error {
|
||||
// mark envelopes only if they were successfully sent
|
||||
for _, e := range bundle {
|
||||
peer.mark(e)
|
||||
+ peer.host.envelopeFeed.Send(EnvelopeEvent{
|
||||
+ Event: EventEnvelopeSent,
|
||||
+ Hash: e.Hash(),
|
||||
+ Peer: peer.peer.ID(), // specifically discover.NodeID because it can be pretty printed
|
||||
+ })
|
||||
}
|
||||
|
||||
log.Trace("broadcast", "num. messages", len(bundle))
|
||||
diff --git i/whisper/whisperv6/whisper.go w/whisper/whisperv6/whisper.go
|
||||
index 9aaf5687c..eb637b4ca 100644
|
||||
--- i/whisper/whisperv6/whisper.go
|
||||
+++ w/whisper/whisperv6/whisper.go
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
+ "github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -89,6 +90,8 @@ type Whisper struct {
|
||||
|
||||
mailServer MailServer // MailServer interface
|
||||
envelopeTracer EnvelopeTracer // Service collecting envelopes metadata
|
||||
+
|
||||
+ envelopeFeed event.Feed
|
||||
}
|
||||
|
||||
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
|
||||
@@ -133,6 +136,12 @@ func New(cfg *Config) *Whisper {
|
||||
return whisper
|
||||
}
|
||||
|
||||
+// SubscribeEnvelopeEvents subscribes to envelopes feed.
|
||||
+// In order to prevent blocking whisper producers events must be amply buffered.
|
||||
+func (whisper *Whisper) SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) event.Subscription {
|
||||
+ return whisper.envelopeFeed.Subscribe(events)
|
||||
+}
|
||||
+
|
||||
// MinPow returns the PoW value required by this node.
|
||||
func (whisper *Whisper) MinPow() float64 {
|
||||
val, exist := whisper.settings.Load(minPowIdx)
|
||||
@@ -986,6 +995,10 @@ func (whisper *Whisper) expire() {
|
||||
hashSet.Each(func(v interface{}) bool {
|
||||
sz := whisper.envelopes[v.(common.Hash)].size()
|
||||
delete(whisper.envelopes, v.(common.Hash))
|
||||
+ whisper.envelopeFeed.Send(EnvelopeEvent{
|
||||
+ Hash: v.(common.Hash),
|
||||
+ Event: EventEnvelopeExpired,
|
||||
+ })
|
||||
whisper.stats.messagesCleared++
|
||||
whisper.stats.memoryCleared += sz
|
||||
whisper.stats.memoryUsed -= sz
|
43
_assets/patches/geth/0026-ethdb-error-deadlock.patch
Normal file
43
_assets/patches/geth/0026-ethdb-error-deadlock.patch
Normal file
|
@ -0,0 +1,43 @@
|
|||
diff --git i/ethdb/database.go w/ethdb/database.go
|
||||
index 001d8f0bb..4c9b1412c 100644
|
||||
--- i/ethdb/database.go
|
||||
+++ w/ethdb/database.go
|
||||
@@ -55,6 +55,7 @@ type LDBDatabase struct {
|
||||
|
||||
quitLock sync.Mutex // Mutex protecting the quit channel access
|
||||
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
||||
+ wg sync.WaitGroup // WaitGroup waits till all metering collections will exit.
|
||||
|
||||
log log.Logger // Contextual logger tracking the database path
|
||||
}
|
||||
@@ -134,14 +135,11 @@ func (db *LDBDatabase) Close() {
|
||||
// Stop the metrics collection to avoid internal database races
|
||||
db.quitLock.Lock()
|
||||
defer db.quitLock.Unlock()
|
||||
-
|
||||
if db.quitChan != nil {
|
||||
- errc := make(chan error)
|
||||
- db.quitChan <- errc
|
||||
- if err := <-errc; err != nil {
|
||||
- db.log.Error("Metrics collection failed", "err", err)
|
||||
- }
|
||||
+ close(db.quitChan)
|
||||
}
|
||||
+ db.wg.Wait()
|
||||
+ db.quitChan = nil
|
||||
err := db.db.Close()
|
||||
if err == nil {
|
||||
db.log.Info("Database closed")
|
||||
@@ -173,7 +171,11 @@ func (db *LDBDatabase) Meter(prefix string) {
|
||||
db.quitChan = make(chan chan error)
|
||||
db.quitLock.Unlock()
|
||||
|
||||
- go db.meter(3 * time.Second)
|
||||
+ db.wg.Add(1)
|
||||
+ go func() {
|
||||
+ db.wg.Done()
|
||||
+ db.meter(3 * time.Second)
|
||||
+ }()
|
||||
}
|
||||
|
||||
// meter periodically retrieves internal leveldb counters and reports them to
|
|
@ -27,18 +27,6 @@ Instructions for creating a patch from the command line:
|
|||
1. Remove the link from [this README] (./README.md)
|
||||
1. Run `make dep-ensure` to re-apply patches.
|
||||
|
||||
# Patches
|
||||
|
||||
- [`0000-accounts-hd-keys.patch`](./0000-accounts-hd-keys.patch) — adds support for HD extended keys (links/docs?)
|
||||
- [`0004-whisper-notifications.patch`](./0004-whisper-notifications.patch) — adds Whisper notifications (need to be reviewed and documented)
|
||||
- [`0009-whisper-envelopes-tracing.patch`](./0009-whisper-envelopes-tracing.patch) — adds Whisper envelope tracing (need to be reviewed and documented)
|
||||
- [`0010-geth-17-fix-npe-in-filter-system.patch`](./0010-geth-17-fix-npe-in-filter-system.patch) - Temp patch for 1.7.x to fix a NPE in the filter system.
|
||||
- [`0014-whisperv6-notifications.patch`](./0014-whisperv6-notifications.patch) — adds Whisper v6 notifications (need to be reviewed and documented)
|
||||
- [`0015-whisperv6-envelopes-tracing.patch`](./0015-whisperv6-envelopes-tracing.patch) — adds Whisper v6 envelope tracing (need to be reviewed and documented)
|
||||
- [`0018-geth-181-whisperv6-peer-race-cond-fix.patch`](./0018-geth-181-whisperv6-peer-race-cond-fix.patch) — Fixes race condition in Whisper v6. This has been merged upstream and this patch will need to be removed for 1.8.2.
|
||||
- [`0019-whisperv6-send-self-messages-without-subscribe.patch`](./0019-whisperv6-send-self-messages-without-subscribe.patch) — Allows user to send own messages without the subscription to it's topic
|
||||
|
||||
|
||||
# Updating
|
||||
|
||||
When a new stable release of `go-ethereum` comes out, we need to upgrade our vendored copy. We use `dep` for vendoring, so for upgrading:
|
||||
|
|
|
@ -120,9 +120,9 @@ func makeEnvelop(payload []byte, symKey []byte, nodeID *ecdsa.PrivateKey, pow fl
|
|||
// makePayload makes a specific payload for MailServer to request historic messages.
|
||||
func makePayload(r MessagesRequest) []byte {
|
||||
// first 8 bytes are lowed and upper bounds as uint32
|
||||
data := make([]byte, 8+whisper.TopicLength)
|
||||
data := make([]byte, 8+whisper.BloomFilterSize)
|
||||
binary.BigEndian.PutUint32(data, r.From)
|
||||
binary.BigEndian.PutUint32(data[4:], r.To)
|
||||
copy(data[8:], r.Topic[:])
|
||||
copy(data[8:], whisper.TopicToBloom(r.Topic))
|
||||
return data
|
||||
}
|
||||
|
|
|
@ -2,55 +2,35 @@ package shhext
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
)
|
||||
|
||||
// NewPublicAPI returns instance of the public API.
|
||||
func NewPublicAPI(w *whisper.Whisper, tracker *tracker) *PublicAPI {
|
||||
return &PublicAPI{
|
||||
w: w,
|
||||
tracker: tracker,
|
||||
w: w,
|
||||
publicAPI: whisper.NewPublicWhisperAPI(w),
|
||||
tracker: tracker,
|
||||
}
|
||||
}
|
||||
|
||||
// PublicAPI extends whisper public API.
|
||||
type PublicAPI struct {
|
||||
w *whisper.Whisper
|
||||
tracker *tracker
|
||||
w *whisper.Whisper
|
||||
publicAPI *whisper.PublicWhisperAPI
|
||||
tracker *tracker
|
||||
}
|
||||
|
||||
// Post shamelessly copied from whisper codebase with slight modifications.
|
||||
func (api *PublicAPI) Post(ctx context.Context, req whisper.NewMessage) (hash common.Hash, err error) {
|
||||
env, err := whisper.MakeEnvelope(api.w, req)
|
||||
if err != nil {
|
||||
return hash, err
|
||||
}
|
||||
// send to specific node (skip PoW check)
|
||||
if len(req.TargetPeer) > 0 {
|
||||
n, err := discover.ParseNode(req.TargetPeer)
|
||||
if err != nil {
|
||||
return hash, fmt.Errorf("failed to parse target peer: %s", err)
|
||||
}
|
||||
err = api.w.SendP2PMessage(n.ID[:], env)
|
||||
if err == nil {
|
||||
api.tracker.Add(env.Hash())
|
||||
return env.Hash(), nil
|
||||
}
|
||||
return hash, err
|
||||
}
|
||||
|
||||
// ensure that the message PoW meets the node's minimum accepted PoW
|
||||
if req.PowTarget < api.w.MinPow() {
|
||||
return hash, whisper.ErrTooLowPoW
|
||||
}
|
||||
err = api.w.Send(env)
|
||||
func (api *PublicAPI) Post(ctx context.Context, req whisper.NewMessage) (hash hexutil.Bytes, err error) {
|
||||
hash, err = api.publicAPI.Post(ctx, req)
|
||||
if err == nil {
|
||||
api.tracker.Add(env.Hash())
|
||||
return env.Hash(), nil
|
||||
var envHash common.Hash
|
||||
copy(envHash[:], hash[:]) // slice can't be used as key
|
||||
api.tracker.Add(envHash)
|
||||
}
|
||||
return hash, err
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ func (s *JailRPCTestSuite) TestIsConnected() {
|
|||
s.True(response)
|
||||
}
|
||||
|
||||
// regression test: eth_getTransactionReceipt with invalid transaction hash should return "error":{"code":-32000,"message":"unknown transaction"}
|
||||
// regression test: eth_getTransactionReceipt with invalid transaction hash should return "result":null.
|
||||
func (s *JailRPCTestSuite) TestRegressionGetTransactionReceipt() {
|
||||
s.StartTestBackend()
|
||||
defer s.StopTestBackend()
|
||||
|
@ -105,7 +105,7 @@ func (s *JailRPCTestSuite) TestRegressionGetTransactionReceipt() {
|
|||
|
||||
// note: transaction hash is assumed to be invalid
|
||||
got := rpcClient.CallRaw(`{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0xbbebf28d0a3a3cbb38e6053a5b21f08f82c62b0c145a17b1c4313cac3f68ae7c"],"id":7}`)
|
||||
expected := `{"jsonrpc":"2.0","id":7,"error":{"code":-32000,"message":"unknown transaction"}}`
|
||||
expected := `{"jsonrpc":"2.0","id":7,"result":null}`
|
||||
s.Equal(expected, got)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ func (s *RPCTestSuite) TestCallRawResult() {
|
|||
}
|
||||
|
||||
// TestCallRawResultGetTransactionReceipt checks if returned response
|
||||
// for a not yet mained transaction is "error":{"code":-32000,"message":"unknown transaction"}.
|
||||
// for a not yet mined transaction is "result": null.
|
||||
// Issue: https://github.com/status-im/status-go/issues/547
|
||||
func (s *RPCTestSuite) TestCallRawResultGetTransactionReceipt() {
|
||||
nodeConfig, err := MakeTestNodeConfig(GetNetworkID())
|
||||
|
@ -152,7 +152,7 @@ func (s *RPCTestSuite) TestCallRawResultGetTransactionReceipt() {
|
|||
s.NotNil(client)
|
||||
|
||||
jsonResult := client.CallRaw(`{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x0ca0d8f2422f62bea77e24ed17db5711a77fa72064cccbb8e53c53b699cd3b34"],"id":5}`)
|
||||
s.Equal(`{"jsonrpc":"2.0","id":5,"error":{"code":-32000,"message":"unknown transaction"}}`, jsonResult)
|
||||
s.Equal(`{"jsonrpc":"2.0","id":5,"result":null}`, jsonResult)
|
||||
|
||||
s.NoError(s.StatusNode.Stop())
|
||||
}
|
||||
|
|
|
@ -180,6 +180,8 @@ func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
|
|||
s.Require().NoError(err)
|
||||
// Generate a group chat topic.
|
||||
groupChatTopic := whisper.BytesToTopic([]byte("groupChatTopic"))
|
||||
// sender must be subscribed to message topic it sends
|
||||
s.NotNil(s.createGroupChatMessageFilter(aliceRPCClient, groupChatKeyID, groupChatTopic.String()))
|
||||
groupChatPayload := newGroupChatParams(groupChatKey, groupChatTopic)
|
||||
payloadStr, err := groupChatPayload.Encode()
|
||||
s.Require().NoError(err)
|
||||
|
@ -281,32 +283,6 @@ func (s *WhisperMailboxSuite) TestRequestMessagesInGroupChat() {
|
|||
s.Require().Equal(helloWorldMessage, messages[0]["payload"].(string))
|
||||
}
|
||||
|
||||
func (s *WhisperMailboxSuite) TestSendMessageWithoutSubscription() {
|
||||
aliceBackend, stop := s.startBackend("alice")
|
||||
defer stop()
|
||||
|
||||
// We need to wait >= whisper.DefaultSyncAllowance seconds to update Bloom filter tolerated.
|
||||
time.Sleep((whisper.DefaultSyncAllowance + 1) * time.Second)
|
||||
|
||||
// Get whisper service.
|
||||
aliceWhisperService, err := aliceBackend.StatusNode().WhisperService()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Get rpc client.
|
||||
aliceRPCClient := aliceBackend.StatusNode().RPCClient()
|
||||
|
||||
// Generate group chat symkey and topic.
|
||||
groupChatKeyID, err := aliceWhisperService.GenerateSymKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Generate group chat topic.
|
||||
groupChatTopic := whisper.BytesToTopic([]byte("groupChatTopic"))
|
||||
|
||||
// Alice send message to group chat.
|
||||
helloWorldMessage := hexutil.Encode([]byte("Hello world!"))
|
||||
s.postMessageToGroup(aliceRPCClient, groupChatKeyID, groupChatTopic.String(), helloWorldMessage)
|
||||
}
|
||||
|
||||
func newGroupChatParams(symkey []byte, topic whisper.TopicType) groupChatParams {
|
||||
groupChatKeyStr := hexutil.Bytes(symkey).String()
|
||||
return groupChatParams{
|
||||
|
|
1
vendor/github.com/ethereum/go-ethereum/.gitattributes
generated
vendored
1
vendor/github.com/ethereum/go-ethereum/.gitattributes
generated
vendored
|
@ -1,2 +1,3 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
*.sol linguist-language=Solidity
|
||||
|
|
3
vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/.github/CODEOWNERS
generated
vendored
|
@ -5,5 +5,8 @@ accounts/usbwallet @karalabe
|
|||
consensus @karalabe
|
||||
core/ @karalabe @holiman
|
||||
eth/ @karalabe
|
||||
les/ @zsfelfoldi
|
||||
light/ @zsfelfoldi
|
||||
mobile/ @karalabe
|
||||
p2p/ @fjl @zsfelfoldi
|
||||
whisper/ @gballet @gluk256
|
||||
|
|
11
vendor/github.com/ethereum/go-ethereum/.github/no-response.yml
generated
vendored
Normal file
11
vendor/github.com/ethereum/go-ethereum/.github/no-response.yml
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Number of days of inactivity before an Issue is closed for lack of response
|
||||
daysUntilClose: 30
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: more-information-needed
|
||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further.
|
17
vendor/github.com/ethereum/go-ethereum/.github/stale.yml
generated
vendored
Normal file
17
vendor/github.com/ethereum/go-ethereum/.github/stale.yml
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 366
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 42
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
6
vendor/github.com/ethereum/go-ethereum/.gitignore
generated
vendored
6
vendor/github.com/ethereum/go-ethereum/.gitignore
generated
vendored
|
@ -34,8 +34,14 @@ profile.cov
|
|||
# IdeaIDE
|
||||
.idea
|
||||
|
||||
# VS Code
|
||||
.vscode
|
||||
|
||||
# dashboard
|
||||
/dashboard/assets/flow-typed
|
||||
/dashboard/assets/node_modules
|
||||
/dashboard/assets/stats.json
|
||||
/dashboard/assets/bundle.js
|
||||
/dashboard/assets/package-lock.json
|
||||
|
||||
**/yarn-error.log
|
||||
|
|
58
vendor/github.com/ethereum/go-ethereum/.travis.yml
generated
vendored
58
vendor/github.com/ethereum/go-ethereum/.travis.yml
generated
vendored
|
@ -6,51 +6,40 @@ matrix:
|
|||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.7.x
|
||||
go: 1.9.x
|
||||
script:
|
||||
- sudo modprobe fuse
|
||||
- sudo chmod 666 /dev/fuse
|
||||
- sudo chown root:$USER /etc/fuse.conf
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.8.x
|
||||
script:
|
||||
- sudo modprobe fuse
|
||||
- sudo chmod 666 /dev/fuse
|
||||
- sudo chown root:$USER /etc/fuse.conf
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
# These are the latest Go versions.
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
script:
|
||||
- sudo modprobe fuse
|
||||
- sudo chmod 666 /dev/fuse
|
||||
- sudo chown root:$USER /etc/fuse.conf
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
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
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
|
||||
# This builder only tests code linters on latest version of Go
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
env:
|
||||
- lint
|
||||
git:
|
||||
|
@ -58,14 +47,12 @@ matrix:
|
|||
script:
|
||||
- go run build/ci.go lint
|
||||
|
||||
# This builder does the Ubuntu PPA and Linux Azure uploads
|
||||
# This builder does the Ubuntu PPA upload
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- azure-linux
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
|
@ -74,11 +61,25 @@ matrix:
|
|||
- devscripts
|
||||
- debhelper
|
||||
- dput
|
||||
- gcc-multilib
|
||||
- fakeroot
|
||||
script:
|
||||
# Build for the primary platforms that Trusty can manage
|
||||
- go run build/ci.go debsrc -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -upload ppa:ethereum/ethereum
|
||||
|
||||
# This builder does the Linux Azure uploads
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.10.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
script:
|
||||
# Build for the primary platforms that Trusty can manage
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||
- go run build/ci.go install -arch 386
|
||||
|
@ -102,7 +103,7 @@ matrix:
|
|||
dist: trusty
|
||||
services:
|
||||
- docker
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
env:
|
||||
- azure-linux-mips
|
||||
git:
|
||||
|
@ -146,7 +147,7 @@ matrix:
|
|||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
before_install:
|
||||
- curl https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz | tar -xz
|
||||
- curl https://storage.googleapis.com/golang/go1.10.1.linux-amd64.tar.gz | tar -xz
|
||||
- export PATH=`pwd`/go/bin:$PATH
|
||||
- export GOROOT=`pwd`/go
|
||||
- export GOPATH=$HOME/go
|
||||
|
@ -163,7 +164,7 @@ matrix:
|
|||
|
||||
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
env:
|
||||
- azure-osx
|
||||
- azure-ios
|
||||
|
@ -192,8 +193,7 @@ matrix:
|
|||
# This builder does the Azure archive purges to avoid accumulating junk
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
go: 1.10.x
|
||||
env:
|
||||
- azure-purge
|
||||
git:
|
||||
|
|
8
vendor/github.com/ethereum/go-ethereum/Dockerfile
generated
vendored
8
vendor/github.com/ethereum/go-ethereum/Dockerfile
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.9-alpine as builder
|
||||
FROM golang:1.10-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||
|
||||
|
@ -12,5 +12,11 @@ FROM alpine:latest
|
|||
RUN apk add --no-cache ca-certificates
|
||||
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
||||
|
||||
RUN addgroup -g 1000 geth && \
|
||||
adduser -h /root -D -u 1000 -G geth geth && \
|
||||
chown geth:geth /root
|
||||
|
||||
USER geth
|
||||
|
||||
EXPOSE 8545 8546 30303 30303/udp 30304/udp
|
||||
ENTRYPOINT ["geth"]
|
||||
|
|
8
vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools
generated
vendored
8
vendor/github.com/ethereum/go-ethereum/Dockerfile.alltools
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
# Build Geth in a stock Go builder container
|
||||
FROM golang:1.9-alpine as builder
|
||||
FROM golang:1.10-alpine as builder
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||
|
||||
|
@ -12,4 +12,10 @@ FROM alpine:latest
|
|||
RUN apk add --no-cache ca-certificates
|
||||
COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
||||
|
||||
RUN addgroup -g 1000 geth && \
|
||||
adduser -h /root -D -u 1000 -G geth geth && \
|
||||
chown geth:geth /root
|
||||
|
||||
USER geth
|
||||
|
||||
EXPOSE 8545 8546 30303 30303/udp 30304/udp
|
||||
|
|
3
vendor/github.com/ethereum/go-ethereum/Makefile
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/Makefile
generated
vendored
|
@ -37,6 +37,9 @@ ios:
|
|||
test: all
|
||||
build/env.sh go run build/ci.go test
|
||||
|
||||
lint: ## Run linters.
|
||||
build/env.sh go run build/ci.go lint
|
||||
|
||||
clean:
|
||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||
|
||||
|
|
4
vendor/github.com/ethereum/go-ethereum/README.md
generated
vendored
4
vendor/github.com/ethereum/go-ethereum/README.md
generated
vendored
|
@ -5,6 +5,8 @@ Official golang implementation of the Ethereum protocol.
|
|||
[![API Reference](
|
||||
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
|
||||
)](https://godoc.org/github.com/ethereum/go-ethereum)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
|
||||
[![Travis](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
|
||||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
Automated builds are available for stable releases and the unstable master branch.
|
||||
|
@ -140,7 +142,7 @@ Do not forget `--rpcaddr 0.0.0.0`, if you want to access RPC from other containe
|
|||
### Programatically interfacing Geth nodes
|
||||
|
||||
As a developer, sooner rather than later you'll want to start interacting with Geth and the Ethereum
|
||||
network via your own programs and not manually through the console. To aid this, Geth has built in
|
||||
network via your own programs and not manually through the console. To aid this, Geth has built-in
|
||||
support for a JSON-RPC based APIs ([standard APIs](https://github.com/ethereum/wiki/wiki/JSON-RPC) and
|
||||
[Geth specific APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)). These can be
|
||||
exposed via HTTP, WebSockets and IPC (unix sockets on unix based platforms, and named pipes on Windows).
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/VERSION
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/VERSION
generated
vendored
|
@ -1 +1 @@
|
|||
1.8.1
|
||||
1.8.5
|
||||
|
|
6
vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go
generated
vendored
6
vendor/github.com/ethereum/go-ethereum/accounts/abi/abi.go
generated
vendored
|
@ -136,11 +136,11 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
|||
|
||||
// MethodById looks up a method by the 4-byte id
|
||||
// returns nil if none found
|
||||
func (abi *ABI) MethodById(sigdata []byte) *Method {
|
||||
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
|
||||
for _, method := range abi.Methods {
|
||||
if bytes.Equal(method.Id(), sigdata[:4]) {
|
||||
return &method
|
||||
return &method, nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
|
||||
}
|
||||
|
|
180
vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go
generated
vendored
180
vendor/github.com/ethereum/go-ethereum/accounts/abi/argument.go
generated
vendored
|
@ -67,6 +67,17 @@ func (arguments Arguments) LengthNonIndexed() int {
|
|||
return out
|
||||
}
|
||||
|
||||
// NonIndexed returns the arguments with indexed arguments filtered out
|
||||
func (arguments Arguments) NonIndexed() Arguments {
|
||||
var ret []Argument
|
||||
for _, arg := range arguments {
|
||||
if !arg.Indexed {
|
||||
ret = append(ret, arg)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
|
||||
func (arguments Arguments) isTuple() bool {
|
||||
return len(arguments) > 1
|
||||
|
@ -74,21 +85,25 @@ func (arguments Arguments) isTuple() bool {
|
|||
|
||||
// Unpack performs the operation hexdata -> Go format
|
||||
func (arguments Arguments) Unpack(v interface{}, data []byte) error {
|
||||
if arguments.isTuple() {
|
||||
return arguments.unpackTuple(v, data)
|
||||
}
|
||||
return arguments.unpackAtomic(v, data)
|
||||
}
|
||||
|
||||
func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
|
||||
// make sure the passed value is arguments pointer
|
||||
valueOf := reflect.ValueOf(v)
|
||||
if reflect.Ptr != valueOf.Kind() {
|
||||
if reflect.Ptr != reflect.ValueOf(v).Kind() {
|
||||
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
|
||||
}
|
||||
marshalledValues, err := arguments.UnpackValues(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if arguments.isTuple() {
|
||||
return arguments.unpackTuple(v, marshalledValues)
|
||||
}
|
||||
return arguments.unpackAtomic(v, marshalledValues)
|
||||
}
|
||||
|
||||
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
|
||||
|
||||
var (
|
||||
value = valueOf.Elem()
|
||||
value = reflect.ValueOf(v).Elem()
|
||||
typ = value.Type()
|
||||
kind = value.Kind()
|
||||
)
|
||||
|
@ -98,53 +113,19 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
|
|||
}
|
||||
// If the output interface is a struct, make sure names don't collide
|
||||
if kind == reflect.Struct {
|
||||
exists := make(map[string]bool)
|
||||
for _, arg := range arguments {
|
||||
field := capitalise(arg.Name)
|
||||
if field == "" {
|
||||
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
|
||||
}
|
||||
if exists[field] {
|
||||
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
|
||||
}
|
||||
exists[field] = true
|
||||
}
|
||||
}
|
||||
// `i` counts the nonindexed arguments.
|
||||
// `j` counts the number of complex types.
|
||||
// both `i` and `j` are used to to correctly compute `data` offset.
|
||||
|
||||
i, j := -1, 0
|
||||
for _, arg := range arguments {
|
||||
|
||||
if arg.Indexed {
|
||||
// can't read, continue
|
||||
continue
|
||||
}
|
||||
i++
|
||||
marshalledValue, err := toGoType((i+j)*32, arg.Type, output)
|
||||
if err != nil {
|
||||
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i, arg := range arguments.NonIndexed() {
|
||||
|
||||
if arg.Type.T == ArrayTy {
|
||||
// combined index ('i' + 'j') need to be adjusted only by size of array, thus
|
||||
// we need to decrement 'j' because 'i' was incremented
|
||||
j += arg.Type.Size - 1
|
||||
}
|
||||
|
||||
reflectValue := reflect.ValueOf(marshalledValue)
|
||||
reflectValue := reflect.ValueOf(marshalledValues[i])
|
||||
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
name := capitalise(arg.Name)
|
||||
for j := 0; j < typ.NumField(); j++ {
|
||||
// TODO read tags: `abi:"fieldName"`
|
||||
if typ.Field(j).Name == name {
|
||||
if err := set(value.Field(j), reflectValue, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := unpackStruct(value, reflectValue, arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case reflect.Slice, reflect.Array:
|
||||
if value.Len() < i {
|
||||
|
@ -166,34 +147,84 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
|
|||
}
|
||||
|
||||
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
||||
func (arguments Arguments) unpackAtomic(v interface{}, output []byte) error {
|
||||
// make sure the passed value is arguments pointer
|
||||
valueOf := reflect.ValueOf(v)
|
||||
if reflect.Ptr != valueOf.Kind() {
|
||||
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
|
||||
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
|
||||
if len(marshalledValues) != 1 {
|
||||
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
|
||||
}
|
||||
arg := arguments[0]
|
||||
if arg.Indexed {
|
||||
return fmt.Errorf("abi: attempting to unpack indexed variable into element.")
|
||||
elem := reflect.ValueOf(v).Elem()
|
||||
kind := elem.Kind()
|
||||
reflectValue := reflect.ValueOf(marshalledValues[0])
|
||||
|
||||
if kind == reflect.Struct {
|
||||
//make sure names don't collide
|
||||
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return unpackStruct(elem, reflectValue, arguments[0])
|
||||
}
|
||||
|
||||
value := valueOf.Elem()
|
||||
return set(elem, reflectValue, arguments.NonIndexed()[0])
|
||||
|
||||
marshalledValue, err := toGoType(0, arg.Type, output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return set(value, reflect.ValueOf(marshalledValue), arg)
|
||||
}
|
||||
|
||||
// Unpack performs the operation Go format -> Hexdata
|
||||
// Computes the full size of an array;
|
||||
// i.e. counting nested arrays, which count towards size for unpacking.
|
||||
func getArraySize(arr *Type) int {
|
||||
size := arr.Size
|
||||
// Arrays can be nested, with each element being the same size
|
||||
arr = arr.Elem
|
||||
for arr.T == ArrayTy {
|
||||
// Keep multiplying by elem.Size while the elem is an array.
|
||||
size *= arr.Size
|
||||
arr = arr.Elem
|
||||
}
|
||||
// Now we have the full array size, including its children.
|
||||
return size
|
||||
}
|
||||
|
||||
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
|
||||
// without supplying a struct to unpack into. Instead, this method returns a list containing the
|
||||
// values. An atomic argument will be a list with one element.
|
||||
func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
|
||||
retval := make([]interface{}, 0, arguments.LengthNonIndexed())
|
||||
virtualArgs := 0
|
||||
for index, arg := range arguments.NonIndexed() {
|
||||
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
|
||||
if arg.Type.T == ArrayTy {
|
||||
// If we have a static array, like [3]uint256, these are coded as
|
||||
// just like uint256,uint256,uint256.
|
||||
// This means that we need to add two 'virtual' arguments when
|
||||
// we count the index from now on.
|
||||
//
|
||||
// Array values nested multiple levels deep are also encoded inline:
|
||||
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
|
||||
//
|
||||
// Calculate the full array size to get the correct offset for the next argument.
|
||||
// Decrement it by 1, as the normal index increment is still applied.
|
||||
virtualArgs += getArraySize(&arg.Type) - 1
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retval = append(retval, marshalledValue)
|
||||
}
|
||||
return retval, nil
|
||||
}
|
||||
|
||||
// PackValues performs the operation Go format -> Hexdata
|
||||
// It is the semantic opposite of UnpackValues
|
||||
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
|
||||
return arguments.Pack(args...)
|
||||
}
|
||||
|
||||
// Pack performs the operation Go format -> Hexdata
|
||||
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
||||
// Make sure arguments match up and pack them
|
||||
abiArgs := arguments
|
||||
if len(args) != len(abiArgs) {
|
||||
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs))
|
||||
}
|
||||
|
||||
// variable input is the output appended at the end of packed
|
||||
// output. This is used for strings and bytes types input.
|
||||
var variableInput []byte
|
||||
|
@ -207,7 +238,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
|||
inputOffset += 32
|
||||
}
|
||||
}
|
||||
|
||||
var ret []byte
|
||||
for i, a := range args {
|
||||
input := abiArgs[i]
|
||||
|
@ -216,7 +246,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check for a slice type (string, bytes, slice)
|
||||
if input.Type.requiresLengthPrefix() {
|
||||
// calculate the offset
|
||||
|
@ -248,3 +277,18 @@ func capitalise(input string) string {
|
|||
}
|
||||
return strings.ToUpper(input[:1]) + input[1:]
|
||||
}
|
||||
|
||||
//unpackStruct extracts each argument into its corresponding struct field
|
||||
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
|
||||
name := capitalise(arg.Name)
|
||||
typ := value.Type()
|
||||
for j := 0; j < typ.NumField(); j++ {
|
||||
// TODO read tags: `abi:"fieldName"`
|
||||
if typ.Field(j).Name == name {
|
||||
if err := set(value.Field(j), reflectValue, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
17
vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go
generated
vendored
17
vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/backends/simulated.go
generated
vendored
|
@ -306,9 +306,9 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
for _, tx := range b.pendingBlock.Transactions() {
|
||||
block.AddTx(tx)
|
||||
block.AddTxWithChain(b.blockchain, tx)
|
||||
}
|
||||
block.AddTx(tx)
|
||||
block.AddTxWithChain(b.blockchain, tx)
|
||||
})
|
||||
statedb, _ := b.blockchain.State()
|
||||
|
||||
|
@ -427,10 +427,23 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumb
|
|||
}
|
||||
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
|
||||
receipts := core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash))
|
||||
if receipts == nil {
|
||||
return nil, nil
|
||||
}
|
||||
logs := make([][]*types.Log, len(receipts))
|
||||
for i, receipt := range receipts {
|
||||
logs[i] = receipt.Logs
|
||||
}
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
<-quit
|
||||
|
|
208
vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go
generated
vendored
208
vendor/github.com/ethereum/go-ethereum/accounts/abi/bind/bind.go
generated
vendored
|
@ -164,118 +164,147 @@ var bindType = map[Lang]func(kind abi.Type) string{
|
|||
LangJava: bindTypeJava,
|
||||
}
|
||||
|
||||
// Helper function for the binding generators.
|
||||
// It reads the unmatched characters after the inner type-match,
|
||||
// (since the inner type is a prefix of the total type declaration),
|
||||
// looks for valid arrays (possibly a dynamic one) wrapping the inner type,
|
||||
// and returns the sizes of these arrays.
|
||||
//
|
||||
// Returned array sizes are in the same order as solidity signatures; inner array size first.
|
||||
// Array sizes may also be "", indicating a dynamic array.
|
||||
func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) {
|
||||
remainder := stringKind[innerLen:]
|
||||
//find all the sizes
|
||||
matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1)
|
||||
parts := make([]string, 0, len(matches))
|
||||
for _, match := range matches {
|
||||
//get group 1 from the regex match
|
||||
parts = append(parts, match[1])
|
||||
}
|
||||
return innerMapping, parts
|
||||
}
|
||||
|
||||
// Translates the array sizes to a Go-lang declaration of a (nested) array of the inner type.
|
||||
// Simply returns the inner type if arraySizes is empty.
|
||||
func arrayBindingGo(inner string, arraySizes []string) string {
|
||||
out := ""
|
||||
//prepend all array sizes, from outer (end arraySizes) to inner (start arraySizes)
|
||||
for i := len(arraySizes) - 1; i >= 0; i-- {
|
||||
out += "[" + arraySizes[i] + "]"
|
||||
}
|
||||
out += inner
|
||||
return out
|
||||
}
|
||||
|
||||
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
|
||||
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
||||
// mapped will use an upscaled type (e.g. *big.Int).
|
||||
func bindTypeGo(kind abi.Type) string {
|
||||
stringKind := kind.String()
|
||||
innerLen, innerMapping := bindUnnestedTypeGo(stringKind)
|
||||
return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping))
|
||||
}
|
||||
|
||||
// The inner function of bindTypeGo, this finds the inner type of stringKind.
|
||||
// (Or just the type itself if it is not an array or slice)
|
||||
// The length of the matched part is returned, with the the translated type.
|
||||
func bindUnnestedTypeGo(stringKind string) (int, string) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(stringKind, "address"):
|
||||
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%scommon.Address", parts[1])
|
||||
return len("address"), "common.Address"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bytes"):
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1])
|
||||
|
||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 4 {
|
||||
return stringKind
|
||||
}
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
switch parts[2] {
|
||||
case "8", "16", "32", "64":
|
||||
return fmt.Sprintf("%s%sint%s", parts[3], parts[1], parts[2])
|
||||
return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2])
|
||||
}
|
||||
return fmt.Sprintf("%s*big.Int", parts[3])
|
||||
return len(parts[0]), "*big.Int"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
|
||||
parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%s%s", parts[2], parts[1])
|
||||
case strings.HasPrefix(stringKind, "bool"):
|
||||
return len("bool"), "bool"
|
||||
|
||||
case strings.HasPrefix(stringKind, "string"):
|
||||
return len("string"), "string"
|
||||
|
||||
default:
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
}
|
||||
|
||||
// Translates the array sizes to a Java declaration of a (nested) array of the inner type.
|
||||
// Simply returns the inner type if arraySizes is empty.
|
||||
func arrayBindingJava(inner string, arraySizes []string) string {
|
||||
// Java array type declarations do not include the length.
|
||||
return inner + strings.Repeat("[]", len(arraySizes))
|
||||
}
|
||||
|
||||
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
|
||||
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
|
||||
// mapped will use an upscaled type (e.g. BigDecimal).
|
||||
func bindTypeJava(kind abi.Type) string {
|
||||
stringKind := kind.String()
|
||||
innerLen, innerMapping := bindUnnestedTypeJava(stringKind)
|
||||
return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping))
|
||||
}
|
||||
|
||||
// The inner function of bindTypeJava, this finds the inner type of stringKind.
|
||||
// (Or just the type itself if it is not an array or slice)
|
||||
// The length of the matched part is returned, with the the translated type.
|
||||
func bindUnnestedTypeJava(stringKind string) (int, string) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(stringKind, "address"):
|
||||
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("Address")
|
||||
return len("address"), "Address"
|
||||
}
|
||||
return fmt.Sprintf("Addresses")
|
||||
return len(parts[0]), "Addresses"
|
||||
|
||||
case strings.HasPrefix(stringKind, "bytes"):
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return stringKind
|
||||
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
if parts[2] != "" {
|
||||
return "byte[][]"
|
||||
}
|
||||
return "byte[]"
|
||||
return len(parts[0]), "byte[]"
|
||||
|
||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 4 {
|
||||
return stringKind
|
||||
//Note that uint and int (without digits) are also matched,
|
||||
// these are size 256, and will translate to BigInt (the default).
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 3 {
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
switch parts[2] {
|
||||
case "8", "16", "32", "64":
|
||||
if parts[1] == "" {
|
||||
if parts[3] == "" {
|
||||
return fmt.Sprintf("int%s", parts[2])
|
||||
}
|
||||
return fmt.Sprintf("int%s[]", parts[2])
|
||||
}
|
||||
|
||||
namedSize := map[string]string{
|
||||
"8": "byte",
|
||||
"16": "short",
|
||||
"32": "int",
|
||||
"64": "long",
|
||||
}[parts[2]]
|
||||
|
||||
//default to BigInt
|
||||
if namedSize == "" {
|
||||
namedSize = "BigInt"
|
||||
}
|
||||
if parts[3] == "" {
|
||||
return fmt.Sprintf("BigInt")
|
||||
}
|
||||
return fmt.Sprintf("BigInts")
|
||||
return len(parts[0]), namedSize
|
||||
|
||||
case strings.HasPrefix(stringKind, "bool"):
|
||||
parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("bool")
|
||||
}
|
||||
return fmt.Sprintf("bool[]")
|
||||
return len("bool"), "boolean"
|
||||
|
||||
case strings.HasPrefix(stringKind, "string"):
|
||||
parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||
if len(parts) != 2 {
|
||||
return stringKind
|
||||
}
|
||||
if parts[1] == "" {
|
||||
return fmt.Sprintf("String")
|
||||
}
|
||||
return fmt.Sprintf("String[]")
|
||||
return len("string"), "String"
|
||||
|
||||
default:
|
||||
return stringKind
|
||||
return len(stringKind), stringKind
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,11 +354,13 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
|||
return "String"
|
||||
case "string[]":
|
||||
return "Strings"
|
||||
case "bool":
|
||||
case "boolean":
|
||||
return "Bool"
|
||||
case "bool[]":
|
||||
case "boolean[]":
|
||||
return "Bools"
|
||||
case "BigInt":
|
||||
case "BigInt[]":
|
||||
return "BigInts"
|
||||
default:
|
||||
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
|
||||
if len(parts) != 4 {
|
||||
return javaKind
|
||||
|
@ -344,8 +375,6 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
|||
default:
|
||||
return javaKind
|
||||
}
|
||||
default:
|
||||
return javaKind
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,8 +385,7 @@ var methodNormalizer = map[Lang]func(string) string{
|
|||
LangJava: decapitalise,
|
||||
}
|
||||
|
||||
// capitalise makes the first character of a string upper case, also removing any
|
||||
// prefixing underscores from the variable names.
|
||||
// capitalise makes a camel-case string which starts with an upper case character.
|
||||
func capitalise(input string) string {
|
||||
for len(input) > 0 && input[0] == '_' {
|
||||
input = input[1:]
|
||||
|
@ -365,12 +393,42 @@ func capitalise(input string) string {
|
|||
if len(input) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(input[:1]) + input[1:]
|
||||
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
|
||||
}
|
||||
|
||||
// decapitalise makes the first character of a string lower case.
|
||||
// decapitalise makes a camel-case string which starts with a lower case character.
|
||||
func decapitalise(input string) string {
|
||||
return strings.ToLower(input[:1]) + input[1:]
|
||||
for len(input) > 0 && input[0] == '_' {
|
||||
input = input[1:]
|
||||
}
|
||||
if len(input) == 0 {
|
||||
return ""
|
||||
}
|
||||
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
|
||||
}
|
||||
|
||||
// toCamelCase converts an under-score string to a camel-case string
|
||||
func toCamelCase(input string) string {
|
||||
toupper := false
|
||||
|
||||
result := ""
|
||||
for k, v := range input {
|
||||
switch {
|
||||
case k == 0:
|
||||
result = strings.ToUpper(string(input[0]))
|
||||
|
||||
case toupper:
|
||||
result += strings.ToUpper(string(v))
|
||||
toupper = false
|
||||
|
||||
case v == '_':
|
||||
toupper = true
|
||||
|
||||
default:
|
||||
result += string(v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// structured checks whether a list of ABI data types has enough information to
|
||||
|
|
36
vendor/github.com/ethereum/go-ethereum/accounts/abi/numbers.go
generated
vendored
36
vendor/github.com/ethereum/go-ethereum/accounts/abi/numbers.go
generated
vendored
|
@ -25,23 +25,23 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
big_t = reflect.TypeOf(&big.Int{})
|
||||
derefbig_t = reflect.TypeOf(big.Int{})
|
||||
uint8_t = reflect.TypeOf(uint8(0))
|
||||
uint16_t = reflect.TypeOf(uint16(0))
|
||||
uint32_t = reflect.TypeOf(uint32(0))
|
||||
uint64_t = reflect.TypeOf(uint64(0))
|
||||
int_t = reflect.TypeOf(int(0))
|
||||
int8_t = reflect.TypeOf(int8(0))
|
||||
int16_t = reflect.TypeOf(int16(0))
|
||||
int32_t = reflect.TypeOf(int32(0))
|
||||
int64_t = reflect.TypeOf(int64(0))
|
||||
address_t = reflect.TypeOf(common.Address{})
|
||||
int_ts = reflect.TypeOf([]int(nil))
|
||||
int8_ts = reflect.TypeOf([]int8(nil))
|
||||
int16_ts = reflect.TypeOf([]int16(nil))
|
||||
int32_ts = reflect.TypeOf([]int32(nil))
|
||||
int64_ts = reflect.TypeOf([]int64(nil))
|
||||
bigT = reflect.TypeOf(&big.Int{})
|
||||
derefbigT = reflect.TypeOf(big.Int{})
|
||||
uint8T = reflect.TypeOf(uint8(0))
|
||||
uint16T = reflect.TypeOf(uint16(0))
|
||||
uint32T = reflect.TypeOf(uint32(0))
|
||||
uint64T = reflect.TypeOf(uint64(0))
|
||||
intT = reflect.TypeOf(int(0))
|
||||
int8T = reflect.TypeOf(int8(0))
|
||||
int16T = reflect.TypeOf(int16(0))
|
||||
int32T = reflect.TypeOf(int32(0))
|
||||
int64T = reflect.TypeOf(int64(0))
|
||||
addressT = reflect.TypeOf(common.Address{})
|
||||
intTS = reflect.TypeOf([]int(nil))
|
||||
int8TS = reflect.TypeOf([]int8(nil))
|
||||
int16TS = reflect.TypeOf([]int16(nil))
|
||||
int32TS = reflect.TypeOf([]int32(nil))
|
||||
int64TS = reflect.TypeOf([]int64(nil))
|
||||
)
|
||||
|
||||
// U256 converts a big Int into a 256bit EVM number.
|
||||
|
@ -52,7 +52,7 @@ func U256(n *big.Int) []byte {
|
|||
// checks whether the given reflect value is signed. This also works for slices with a number type
|
||||
func isSigned(v reflect.Value) bool {
|
||||
switch v.Type() {
|
||||
case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t:
|
||||
case intTS, int8TS, int16TS, int32TS, int64TS, intT, int8T, int16T, int32T, int64T:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
36
vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go
generated
vendored
36
vendor/github.com/ethereum/go-ethereum/accounts/abi/reflect.go
generated
vendored
|
@ -24,7 +24,7 @@ import (
|
|||
// indirect recursively dereferences the value until it either gets the value
|
||||
// or finds a big.Int
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbig_t {
|
||||
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT {
|
||||
return indirect(v.Elem())
|
||||
}
|
||||
return v
|
||||
|
@ -36,26 +36,26 @@ func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type)
|
|||
switch size {
|
||||
case 8:
|
||||
if unsigned {
|
||||
return reflect.Uint8, uint8_t
|
||||
return reflect.Uint8, uint8T
|
||||
}
|
||||
return reflect.Int8, int8_t
|
||||
return reflect.Int8, int8T
|
||||
case 16:
|
||||
if unsigned {
|
||||
return reflect.Uint16, uint16_t
|
||||
return reflect.Uint16, uint16T
|
||||
}
|
||||
return reflect.Int16, int16_t
|
||||
return reflect.Int16, int16T
|
||||
case 32:
|
||||
if unsigned {
|
||||
return reflect.Uint32, uint32_t
|
||||
return reflect.Uint32, uint32T
|
||||
}
|
||||
return reflect.Int32, int32_t
|
||||
return reflect.Int32, int32T
|
||||
case 64:
|
||||
if unsigned {
|
||||
return reflect.Uint64, uint64_t
|
||||
return reflect.Uint64, uint64T
|
||||
}
|
||||
return reflect.Int64, int64_t
|
||||
return reflect.Int64, int64T
|
||||
}
|
||||
return reflect.Ptr, big_t
|
||||
return reflect.Ptr, bigT
|
||||
}
|
||||
|
||||
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value
|
||||
|
@ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// requireUniqueStructFieldNames makes sure field names don't collide
|
||||
func requireUniqueStructFieldNames(args Arguments) error {
|
||||
exists := make(map[string]bool)
|
||||
for _, arg := range args {
|
||||
field := capitalise(arg.Name)
|
||||
if field == "" {
|
||||
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
|
||||
}
|
||||
if exists[field] {
|
||||
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
|
||||
}
|
||||
exists[field] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/accounts/abi/type.go
generated
vendored
|
@ -135,7 +135,7 @@ func NewType(t string) (typ Type, err error) {
|
|||
typ.Type = reflect.TypeOf(bool(false))
|
||||
case "address":
|
||||
typ.Kind = reflect.Array
|
||||
typ.Type = address_t
|
||||
typ.Type = addressT
|
||||
typ.Size = 20
|
||||
typ.T = AddressTy
|
||||
case "string":
|
||||
|
|
66
vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go
generated
vendored
66
vendor/github.com/ethereum/go-ethereum/accounts/abi/unpack.go
generated
vendored
|
@ -93,15 +93,28 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) {
|
|||
|
||||
}
|
||||
|
||||
func getFullElemSize(elem *Type) int {
|
||||
//all other should be counted as 32 (slices have pointers to respective elements)
|
||||
size := 32
|
||||
//arrays wrap it, each element being the same size
|
||||
for elem.T == ArrayTy {
|
||||
size *= elem.Size
|
||||
elem = elem.Elem
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// iteratively unpack elements
|
||||
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
|
||||
}
|
||||
if start+32*size > len(output) {
|
||||
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
|
||||
}
|
||||
|
||||
// this value will become our slice or our array, depending on the type
|
||||
var refSlice reflect.Value
|
||||
slice := output[start : start+size*32]
|
||||
|
||||
if t.T == SliceTy {
|
||||
// declare our slice
|
||||
|
@ -113,15 +126,20 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
|
|||
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
|
||||
}
|
||||
|
||||
for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 {
|
||||
// this corrects the arrangement so that we get all the underlying array values
|
||||
if t.Elem.T == ArrayTy && j != 0 {
|
||||
i = start + t.Elem.Size*32*j
|
||||
}
|
||||
// Arrays have packed elements, resulting in longer unpack steps.
|
||||
// Slices have just 32 bytes per element (pointing to the contents).
|
||||
elemSize := 32
|
||||
if t.T == ArrayTy {
|
||||
elemSize = getFullElemSize(t.Elem)
|
||||
}
|
||||
|
||||
for i, j := start, 0; j < size; i, j = i+elemSize, j+1 {
|
||||
|
||||
inter, err := toGoType(i, *t.Elem, output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// append the item to our reflect slice
|
||||
refSlice.Index(j).Set(reflect.ValueOf(inter))
|
||||
}
|
||||
|
@ -181,16 +199,32 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
|||
|
||||
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
|
||||
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
|
||||
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
||||
if offset+32 > len(output) {
|
||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
||||
}
|
||||
length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
|
||||
if offset+32+length > len(output) {
|
||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length)
|
||||
}
|
||||
start = offset + 32
|
||||
bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32])
|
||||
bigOffsetEnd.Add(bigOffsetEnd, common.Big32)
|
||||
outputLength := big.NewInt(int64(len(output)))
|
||||
|
||||
//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
|
||||
if bigOffsetEnd.Cmp(outputLength) > 0 {
|
||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", bigOffsetEnd, outputLength)
|
||||
}
|
||||
|
||||
if bigOffsetEnd.BitLen() > 63 {
|
||||
return 0, 0, fmt.Errorf("abi offset larger than int64: %v", bigOffsetEnd)
|
||||
}
|
||||
|
||||
offsetEnd := int(bigOffsetEnd.Uint64())
|
||||
lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd])
|
||||
|
||||
totalSize := big.NewInt(0)
|
||||
totalSize.Add(totalSize, bigOffsetEnd)
|
||||
totalSize.Add(totalSize, lengthBig)
|
||||
if totalSize.BitLen() > 63 {
|
||||
return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize)
|
||||
}
|
||||
|
||||
if totalSize.Cmp(outputLength) > 0 {
|
||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %v require %v", outputLength, totalSize)
|
||||
}
|
||||
start = int(bigOffsetEnd.Uint64())
|
||||
length = int(lengthBig.Uint64())
|
||||
return
|
||||
}
|
||||
|
|
16
vendor/github.com/ethereum/go-ethereum/accounts/url.go
generated
vendored
16
vendor/github.com/ethereum/go-ethereum/accounts/url.go
generated
vendored
|
@ -74,6 +74,22 @@ func (u URL) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(u.String())
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses url.
|
||||
func (u *URL) UnmarshalJSON(input []byte) error {
|
||||
var textUrl string
|
||||
err := json.Unmarshal(input, &textUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url, err := parseURL(textUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Scheme = url.Scheme
|
||||
u.Path = url.Path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/hub.go
generated
vendored
|
@ -127,7 +127,7 @@ func (hub *Hub) refreshWallets() {
|
|||
// breaking the Ledger protocol if that is waiting for user confirmation. This
|
||||
// is a bug acknowledged at Ledger, but it won't be fixed on old devices so we
|
||||
// need to prevent concurrent comms ourselves. The more elegant solution would
|
||||
// be to ditch enumeration in favor of hutplug events, but that don't work yet
|
||||
// be to ditch enumeration in favor of hotplug events, but that don't work yet
|
||||
// on Windows so if we need to hack it anyway, this is more elegant for now.
|
||||
hub.commsLock.Lock()
|
||||
if hub.commsPend > 0 { // A confirmation is pending, don't refresh
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/ledger.go
generated
vendored
|
@ -53,11 +53,9 @@ const (
|
|||
ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
|
||||
|
||||
ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet
|
||||
ledgerP1ConfirmFetchAddress ledgerParam1 = 0x01 // Require a user confirmation before returning the address
|
||||
ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing
|
||||
ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing
|
||||
ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
|
||||
ledgerP2ReturnAddressChainCode ledgerParam2 = 0x01 // Require a user confirmation before returning the address
|
||||
)
|
||||
|
||||
// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/accounts/usbwallet/wallet.go
generated
vendored
|
@ -99,7 +99,7 @@ type wallet struct {
|
|||
//
|
||||
// As such, a hardware wallet needs two locks to function correctly. A state
|
||||
// lock can be used to protect the wallet's software-side internal state, which
|
||||
// must not be held exlusively during hardware communication. A communication
|
||||
// must not be held exclusively during hardware communication. A communication
|
||||
// lock can be used to achieve exclusive access to the device itself, this one
|
||||
// however should allow "skipping" waiting for operations that might want to
|
||||
// use the device, but can live without too (e.g. account self-derivation).
|
||||
|
|
4
vendor/github.com/ethereum/go-ethereum/appveyor.yml
generated
vendored
4
vendor/github.com/ethereum/go-ethereum/appveyor.yml
generated
vendored
|
@ -23,8 +23,8 @@ environment:
|
|||
install:
|
||||
- git submodule update --init
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.9.2.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.9.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.10.1.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.10.1.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
|
9
vendor/github.com/ethereum/go-ethereum/bmt/bmt.go
generated
vendored
9
vendor/github.com/ethereum/go-ethereum/bmt/bmt.go
generated
vendored
|
@ -75,7 +75,7 @@ type Hasher struct {
|
|||
blocksize int // segment size (size of hash) also for hash.Hash
|
||||
count int // segment count
|
||||
size int // for hash.Hash same as hashsize
|
||||
cur int // cursor position for righmost currently open chunk
|
||||
cur int // cursor position for rightmost currently open chunk
|
||||
segment []byte // the rightmost open segment (not complete)
|
||||
depth int // index of last level
|
||||
result chan []byte // result channel
|
||||
|
@ -149,7 +149,7 @@ func NewTreePool(hasher BaseHasher, segmentCount, capacity int) *TreePool {
|
|||
}
|
||||
}
|
||||
|
||||
// Drain drains the pool uptil it has no more than n resources
|
||||
// Drain drains the pool until it has no more than n resources
|
||||
func (self *TreePool) Drain(n int) {
|
||||
self.lock.Lock()
|
||||
defer self.lock.Unlock()
|
||||
|
@ -412,11 +412,10 @@ func (self *Hasher) Reset() {
|
|||
|
||||
// ResetWithLength needs to be called before writing to the hasher
|
||||
// the argument is supposed to be the byte slice binary representation of
|
||||
// the legth of the data subsumed under the hash
|
||||
// the length of the data subsumed under the hash
|
||||
func (self *Hasher) ResetWithLength(l []byte) {
|
||||
self.Reset()
|
||||
self.blockLength = l
|
||||
|
||||
}
|
||||
|
||||
// Release gives back the Tree to the pool whereby it unlocks
|
||||
|
@ -531,7 +530,7 @@ func (self *Hasher) finalise(n *Node, i int) (d int) {
|
|||
for {
|
||||
// when the final segment's path is going via left segments
|
||||
// the incoming data is pushed to the parent upon pulling the left
|
||||
// we do not need toogle the state since this condition is
|
||||
// we do not need toggle the state since this condition is
|
||||
// detectable
|
||||
n.unbalanced = isLeft
|
||||
n.right = nil
|
||||
|
|
13
vendor/github.com/ethereum/go-ethereum/build/ci-notes.md
generated
vendored
13
vendor/github.com/ethereum/go-ethereum/build/ci-notes.md
generated
vendored
|
@ -2,12 +2,7 @@
|
|||
|
||||
Tagged releases and develop branch commits are available as installable Debian packages
|
||||
for Ubuntu. Packages are built for the all Ubuntu versions which are supported by
|
||||
Canonical:
|
||||
|
||||
- Trusty Tahr (14.04 LTS)
|
||||
- Xenial Xerus (16.04 LTS)
|
||||
- Yakkety Yak (16.10)
|
||||
- Zesty Zapus (17.04)
|
||||
Canonical.
|
||||
|
||||
Packages of develop branch commits have suffix -unstable and cannot be installed alongside
|
||||
the stable version. Switching between release streams requires user intervention.
|
||||
|
@ -21,18 +16,18 @@ variable which Travis CI makes available to certain builds.
|
|||
We want to build go-ethereum with the most recent version of Go, irrespective of the Go
|
||||
version that is available in the main Ubuntu repository. In order to make this possible,
|
||||
our PPA depends on the ~gophers/ubuntu/archive PPA. Our source package build-depends on
|
||||
golang-1.9, which is co-installable alongside the regular golang package. PPA dependencies
|
||||
golang-1.10, which is co-installable alongside the regular golang package. PPA dependencies
|
||||
can be edited at https://launchpad.net/%7Eethereum/+archive/ubuntu/ethereum/+edit-dependencies
|
||||
|
||||
## Building Packages Locally (for testing)
|
||||
|
||||
You need to run Ubuntu to do test packaging.
|
||||
|
||||
Add the gophers PPA and install Go 1.9 and Debian packaging tools:
|
||||
Add the gophers PPA and install Go 1.10 and Debian packaging tools:
|
||||
|
||||
$ sudo apt-add-repository ppa:gophers/ubuntu/archive
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install build-essential golang-1.9 devscripts debhelper
|
||||
$ sudo apt-get install build-essential golang-1.10 devscripts debhelper
|
||||
|
||||
Create the source packages:
|
||||
|
||||
|
|
30
vendor/github.com/ethereum/go-ethereum/build/ci.go
generated
vendored
30
vendor/github.com/ethereum/go-ethereum/build/ci.go
generated
vendored
|
@ -182,13 +182,13 @@ func doInstall(cmdline []string) {
|
|||
// Check Go version. People regularly open issues about compilation
|
||||
// failure with outdated Go. This should save them the trouble.
|
||||
if !strings.Contains(runtime.Version(), "devel") {
|
||||
// Figure out the minor version number since we can't textually compare (1.10 < 1.7)
|
||||
// Figure out the minor version number since we can't textually compare (1.10 < 1.9)
|
||||
var minor int
|
||||
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
||||
|
||||
if minor < 7 {
|
||||
if minor < 9 {
|
||||
log.Println("You have Go version", runtime.Version())
|
||||
log.Println("go-ethereum requires at least Go version 1.7 and cannot")
|
||||
log.Println("go-ethereum requires at least Go version 1.9 and cannot")
|
||||
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -262,16 +262,6 @@ func goTool(subcmd string, args ...string) *exec.Cmd {
|
|||
|
||||
func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd {
|
||||
cmd := build.GoTool(subcmd, args...)
|
||||
if subcmd == "build" || subcmd == "install" || subcmd == "test" {
|
||||
// Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756).
|
||||
// Work around issue by allowing multiple definitions for <1.8 builds.
|
||||
var minor int
|
||||
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
|
||||
|
||||
if runtime.GOOS == "windows" && minor < 8 {
|
||||
cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...)
|
||||
}
|
||||
}
|
||||
cmd.Env = []string{"GOPATH=" + build.GOPATH()}
|
||||
if arch == "" || arch == runtime.GOARCH {
|
||||
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
|
||||
|
@ -339,7 +329,10 @@ func doLint(cmdline []string) {
|
|||
// Run fast linters batched together
|
||||
configs := []string{
|
||||
"--vendor",
|
||||
"--tests",
|
||||
"--disable-all",
|
||||
"--enable=goimports",
|
||||
"--enable=varcheck",
|
||||
"--enable=vet",
|
||||
"--enable=gofmt",
|
||||
"--enable=misspell",
|
||||
|
@ -350,7 +343,7 @@ func doLint(cmdline []string) {
|
|||
|
||||
// Run slow linters one by one
|
||||
for _, linter := range []string{"unconvert", "gosimple"} {
|
||||
configs = []string{"--vendor", "--deadline=10m", "--disable-all", "--enable=" + linter}
|
||||
configs = []string{"--vendor", "--tests", "--deadline=10m", "--disable-all", "--enable=" + linter}
|
||||
build.MustRunCommand(filepath.Join(GOBIN, "gometalinter.v2"), append(configs, packages...)...)
|
||||
}
|
||||
}
|
||||
|
@ -736,7 +729,7 @@ func doAndroidArchive(cmdline []string) {
|
|||
log.Fatal("Please ensure ANDROID_NDK points to your Android NDK")
|
||||
}
|
||||
// Build the Android archive and Maven resources
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||
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"))
|
||||
|
||||
|
@ -776,7 +769,7 @@ func doAndroidArchive(cmdline []string) {
|
|||
if meta.Develop {
|
||||
repo = *deploy + "/content/repositories/snapshots"
|
||||
}
|
||||
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file",
|
||||
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", "-e", "-X",
|
||||
"-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh",
|
||||
"-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar")
|
||||
}
|
||||
|
@ -787,9 +780,10 @@ func gomobileTool(subcmd string, args ...string) *exec.Cmd {
|
|||
cmd.Args = append(cmd.Args, args...)
|
||||
cmd.Env = []string{
|
||||
"GOPATH=" + build.GOPATH(),
|
||||
"PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
|
||||
}
|
||||
for _, e := range os.Environ() {
|
||||
if strings.HasPrefix(e, "GOPATH=") {
|
||||
if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") {
|
||||
continue
|
||||
}
|
||||
cmd.Env = append(cmd.Env, e)
|
||||
|
@ -856,7 +850,7 @@ func doXCodeFramework(cmdline []string) {
|
|||
env := build.Env()
|
||||
|
||||
// Build the iOS XCode framework
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||
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")
|
||||
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/build/deb.control
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/build/deb.control
generated
vendored
|
@ -2,7 +2,7 @@ Source: {{.Name}}
|
|||
Section: science
|
||||
Priority: extra
|
||||
Maintainer: {{.Author}}
|
||||
Build-Depends: debhelper (>= 8.0.0), golang-1.9
|
||||
Build-Depends: debhelper (>= 8.0.0), golang-1.10
|
||||
Standards-Version: 3.9.5
|
||||
Homepage: https://ethereum.org
|
||||
Vcs-Git: git://github.com/ethereum/go-ethereum.git
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/build/deb.rules
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/build/deb.rules
generated
vendored
|
@ -5,7 +5,7 @@
|
|||
#export DH_VERBOSE=1
|
||||
|
||||
override_dh_auto_build:
|
||||
build/env.sh /usr/lib/go-1.9/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||
build/env.sh /usr/lib/go-1.10/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
|
||||
|
||||
override_dh_auto_test:
|
||||
|
||||
|
|
18
vendor/github.com/ethereum/go-ethereum/build/goimports.sh
generated
vendored
Executable file
18
vendor/github.com/ethereum/go-ethereum/build/goimports.sh
generated
vendored
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
find_files() {
|
||||
find . -not \( \
|
||||
\( \
|
||||
-wholename '.github' \
|
||||
-o -wholename './build/_workspace' \
|
||||
-o -wholename './build/bin' \
|
||||
-o -wholename './crypto/bn256' \
|
||||
-o -wholename '*/vendor/*' \
|
||||
\) -prune \
|
||||
\) -name '*.go'
|
||||
}
|
||||
|
||||
GOFMT="gofmt -s -w";
|
||||
GOIMPORTS="goimports -w";
|
||||
find_files | xargs $GOFMT;
|
||||
find_files | xargs $GOIMPORTS;
|
1
vendor/github.com/ethereum/go-ethereum/cmd/clef/4byte.json
generated
vendored
Normal file
1
vendor/github.com/ethereum/go-ethereum/cmd/clef/4byte.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
864
vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md
generated
vendored
Normal file
864
vendor/github.com/ethereum/go-ethereum/cmd/clef/README.md
generated
vendored
Normal file
|
@ -0,0 +1,864 @@
|
|||
Clef
|
||||
----
|
||||
Clef can be used to sign transactions and data and is meant as a replacement for geth's account management.
|
||||
This allows DApps not to depend on geth's account management. When a DApp wants to sign data it can send the data to
|
||||
the signer, the signer will then provide the user with context and asks the user for permission to sign the data. If
|
||||
the users grants the signing request the signer will send the signature back to the DApp.
|
||||
|
||||
This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can
|
||||
help in situations when a DApp is connected to a remote node because a local Ethereum node is not available, not
|
||||
synchronised with the chain or a particular Ethereum node that has no built-in (or limited) account management.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Command line flags
|
||||
Clef accepts the following command line options:
|
||||
```
|
||||
COMMANDS:
|
||||
init Initialize the signer, generate secret storage
|
||||
attest Attest that a js-file is to be used
|
||||
addpw Store a credential for a keystore file
|
||||
help Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--loglevel value log level to emit to the screen (default: 4)
|
||||
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
|
||||
--configdir value Directory for clef configuration (default: "$HOME/.clef")
|
||||
--networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1)
|
||||
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||
--nousb Disables monitoring for and managing USB hardware wallets
|
||||
--rpcaddr value HTTP-RPC server listening interface (default: "localhost")
|
||||
--rpcport value HTTP-RPC server listening port (default: 8550)
|
||||
--signersecret value A file containing the password used to encrypt signer credentials, e.g. keystore credentials and ruleset hash
|
||||
--4bytedb value File containing 4byte-identifiers (default: "./4byte.json")
|
||||
--4bytedb-custom value File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json")
|
||||
--auditlog value File used to emit audit logs. Set to "" to disable (default: "audit.log")
|
||||
--rules value Enable rule-engine (default: "rules.json")
|
||||
--stdio-ui Use STDIN/STDOUT as a channel for an external UI. This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user interface, and can be used when the signer is started by an external process.
|
||||
--stdio-ui-test Mechanism to test interface between signer and UI. Requires 'stdio-ui'.
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
|
||||
```
|
||||
|
||||
|
||||
Example:
|
||||
```
|
||||
signer -keystore /my/keystore -chainid 4
|
||||
```
|
||||
|
||||
Check out the [tutorial](tutorial.md) for some concrete examples on how the signer works.
|
||||
|
||||
## Security model
|
||||
|
||||
The security model of the signer is as follows:
|
||||
|
||||
* One critical component (the signer binary / daemon) is responsible for handling cryptographic operations: signing, private keys, encryption/decryption of keystore files.
|
||||
* The signer binary has a well-defined 'external' API.
|
||||
* The 'external' API is considered UNTRUSTED.
|
||||
* The signer binary also communicates with whatever process that invoked the binary, via stdin/stdout.
|
||||
* This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated.
|
||||
|
||||
The general flow for signing a transaction using e.g. geth is as follows:
|
||||
![image](sign_flow.png)
|
||||
|
||||
In this case, `geth` would be started with `--externalsigner=http://localhost:8550` and would relay requests to `eth.sendTransaction`.
|
||||
|
||||
## TODOs
|
||||
|
||||
Some snags and todos
|
||||
|
||||
* [ ] The signer should take a startup param "--no-change", for UIs that do not contain the capability
|
||||
to perform changes to things, only approve/deny. Such a UI should be able to start the signer in
|
||||
a more secure mode by telling it that it only wants approve/deny capabilities.
|
||||
|
||||
* [x] It would be nice if the signer could collect new 4byte-id:s/method selectors, and have a
|
||||
secondary database for those (`4byte_custom.json`). Users could then (optionally) submit their collections for
|
||||
inclusion upstream.
|
||||
|
||||
* It should be possible to configure the signer to check if an account is indeed known to it, before
|
||||
passing on to the UI. The reason it currently does not, is that it would make it possible to enumerate
|
||||
accounts if it immediately returned "unknown account".
|
||||
* [x] It should be possible to configure the signer to auto-allow listing (certain) accounts, instead of asking every time.
|
||||
* [x] Done Upon startup, the signer should spit out some info to the caller (particularly important when executed in `stdio-ui`-mode),
|
||||
invoking methods with the following info:
|
||||
* [x] Version info about the signer
|
||||
* [x] Address of API (http/ipc)
|
||||
* [ ] List of known accounts
|
||||
* [ ] Have a default timeout on signing operations, so that if the user has not answered withing e.g. 60 seconds, the request is rejected.
|
||||
* [ ] `account_signRawTransaction`
|
||||
* [ ] `account_bulkSignTransactions([] transactions)` should
|
||||
* only exist if enabled via config/flag
|
||||
* only allow non-data-sending transactions
|
||||
* all txs must use the same `from`-account
|
||||
* let the user confirm, showing
|
||||
* the total amount
|
||||
* the number of unique recipients
|
||||
|
||||
* Geth todos
|
||||
- The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is
|
||||
put together is a bit of a hack into the http server. This could probably be greatly improved
|
||||
- Relay: Geth should be started in `geth --external_signer localhost:8550`.
|
||||
- Currently, the Geth APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This
|
||||
type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which
|
||||
retains the original input.
|
||||
- The Geth api should switch to use the same type, and relay `to`-account verbatim to the external api.
|
||||
|
||||
* [x] Storage
|
||||
* [x] An encrypted key-value storage should be implemented
|
||||
* See [rules.md](rules.md) for more info about this.
|
||||
|
||||
* Another potential thing to introduce is pairing.
|
||||
* To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API).
|
||||
* Thus geth/mist/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests.
|
||||
* This feature would make the addition of rules less dangerous.
|
||||
|
||||
* Wallets / accounts. Add API methods for wallets.
|
||||
|
||||
## Communication
|
||||
|
||||
### External API
|
||||
|
||||
The signer listens to HTTP requests on `rpcaddr`:`rpcport`, with the same JSONRPC standard as Geth. The messages are
|
||||
expected to be JSON [jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
|
||||
|
||||
Some of these call can require user interaction. Clients must be aware that responses
|
||||
may be delayed significanlty or may never be received if a users decides to ignore the confirmation request.
|
||||
|
||||
The External API is **untrusted** : it does not accept credentials over this api, nor does it expect
|
||||
that requests have any authority.
|
||||
|
||||
### UI API
|
||||
|
||||
The signer has one native console-based UI, for operation without any standalone tools.
|
||||
However, there is also an API to communicate with an external UI. To enable that UI,
|
||||
the signer needs to be executed with the `--stdio-ui` option, which allocates the
|
||||
`stdin`/`stdout` for the UI-api.
|
||||
|
||||
An example (insecure) proof-of-concept of has been implemented in `pythonsigner.py`.
|
||||
|
||||
The model is as follows:
|
||||
|
||||
* The user starts the UI app (`pythonsigner.py`).
|
||||
* The UI app starts the `signer` with `--stdio-ui`, and listens to the
|
||||
process output for confirmation-requests.
|
||||
* The `signer` opens the external http api.
|
||||
* When the `signer` receives requests, it sends a `jsonrpc` request via `stdout`.
|
||||
* The UI app prompts the user accordingly, and responds to the `signer`
|
||||
* The `signer` signs (or not), and responds to the original request.
|
||||
|
||||
## External API
|
||||
|
||||
See the [external api changelog](extapi_changelog.md) for information about changes to this API.
|
||||
|
||||
### Encoding
|
||||
- number: positive integers that are hex encoded
|
||||
- data: hex encoded data
|
||||
- string: ASCII string
|
||||
|
||||
All hex encoded values must be prefixed with `0x`.
|
||||
|
||||
## Methods
|
||||
|
||||
### account_new
|
||||
|
||||
#### Create new password protected account
|
||||
|
||||
The signer will generate a new private key, encrypts it according to [web3 keystore spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) and stores it in the keystore directory.
|
||||
The client is responsible for creating a backup of the keystore. If the keystore is lost there is no method of retrieving lost accounts.
|
||||
|
||||
#### Arguments
|
||||
|
||||
None
|
||||
|
||||
#### Result
|
||||
- address [string]: account address that is derived from the generated key
|
||||
- url [string]: location of the keyfile
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_new",
|
||||
"params": []
|
||||
}
|
||||
|
||||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133",
|
||||
"url": "keystore:///my/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### account_list
|
||||
|
||||
#### List available accounts
|
||||
List all accounts that this signer currently manages
|
||||
|
||||
#### Arguments
|
||||
|
||||
None
|
||||
|
||||
#### Result
|
||||
- array with account records:
|
||||
- account.address [string]: account address that is derived from the generated key
|
||||
- account.type [string]: type of the
|
||||
- account.url [string]: location of the account
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_list"
|
||||
}
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"result": [
|
||||
{
|
||||
"address": "0xafb2f771f58513609765698f65d3f2f0224a956f",
|
||||
"type": "account",
|
||||
"url": "keystore:///tmp/keystore/UTC--2017-08-24T07-26-47.162109726Z--afb2f771f58513609765698f65d3f2f0224a956f"
|
||||
},
|
||||
{
|
||||
"address": "0xbea9183f8f4f03d427f6bcea17388bdff1cab133",
|
||||
"type": "account",
|
||||
"url": "keystore:///tmp/keystore/UTC--2017-08-24T08-40-15.419655028Z--bea9183f8f4f03d427f6bcea17388bdff1cab133"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### account_signTransaction
|
||||
|
||||
#### Sign transactions
|
||||
Signs a transactions and responds with the signed transaction in RLP encoded form.
|
||||
|
||||
#### Arguments
|
||||
2. transaction object:
|
||||
- `from` [address]: account to send the transaction from
|
||||
- `to` [address]: receiver account. If omitted or `0x`, will cause contract creation.
|
||||
- `gas` [number]: maximum amount of gas to burn
|
||||
- `gasPrice` [number]: gas price
|
||||
- `value` [number:optional]: amount of Wei to send with the transaction
|
||||
- `data` [data:optional]: input data
|
||||
- `nonce` [number]: account nonce
|
||||
3. method signature [string:optional]
|
||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||
|
||||
|
||||
#### Result
|
||||
- signed transaction in RLP encoded form [data]
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_signTransaction",
|
||||
"params": [
|
||||
{
|
||||
"from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
||||
"gas": "0x55555",
|
||||
"gasPrice": "0x1234",
|
||||
"input": "0xabcd",
|
||||
"nonce": "0x0",
|
||||
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"value": "0x1234"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 67,
|
||||
"error": {
|
||||
"code": -32000,
|
||||
"message": "Request denied"
|
||||
}
|
||||
}
|
||||
```
|
||||
#### Sample call with ABI-data
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_signTransaction",
|
||||
"params": [
|
||||
{
|
||||
"from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa",
|
||||
"gas": "0x333",
|
||||
"gasPrice": "0x1",
|
||||
"nonce": "0x0",
|
||||
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"value": "0x0",
|
||||
"data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
|
||||
},
|
||||
"safeSend(address)"
|
||||
],
|
||||
"id": 67
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 67,
|
||||
"result": {
|
||||
"raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
|
||||
"tx": {
|
||||
"nonce": "0x0",
|
||||
"gasPrice": "0x1",
|
||||
"gas": "0x333",
|
||||
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"value": "0x0",
|
||||
"input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
|
||||
"v": "0x26",
|
||||
"r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
|
||||
"s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
|
||||
"hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bash example:
|
||||
```bash
|
||||
#curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
|
||||
|
||||
{"jsonrpc":"2.0","id":67,"result":{"raw":"0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","tx":{"nonce":"0x0","gasPrice":"0x1","gas":"0x333","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0","value":"0x0","input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012","v":"0x26","r":"0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e","s":"0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","hash":"0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"}}}
|
||||
```
|
||||
|
||||
|
||||
### account_sign
|
||||
|
||||
#### Sign data
|
||||
Signs a chunk of data and returns the calculated signature.
|
||||
|
||||
#### Arguments
|
||||
- account [address]: account to sign with
|
||||
- data [data]: data to sign
|
||||
|
||||
#### Result
|
||||
- calculated signature [data]
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 3,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_sign",
|
||||
"params": [
|
||||
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
||||
"0xaabbccdd"
|
||||
]
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 3,
|
||||
"jsonrpc": "2.0",
|
||||
"result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
|
||||
}
|
||||
```
|
||||
|
||||
### account_ecRecover
|
||||
|
||||
#### Recover address
|
||||
Derive the address from the account that was used to sign data from the data and signature.
|
||||
|
||||
#### Arguments
|
||||
- data [data]: data that was signed
|
||||
- signature [data]: the signature to verify
|
||||
|
||||
#### Result
|
||||
- derived account [address]
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 4,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_ecRecover",
|
||||
"params": [
|
||||
"0xaabbccdd",
|
||||
"0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c"
|
||||
]
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 4,
|
||||
"jsonrpc": "2.0",
|
||||
"result": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### account_import
|
||||
|
||||
#### Import account
|
||||
Import a private key into the keystore. The imported key is expected to be encrypted according to the web3 keystore
|
||||
format.
|
||||
|
||||
#### Arguments
|
||||
- account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export)
|
||||
|
||||
#### Result
|
||||
- imported key [object]:
|
||||
- key.address [address]: address of the imported key
|
||||
- key.type [string]: type of the account
|
||||
- key.url [string]: key URL
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 6,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_import",
|
||||
"params": [
|
||||
{
|
||||
"address": "c7412fc59930fd90099c917a50e5f11d0934b2f5",
|
||||
"crypto": {
|
||||
"cipher": "aes-128-ctr",
|
||||
"cipherparams": {
|
||||
"iv": "401c39a7c7af0388491c3d3ecb39f532"
|
||||
},
|
||||
"ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204",
|
||||
"kdf": "scrypt",
|
||||
"kdfparams": {
|
||||
"dklen": 32,
|
||||
"n": 262144,
|
||||
"p": 1,
|
||||
"r": 8,
|
||||
"salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a"
|
||||
},
|
||||
"mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806"
|
||||
},
|
||||
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
|
||||
"version": 3
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 6,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"address": "0xc7412fc59930fd90099c917a50e5f11d0934b2f5",
|
||||
"type": "account",
|
||||
"url": "keystore:///tmp/keystore/UTC--2017-08-24T11-00-42.032024108Z--c7412fc59930fd90099c917a50e5f11d0934b2f5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### account_export
|
||||
|
||||
#### Export account from keystore
|
||||
Export a private key from the keystore. The exported private key is encrypted with the original passphrase. When the
|
||||
key is imported later this passphrase is required.
|
||||
|
||||
#### Arguments
|
||||
- account [address]: export private key that is associated with this account
|
||||
|
||||
#### Result
|
||||
- exported key, see [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) for
|
||||
more information
|
||||
|
||||
#### Sample call
|
||||
```json
|
||||
{
|
||||
"id": 5,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "account_export",
|
||||
"params": [
|
||||
"0xc7412fc59930fd90099c917a50e5f11d0934b2f5"
|
||||
]
|
||||
}
|
||||
```
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 5,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"address": "c7412fc59930fd90099c917a50e5f11d0934b2f5",
|
||||
"crypto": {
|
||||
"cipher": "aes-128-ctr",
|
||||
"cipherparams": {
|
||||
"iv": "401c39a7c7af0388491c3d3ecb39f532"
|
||||
},
|
||||
"ciphertext": "eb045260b18dd35cd0e6d99ead52f8fa1e63a6b0af2d52a8de198e59ad783204",
|
||||
"kdf": "scrypt",
|
||||
"kdfparams": {
|
||||
"dklen": 32,
|
||||
"n": 262144,
|
||||
"p": 1,
|
||||
"r": 8,
|
||||
"salt": "9a657e3618527c9b5580ded60c12092e5038922667b7b76b906496f021bb841a"
|
||||
},
|
||||
"mac": "880dc10bc06e9cec78eb9830aeb1e7a4a26b4c2c19615c94acb632992b952806"
|
||||
},
|
||||
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
|
||||
"version": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## UI API
|
||||
|
||||
These methods needs to be implemented by a UI listener.
|
||||
|
||||
By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
|
||||
denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
|
||||
See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
|
||||
|
||||
All methods in this API uses object-based parameters, so that there can be no mixups of parameters: each piece of data is accessed by key.
|
||||
|
||||
See the [ui api changelog](intapi_changelog.md) for information about changes to this API.
|
||||
|
||||
OBS! A slight deviation from `json` standard is in place: every request and response should be confined to a single line.
|
||||
Whereas the `json` specification allows for linebreaks, linebreaks __should not__ be used in this communication channel, to make
|
||||
things simpler for both parties.
|
||||
|
||||
### ApproveTx
|
||||
|
||||
Invoked when there's a transaction for approval.
|
||||
|
||||
|
||||
#### Sample call
|
||||
|
||||
Here's a method invocation:
|
||||
```bash
|
||||
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
|
||||
```
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "ApproveTx",
|
||||
"params": [
|
||||
{
|
||||
"transaction": {
|
||||
"from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
|
||||
"to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"gas": "0x333",
|
||||
"gasPrice": "0x1",
|
||||
"value": "0x0",
|
||||
"nonce": "0x0",
|
||||
"data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
|
||||
"input": null
|
||||
},
|
||||
"call_info": [
|
||||
{
|
||||
"type": "WARNING",
|
||||
"message": "Invalid checksum on to-address"
|
||||
},
|
||||
{
|
||||
"type": "Info",
|
||||
"message": "safeSend(address: 0x0000000000000000000000000000000000000012)"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"remote": "127.0.0.1:48486",
|
||||
"local": "localhost:8550",
|
||||
"scheme": "HTTP/1.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The same method invocation, but with invalid data:
|
||||
```bash
|
||||
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000002000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
|
||||
```
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "ApproveTx",
|
||||
"params": [
|
||||
{
|
||||
"transaction": {
|
||||
"from": "0x0x694267f14675d7e1b9494fd8d72fefe1755710fa",
|
||||
"to": "0x0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"gas": "0x333",
|
||||
"gasPrice": "0x1",
|
||||
"value": "0x0",
|
||||
"nonce": "0x0",
|
||||
"data": "0x4401a6e40000000000000002000000000000000000000000000000000000000000000012",
|
||||
"input": null
|
||||
},
|
||||
"call_info": [
|
||||
{
|
||||
"type": "WARNING",
|
||||
"message": "Invalid checksum on to-address"
|
||||
},
|
||||
{
|
||||
"type": "WARNING",
|
||||
"message": "Transaction data did not match ABI-interface: WARNING: Supplied data is stuffed with extra data. \nWant 0000000000000002000000000000000000000000000000000000000000000012\nHave 0000000000000000000000000000000000000000000000000000000000000012\nfor method safeSend(address)"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"remote": "127.0.0.1:48492",
|
||||
"local": "localhost:8550",
|
||||
"scheme": "HTTP/1.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
One which has missing `to`, but with no `data`:
|
||||
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "ApproveTx",
|
||||
"params": [
|
||||
{
|
||||
"transaction": {
|
||||
"from": "",
|
||||
"to": null,
|
||||
"gas": "0x0",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
"nonce": "0x0",
|
||||
"data": null,
|
||||
"input": null
|
||||
},
|
||||
"call_info": [
|
||||
{
|
||||
"type": "CRITICAL",
|
||||
"message": "Tx will create contract with empty code!"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"remote": "signer binary",
|
||||
"local": "main",
|
||||
"scheme": "in-proc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### ApproveExport
|
||||
|
||||
Invoked when a request to export an account has been made.
|
||||
|
||||
#### Sample call
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 7,
|
||||
"method": "ApproveExport",
|
||||
"params": [
|
||||
{
|
||||
"address": "0x0000000000000000000000000000000000000000",
|
||||
"meta": {
|
||||
"remote": "signer binary",
|
||||
"local": "main",
|
||||
"scheme": "in-proc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### ApproveListing
|
||||
|
||||
Invoked when a request for account listing has been made.
|
||||
|
||||
#### Sample call
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 5,
|
||||
"method": "ApproveListing",
|
||||
"params": [
|
||||
{
|
||||
"accounts": [
|
||||
{
|
||||
"type": "Account",
|
||||
"url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42",
|
||||
"address": "0x123409812340981234098123409812deadbeef42"
|
||||
},
|
||||
{
|
||||
"type": "Account",
|
||||
"url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42",
|
||||
"address": "0xcafebabedeadbeef34098123409812deadbeef42"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"remote": "signer binary",
|
||||
"local": "main",
|
||||
"scheme": "in-proc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### ApproveSignData
|
||||
|
||||
#### Sample call
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 4,
|
||||
"method": "ApproveSignData",
|
||||
"params": [
|
||||
{
|
||||
"address": "0x123409812340981234098123409812deadbeef42",
|
||||
"raw_data": "0x01020304",
|
||||
"message": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004",
|
||||
"hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310",
|
||||
"meta": {
|
||||
"remote": "signer binary",
|
||||
"local": "main",
|
||||
"scheme": "in-proc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### ShowInfo
|
||||
|
||||
The UI should show the info to the user. Does not expect response.
|
||||
|
||||
#### Sample call
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 9,
|
||||
"method": "ShowInfo",
|
||||
"params": [
|
||||
{
|
||||
"text": "Tests completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### ShowError
|
||||
|
||||
The UI should show the info to the user. Does not expect response.
|
||||
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"method": "ShowError",
|
||||
"params": [
|
||||
{
|
||||
"text": "Testing 'ShowError'"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### OnApproved
|
||||
|
||||
`OnApprovedTx` is called when a transaction has been approved and signed. The call contains the return value that will be sent to the external caller. The return value from this method is ignored - the reason for having this callback is to allow the ruleset to keep track of approved transactions.
|
||||
|
||||
When implementing rate-limited rules, this callback should be used.
|
||||
|
||||
TLDR; Use this method to keep track of signed transactions, instead of using the data in `ApproveTx`.
|
||||
|
||||
### OnSignerStartup
|
||||
|
||||
This method provide the UI with information about what API version the signer uses (both internal and external) aswell as build-info and external api,
|
||||
in k/v-form.
|
||||
|
||||
Example call:
|
||||
```json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "OnSignerStartup",
|
||||
"params": [
|
||||
{
|
||||
"info": {
|
||||
"extapi_http": "http://localhost:8550",
|
||||
"extapi_ipc": null,
|
||||
"extapi_version": "2.0.0",
|
||||
"intapi_version": "1.2.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Rules for UI apis
|
||||
|
||||
A UI should conform to the following rules.
|
||||
|
||||
* A UI MUST NOT load any external resources that were not embedded/part of the UI package.
|
||||
* For example, not load icons, stylesheets from the internet
|
||||
* Not load files from the filesystem, unless they reside in the same local directory (e.g. config files)
|
||||
* A Graphical UI MUST show the blocky-identicon for ethereum addresses.
|
||||
* A UI MUST warn display approproate warning if the destination-account is formatted with invalid checksum.
|
||||
* A UI MUST NOT open any ports or services
|
||||
* The signer opens the public port
|
||||
* A UI SHOULD verify the permissions on the signer binary, and refuse to execute or warn if permissions allow non-user write.
|
||||
* A UI SHOULD inform the user about the `SHA256` or `MD5` hash of the binary being executed
|
||||
* A UI SHOULD NOT maintain a secondary storage of data, e.g. list of accounts
|
||||
* The signer provides accounts
|
||||
* A UI SHOULD, to the best extent possible, use static linking / bundling, so that requried libraries are bundled
|
||||
along with the UI.
|
||||
|
||||
|
25
vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md
generated
vendored
Normal file
25
vendor/github.com/ethereum/go-ethereum/cmd/clef/extapi_changelog.md
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
### Changelog for external API
|
||||
|
||||
|
||||
|
||||
#### 2.0.0
|
||||
|
||||
* Commit `73abaf04b1372fa4c43201fb1b8019fe6b0a6f8d`, move `from` into `transaction` object in `signTransaction`. This
|
||||
makes the `accounts_signTransaction` identical to the old `eth_signTransaction`.
|
||||
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
Initial release.
|
||||
|
||||
### Versioning
|
||||
|
||||
The API uses [semantic versioning](https://semver.org/).
|
||||
|
||||
TLDR; Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
|
||||
* MAJOR version when you make incompatible API changes,
|
||||
* MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
* PATCH version when you make backwards-compatible bug fixes.
|
||||
|
||||
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
|
86
vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md
generated
vendored
Normal file
86
vendor/github.com/ethereum/go-ethereum/cmd/clef/intapi_changelog.md
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
### Changelog for internal API (ui-api)
|
||||
|
||||
### 2.0.0
|
||||
|
||||
* Modify how `call_info` on a transaction is conveyed. New format:
|
||||
|
||||
```
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"method": "ApproveTx",
|
||||
"params": [
|
||||
{
|
||||
"transaction": {
|
||||
"from": "0x82A2A876D39022B3019932D30Cd9c97ad5616813",
|
||||
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
|
||||
"gas": "0x333",
|
||||
"gasPrice": "0x123",
|
||||
"value": "0x10",
|
||||
"nonce": "0x0",
|
||||
"data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
|
||||
"input": null
|
||||
},
|
||||
"call_info": [
|
||||
{
|
||||
"type": "WARNING",
|
||||
"message": "Invalid checksum on to-address"
|
||||
},
|
||||
{
|
||||
"type": "WARNING",
|
||||
"message": "Tx contains data, but provided ABI signature could not be matched: Did not match: test (0 matches)"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"remote": "127.0.0.1:54286",
|
||||
"local": "localhost:8550",
|
||||
"scheme": "HTTP/1.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2.0
|
||||
|
||||
* Add `OnStartup` method, to provide the UI with information about what API version
|
||||
the signer uses (both internal and external) aswell as build-info and external api.
|
||||
|
||||
Example call:
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "OnSignerStartup",
|
||||
"params": [
|
||||
{
|
||||
"info": {
|
||||
"extapi_http": "http://localhost:8550",
|
||||
"extapi_ipc": null,
|
||||
"extapi_version": "2.0.0",
|
||||
"intapi_version": "1.2.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.1.0
|
||||
|
||||
* Add `OnApproved` method
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
Initial release.
|
||||
|
||||
### Versioning
|
||||
|
||||
The API uses [semantic versioning](https://semver.org/).
|
||||
|
||||
TLDR; Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
|
||||
* MAJOR version when you make incompatible API changes,
|
||||
* MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
* PATCH version when you make backwards-compatible bug fixes.
|
||||
|
||||
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
|
640
vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go
generated
vendored
Normal file
640
vendor/github.com/ethereum/go-ethereum/cmd/clef/main.go
generated
vendored
Normal file
|
@ -0,0 +1,640 @@
|
|||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// signer is a utility that can be used so sign transactions and
|
||||
// arbitrary data.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/signer/core"
|
||||
"github.com/ethereum/go-ethereum/signer/rules"
|
||||
"github.com/ethereum/go-ethereum/signer/storage"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// ExternalApiVersion -- see extapi_changelog.md
|
||||
const ExternalApiVersion = "2.0.0"
|
||||
|
||||
// InternalApiVersion -- see intapi_changelog.md
|
||||
const InternalApiVersion = "2.0.0"
|
||||
|
||||
const legalWarning = `
|
||||
WARNING!
|
||||
|
||||
Clef is alpha software, and not yet publically released. This software has _not_ been audited, and there
|
||||
are no guarantees about the workings of this software. It may contain severe flaws. You should not use this software
|
||||
unless you agree to take full responsibility for doing so, and know what you are doing.
|
||||
|
||||
TLDR; THIS IS NOT PRODUCTION-READY SOFTWARE!
|
||||
|
||||
`
|
||||
|
||||
var (
|
||||
logLevelFlag = cli.IntFlag{
|
||||
Name: "loglevel",
|
||||
Value: 4,
|
||||
Usage: "log level to emit to the screen",
|
||||
}
|
||||
keystoreFlag = cli.StringFlag{
|
||||
Name: "keystore",
|
||||
Value: filepath.Join(node.DefaultDataDir(), "keystore"),
|
||||
Usage: "Directory for the keystore",
|
||||
}
|
||||
configdirFlag = cli.StringFlag{
|
||||
Name: "configdir",
|
||||
Value: DefaultConfigDir(),
|
||||
Usage: "Directory for Clef configuration",
|
||||
}
|
||||
rpcPortFlag = cli.IntFlag{
|
||||
Name: "rpcport",
|
||||
Usage: "HTTP-RPC server listening port",
|
||||
Value: node.DefaultHTTPPort + 5,
|
||||
}
|
||||
signerSecretFlag = cli.StringFlag{
|
||||
Name: "signersecret",
|
||||
Usage: "A file containing the password used to encrypt Clef credentials, e.g. keystore credentials and ruleset hash",
|
||||
}
|
||||
dBFlag = cli.StringFlag{
|
||||
Name: "4bytedb",
|
||||
Usage: "File containing 4byte-identifiers",
|
||||
Value: "./4byte.json",
|
||||
}
|
||||
customDBFlag = cli.StringFlag{
|
||||
Name: "4bytedb-custom",
|
||||
Usage: "File used for writing new 4byte-identifiers submitted via API",
|
||||
Value: "./4byte-custom.json",
|
||||
}
|
||||
auditLogFlag = cli.StringFlag{
|
||||
Name: "auditlog",
|
||||
Usage: "File used to emit audit logs. Set to \"\" to disable",
|
||||
Value: "audit.log",
|
||||
}
|
||||
ruleFlag = cli.StringFlag{
|
||||
Name: "rules",
|
||||
Usage: "Enable rule-engine",
|
||||
Value: "rules.json",
|
||||
}
|
||||
stdiouiFlag = cli.BoolFlag{
|
||||
Name: "stdio-ui",
|
||||
Usage: "Use STDIN/STDOUT as a channel for an external UI. " +
|
||||
"This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user " +
|
||||
"interface, and can be used when Clef is started by an external process.",
|
||||
}
|
||||
testFlag = cli.BoolFlag{
|
||||
Name: "stdio-ui-test",
|
||||
Usage: "Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.",
|
||||
}
|
||||
app = cli.NewApp()
|
||||
initCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(initializeSecrets),
|
||||
Name: "init",
|
||||
Usage: "Initialize the signer, generate secret storage",
|
||||
ArgsUsage: "",
|
||||
Flags: []cli.Flag{
|
||||
logLevelFlag,
|
||||
configdirFlag,
|
||||
},
|
||||
Description: `
|
||||
The init command generates a master seed which Clef can use to store credentials and data needed for
|
||||
the rule-engine to work.`,
|
||||
}
|
||||
attestCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(attestFile),
|
||||
Name: "attest",
|
||||
Usage: "Attest that a js-file is to be used",
|
||||
ArgsUsage: "<sha256sum>",
|
||||
Flags: []cli.Flag{
|
||||
logLevelFlag,
|
||||
configdirFlag,
|
||||
signerSecretFlag,
|
||||
},
|
||||
Description: `
|
||||
The attest command stores the sha256 of the rule.js-file that you want to use for automatic processing of
|
||||
incoming requests.
|
||||
|
||||
Whenever you make an edit to the rule file, you need to use attestation to tell
|
||||
Clef that the file is 'safe' to execute.`,
|
||||
}
|
||||
|
||||
addCredentialCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(addCredential),
|
||||
Name: "addpw",
|
||||
Usage: "Store a credential for a keystore file",
|
||||
ArgsUsage: "<address> <password>",
|
||||
Flags: []cli.Flag{
|
||||
logLevelFlag,
|
||||
configdirFlag,
|
||||
signerSecretFlag,
|
||||
},
|
||||
Description: `
|
||||
The addpw command stores a password for a given address (keyfile). If you invoke it with only one parameter, it will
|
||||
remove any stored credential for that address (keyfile)
|
||||
`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
app.Name = "Clef"
|
||||
app.Usage = "Manage Ethereum account operations"
|
||||
app.Flags = []cli.Flag{
|
||||
logLevelFlag,
|
||||
keystoreFlag,
|
||||
configdirFlag,
|
||||
utils.NetworkIdFlag,
|
||||
utils.LightKDFFlag,
|
||||
utils.NoUSBFlag,
|
||||
utils.RPCListenAddrFlag,
|
||||
utils.RPCVirtualHostsFlag,
|
||||
utils.IPCDisabledFlag,
|
||||
utils.IPCPathFlag,
|
||||
utils.RPCEnabledFlag,
|
||||
rpcPortFlag,
|
||||
signerSecretFlag,
|
||||
dBFlag,
|
||||
customDBFlag,
|
||||
auditLogFlag,
|
||||
ruleFlag,
|
||||
stdiouiFlag,
|
||||
testFlag,
|
||||
}
|
||||
app.Action = signer
|
||||
app.Commands = []cli.Command{initCommand, attestCommand, addCredentialCommand}
|
||||
|
||||
}
|
||||
func main() {
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func initializeSecrets(c *cli.Context) error {
|
||||
if err := initialize(c); err != nil {
|
||||
return err
|
||||
}
|
||||
configDir := c.String(configdirFlag.Name)
|
||||
|
||||
masterSeed := make([]byte, 256)
|
||||
n, err := io.ReadFull(rand.Reader, masterSeed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(masterSeed) {
|
||||
return fmt.Errorf("failed to read enough random")
|
||||
}
|
||||
err = os.Mkdir(configDir, 0700)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
location := filepath.Join(configDir, "secrets.dat")
|
||||
if _, err := os.Stat(location); err == nil {
|
||||
return fmt.Errorf("file %v already exists, will not overwrite", location)
|
||||
}
|
||||
err = ioutil.WriteFile(location, masterSeed, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("A master seed has been generated into %s\n", location)
|
||||
fmt.Printf(`
|
||||
This is required to be able to store credentials, such as :
|
||||
* Passwords for keystores (used by rule engine)
|
||||
* Storage for javascript rules
|
||||
* Hash of rule-file
|
||||
|
||||
You should treat that file with utmost secrecy, and make a backup of it.
|
||||
NOTE: This file does not contain your accounts. Those need to be backed up separately!
|
||||
|
||||
`)
|
||||
return nil
|
||||
}
|
||||
func attestFile(ctx *cli.Context) error {
|
||||
if len(ctx.Args()) < 1 {
|
||||
utils.Fatalf("This command requires an argument.")
|
||||
}
|
||||
if err := initialize(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stretchedKey, err := readMasterKey(ctx)
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
configDir := ctx.String(configdirFlag.Name)
|
||||
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
||||
confKey := crypto.Keccak256([]byte("config"), stretchedKey)
|
||||
|
||||
// Initialize the encrypted storages
|
||||
configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confKey)
|
||||
val := ctx.Args().First()
|
||||
configStorage.Put("ruleset_sha256", val)
|
||||
log.Info("Ruleset attestation updated", "sha256", val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func addCredential(ctx *cli.Context) error {
|
||||
if len(ctx.Args()) < 1 {
|
||||
utils.Fatalf("This command requires at leaste one argument.")
|
||||
}
|
||||
if err := initialize(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stretchedKey, err := readMasterKey(ctx)
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
configDir := ctx.String(configdirFlag.Name)
|
||||
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
||||
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
|
||||
|
||||
// Initialize the encrypted storages
|
||||
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
|
||||
key := ctx.Args().First()
|
||||
value := ""
|
||||
if len(ctx.Args()) > 1 {
|
||||
value = ctx.Args().Get(1)
|
||||
}
|
||||
pwStorage.Put(key, value)
|
||||
log.Info("Credential store updated", "key", key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func initialize(c *cli.Context) error {
|
||||
// Set up the logger to print everything
|
||||
logOutput := os.Stdout
|
||||
if c.Bool(stdiouiFlag.Name) {
|
||||
logOutput = os.Stderr
|
||||
// If using the stdioui, we can't do the 'confirm'-flow
|
||||
fmt.Fprintf(logOutput, legalWarning)
|
||||
} else {
|
||||
if !confirm(legalWarning) {
|
||||
return fmt.Errorf("aborted by user")
|
||||
}
|
||||
}
|
||||
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(logOutput, log.TerminalFormat(true))))
|
||||
return nil
|
||||
}
|
||||
|
||||
func signer(c *cli.Context) error {
|
||||
if err := initialize(c); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
ui core.SignerUI
|
||||
)
|
||||
if c.Bool(stdiouiFlag.Name) {
|
||||
log.Info("Using stdin/stdout as UI-channel")
|
||||
ui = core.NewStdIOUI()
|
||||
} else {
|
||||
log.Info("Using CLI as UI-channel")
|
||||
ui = core.NewCommandlineUI()
|
||||
}
|
||||
db, err := core.NewAbiDBFromFiles(c.String(dBFlag.Name), c.String(customDBFlag.Name))
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
log.Info("Loaded 4byte db", "signatures", db.Size(), "file", c.String("4bytedb"))
|
||||
|
||||
var (
|
||||
api core.ExternalAPI
|
||||
)
|
||||
|
||||
configDir := c.String(configdirFlag.Name)
|
||||
if stretchedKey, err := readMasterKey(c); err != nil {
|
||||
log.Info("No master seed provided, rules disabled")
|
||||
} else {
|
||||
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
||||
|
||||
// Generate domain specific keys
|
||||
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
|
||||
jskey := crypto.Keccak256([]byte("jsstorage"), stretchedKey)
|
||||
confkey := crypto.Keccak256([]byte("config"), stretchedKey)
|
||||
|
||||
// Initialize the encrypted storages
|
||||
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
|
||||
jsStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "jsstorage.json"), jskey)
|
||||
configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confkey)
|
||||
|
||||
//Do we have a rule-file?
|
||||
ruleJS, err := ioutil.ReadFile(c.String(ruleFlag.Name))
|
||||
if err != nil {
|
||||
log.Info("Could not load rulefile, rules not enabled", "file", "rulefile")
|
||||
} else {
|
||||
hasher := sha256.New()
|
||||
hasher.Write(ruleJS)
|
||||
shasum := hasher.Sum(nil)
|
||||
storedShasum := configStorage.Get("ruleset_sha256")
|
||||
if storedShasum != hex.EncodeToString(shasum) {
|
||||
log.Info("Could not validate ruleset hash, rules not enabled", "got", hex.EncodeToString(shasum), "expected", storedShasum)
|
||||
} else {
|
||||
// Initialize rules
|
||||
ruleEngine, err := rules.NewRuleEvaluator(ui, jsStorage, pwStorage)
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
ruleEngine.Init(string(ruleJS))
|
||||
ui = ruleEngine
|
||||
log.Info("Rule engine configured", "file", c.String(ruleFlag.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apiImpl := core.NewSignerAPI(
|
||||
c.Int64(utils.NetworkIdFlag.Name),
|
||||
c.String(keystoreFlag.Name),
|
||||
c.Bool(utils.NoUSBFlag.Name),
|
||||
ui, db,
|
||||
c.Bool(utils.LightKDFFlag.Name))
|
||||
|
||||
api = apiImpl
|
||||
|
||||
// Audit logging
|
||||
if logfile := c.String(auditLogFlag.Name); logfile != "" {
|
||||
api, err = core.NewAuditLogger(logfile, api)
|
||||
if err != nil {
|
||||
utils.Fatalf(err.Error())
|
||||
}
|
||||
log.Info("Audit logs configured", "file", logfile)
|
||||
}
|
||||
// register signer API with server
|
||||
var (
|
||||
extapiUrl = "n/a"
|
||||
ipcApiUrl = "n/a"
|
||||
)
|
||||
rpcApi := []rpc.API{
|
||||
{
|
||||
Namespace: "account",
|
||||
Public: true,
|
||||
Service: api,
|
||||
Version: "1.0"},
|
||||
}
|
||||
if c.Bool(utils.RPCEnabledFlag.Name) {
|
||||
|
||||
vhosts := splitAndTrim(c.GlobalString(utils.RPCVirtualHostsFlag.Name))
|
||||
cors := splitAndTrim(c.GlobalString(utils.RPCCORSDomainFlag.Name))
|
||||
|
||||
// start http server
|
||||
httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.RPCListenAddrFlag.Name), c.Int(rpcPortFlag.Name))
|
||||
listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcApi, []string{"account"}, cors, vhosts)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not start RPC api: %v", err)
|
||||
}
|
||||
extapiUrl = fmt.Sprintf("http://%s", httpEndpoint)
|
||||
log.Info("HTTP endpoint opened", "url", extapiUrl)
|
||||
|
||||
defer func() {
|
||||
listener.Close()
|
||||
log.Info("HTTP endpoint closed", "url", httpEndpoint)
|
||||
}()
|
||||
|
||||
}
|
||||
if !c.Bool(utils.IPCDisabledFlag.Name) {
|
||||
if c.IsSet(utils.IPCPathFlag.Name) {
|
||||
ipcApiUrl = c.String(utils.IPCPathFlag.Name)
|
||||
} else {
|
||||
ipcApiUrl = filepath.Join(configDir, "clef.ipc")
|
||||
}
|
||||
|
||||
listener, _, err := rpc.StartIPCEndpoint(ipcApiUrl, rpcApi)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not start IPC api: %v", err)
|
||||
}
|
||||
log.Info("IPC endpoint opened", "url", ipcApiUrl)
|
||||
defer func() {
|
||||
listener.Close()
|
||||
log.Info("IPC endpoint closed", "url", ipcApiUrl)
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
if c.Bool(testFlag.Name) {
|
||||
log.Info("Performing UI test")
|
||||
go testExternalUI(apiImpl)
|
||||
}
|
||||
ui.OnSignerStartup(core.StartupInfo{
|
||||
Info: map[string]interface{}{
|
||||
"extapi_version": ExternalApiVersion,
|
||||
"intapi_version": InternalApiVersion,
|
||||
"extapi_http": extapiUrl,
|
||||
"extapi_ipc": ipcApiUrl,
|
||||
},
|
||||
})
|
||||
|
||||
abortChan := make(chan os.Signal)
|
||||
signal.Notify(abortChan, os.Interrupt)
|
||||
|
||||
sig := <-abortChan
|
||||
log.Info("Exiting...", "signal", sig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// splitAndTrim splits input separated by a comma
|
||||
// and trims excessive white space from the substrings.
|
||||
func splitAndTrim(input string) []string {
|
||||
result := strings.Split(input, ",")
|
||||
for i, r := range result {
|
||||
result[i] = strings.TrimSpace(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DefaultConfigDir is the default config directory to use for the vaults and other
|
||||
// persistence requirements.
|
||||
func DefaultConfigDir() string {
|
||||
// Try to place the data folder in the user's home dir
|
||||
home := homeDir()
|
||||
if home != "" {
|
||||
if runtime.GOOS == "darwin" {
|
||||
return filepath.Join(home, "Library", "Signer")
|
||||
} else if runtime.GOOS == "windows" {
|
||||
return filepath.Join(home, "AppData", "Roaming", "Signer")
|
||||
} else {
|
||||
return filepath.Join(home, ".clef")
|
||||
}
|
||||
}
|
||||
// As we cannot guess a stable location, return empty and handle later
|
||||
return ""
|
||||
}
|
||||
|
||||
func homeDir() string {
|
||||
if home := os.Getenv("HOME"); home != "" {
|
||||
return home
|
||||
}
|
||||
if usr, err := user.Current(); err == nil {
|
||||
return usr.HomeDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func readMasterKey(ctx *cli.Context) ([]byte, error) {
|
||||
var (
|
||||
file string
|
||||
configDir = ctx.String(configdirFlag.Name)
|
||||
)
|
||||
if ctx.IsSet(signerSecretFlag.Name) {
|
||||
file = ctx.String(signerSecretFlag.Name)
|
||||
} else {
|
||||
file = filepath.Join(configDir, "secrets.dat")
|
||||
}
|
||||
if err := checkFile(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
masterKey, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(masterKey) < 256 {
|
||||
return nil, fmt.Errorf("master key of insufficient length, expected >255 bytes, got %d", len(masterKey))
|
||||
}
|
||||
// Create vault location
|
||||
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), masterKey)[:10]))
|
||||
err = os.Mkdir(vaultLocation, 0700)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
//!TODO, use KDF to stretch the master key
|
||||
// stretched_key := stretch_key(master_key)
|
||||
|
||||
return masterKey, nil
|
||||
}
|
||||
|
||||
// checkFile is a convenience function to check if a file
|
||||
// * exists
|
||||
// * is mode 0600
|
||||
func checkFile(filename string) error {
|
||||
info, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed stat on %s: %v", filename, err)
|
||||
}
|
||||
// Check the unix permission bits
|
||||
if info.Mode().Perm()&077 != 0 {
|
||||
return fmt.Errorf("file (%v) has insecure file permissions (%v)", filename, info.Mode().String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// confirm displays a text and asks for user confirmation
|
||||
func confirm(text string) bool {
|
||||
fmt.Printf(text)
|
||||
fmt.Printf("\nEnter 'ok' to proceed:\n>")
|
||||
|
||||
text, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
if err != nil {
|
||||
log.Crit("Failed to read user input", "err", err)
|
||||
}
|
||||
|
||||
if text := strings.TrimSpace(text); text == "ok" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func testExternalUI(api *core.SignerAPI) {
|
||||
|
||||
ctx := context.WithValue(context.Background(), "remote", "clef binary")
|
||||
ctx = context.WithValue(ctx, "scheme", "in-proc")
|
||||
ctx = context.WithValue(ctx, "local", "main")
|
||||
|
||||
errs := make([]string, 0)
|
||||
|
||||
api.UI.ShowInfo("Testing 'ShowInfo'")
|
||||
api.UI.ShowError("Testing 'ShowError'")
|
||||
|
||||
checkErr := func(method string, err error) {
|
||||
if err != nil && err != core.ErrRequestDenied {
|
||||
errs = append(errs, fmt.Sprintf("%v: %v", method, err.Error()))
|
||||
}
|
||||
}
|
||||
var err error
|
||||
|
||||
_, err = api.SignTransaction(ctx, core.SendTxArgs{From: common.MixedcaseAddress{}}, nil)
|
||||
checkErr("SignTransaction", err)
|
||||
_, err = api.Sign(ctx, common.MixedcaseAddress{}, common.Hex2Bytes("01020304"))
|
||||
checkErr("Sign", err)
|
||||
_, err = api.List(ctx)
|
||||
checkErr("List", err)
|
||||
_, err = api.New(ctx)
|
||||
checkErr("New", err)
|
||||
_, err = api.Export(ctx, common.Address{})
|
||||
checkErr("Export", err)
|
||||
_, err = api.Import(ctx, json.RawMessage{})
|
||||
checkErr("Import", err)
|
||||
|
||||
api.UI.ShowInfo("Tests completed")
|
||||
|
||||
if len(errs) > 0 {
|
||||
log.Error("Got errors")
|
||||
for _, e := range errs {
|
||||
log.Error(e)
|
||||
}
|
||||
} else {
|
||||
log.Info("No errors")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
//Create Account
|
||||
|
||||
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_new","params":["test"],"id":67}' localhost:8550
|
||||
|
||||
// List accounts
|
||||
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_list","params":[""],"id":67}' http://localhost:8550/
|
||||
|
||||
// Make Transaction
|
||||
// safeSend(0x12)
|
||||
// 4401a6e40000000000000000000000000000000000000000000000000000000000000012
|
||||
|
||||
// supplied abi
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x82A2A876D39022B3019932D30Cd9c97ad5616813","gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"test"],"id":67}' http://localhost:8550/
|
||||
|
||||
// Not supplied
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x82A2A876D39022B3019932D30Cd9c97ad5616813","gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"}],"id":67}' http://localhost:8550/
|
||||
|
||||
// Sign data
|
||||
|
||||
curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_sign","params":["0x694267f14675d7e1b9494fd8d72fefe1755710fa","bazonk gaz baz"],"id":67}' http://localhost:8550/
|
||||
|
||||
|
||||
**/
|
179
vendor/github.com/ethereum/go-ethereum/cmd/clef/pythonsigner.py
generated
vendored
Normal file
179
vendor/github.com/ethereum/go-ethereum/cmd/clef/pythonsigner.py
generated
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
import os,sys, subprocess
|
||||
from tinyrpc.transports import ServerTransport
|
||||
from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
|
||||
from tinyrpc.dispatch import public,RPCDispatcher
|
||||
from tinyrpc.server import RPCServer
|
||||
|
||||
""" This is a POC example of how to write a custom UI for Clef. The UI starts the
|
||||
clef process with the '--stdio-ui' option, and communicates with clef using standard input / output.
|
||||
|
||||
The standard input/output is a relatively secure way to communicate, as it does not require opening any ports
|
||||
or IPC files. Needless to say, it does not protect against memory inspection mechanisms where an attacker
|
||||
can access process memory."""
|
||||
|
||||
try:
|
||||
import urllib.parse as urlparse
|
||||
except ImportError:
|
||||
import urllib as urlparse
|
||||
|
||||
class StdIOTransport(ServerTransport):
|
||||
""" Uses std input/output for RPC """
|
||||
def receive_message(self):
|
||||
return None, urlparse.unquote(sys.stdin.readline())
|
||||
|
||||
def send_reply(self, context, reply):
|
||||
print(reply)
|
||||
|
||||
class PipeTransport(ServerTransport):
|
||||
""" Uses std a pipe for RPC """
|
||||
|
||||
def __init__(self,input, output):
|
||||
self.input = input
|
||||
self.output = output
|
||||
|
||||
def receive_message(self):
|
||||
data = self.input.readline()
|
||||
print(">> {}".format( data))
|
||||
return None, urlparse.unquote(data)
|
||||
|
||||
def send_reply(self, context, reply):
|
||||
print("<< {}".format( reply))
|
||||
self.output.write(reply)
|
||||
self.output.write("\n")
|
||||
|
||||
class StdIOHandler():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@public
|
||||
def ApproveTx(self,req):
|
||||
"""
|
||||
Example request:
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "ApproveTx",
|
||||
"params": [{
|
||||
"transaction": {
|
||||
"to": "0xae967917c465db8578ca9024c205720b1a3651A9",
|
||||
"gas": "0x333",
|
||||
"gasPrice": "0x123",
|
||||
"value": "0x10",
|
||||
"data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff",
|
||||
"nonce": "0x0"
|
||||
},
|
||||
"from": "0xAe967917c465db8578ca9024c205720b1a3651A9",
|
||||
"call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658",
|
||||
"meta": {
|
||||
"remote": "127.0.0.1:34572",
|
||||
"local": "localhost:8550",
|
||||
"scheme": "HTTP/1.1"
|
||||
}
|
||||
}],
|
||||
"id": 1
|
||||
}
|
||||
|
||||
:param transaction: transaction info
|
||||
:param call_info: info abou the call, e.g. if ABI info could not be
|
||||
:param meta: metadata about the request, e.g. where the call comes from
|
||||
:return:
|
||||
"""
|
||||
transaction = req.get('transaction')
|
||||
_from = req.get('from')
|
||||
call_info = req.get('call_info')
|
||||
meta = req.get('meta')
|
||||
|
||||
return {
|
||||
"approved" : False,
|
||||
#"transaction" : transaction,
|
||||
# "from" : _from,
|
||||
# "password" : None,
|
||||
}
|
||||
|
||||
@public
|
||||
def ApproveSignData(self, req):
|
||||
""" Example request
|
||||
|
||||
"""
|
||||
return {"approved": False, "password" : None}
|
||||
|
||||
@public
|
||||
def ApproveExport(self, req):
|
||||
""" Example request
|
||||
|
||||
"""
|
||||
return {"approved" : False}
|
||||
|
||||
@public
|
||||
def ApproveImport(self, req):
|
||||
""" Example request
|
||||
|
||||
"""
|
||||
return { "approved" : False, "old_password": "", "new_password": ""}
|
||||
|
||||
@public
|
||||
def ApproveListing(self, req):
|
||||
""" Example request
|
||||
|
||||
"""
|
||||
return {'accounts': []}
|
||||
|
||||
@public
|
||||
def ApproveNewAccount(self, req):
|
||||
"""
|
||||
Example request
|
||||
|
||||
:return:
|
||||
"""
|
||||
return {"approved": False,
|
||||
#"password": ""
|
||||
}
|
||||
|
||||
@public
|
||||
def ShowError(self,message = {}):
|
||||
"""
|
||||
Example request:
|
||||
|
||||
{"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowError'"},"id":1}
|
||||
|
||||
:param message: to show
|
||||
:return: nothing
|
||||
"""
|
||||
if 'text' in message.keys():
|
||||
sys.stderr.write("Error: {}\n".format( message['text']))
|
||||
return
|
||||
|
||||
@public
|
||||
def ShowInfo(self,message = {}):
|
||||
"""
|
||||
Example request
|
||||
{"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowInfo'"},"id":0}
|
||||
|
||||
:param message: to display
|
||||
:return:nothing
|
||||
"""
|
||||
|
||||
if 'text' in message.keys():
|
||||
sys.stdout.write("Error: {}\n".format( message['text']))
|
||||
return
|
||||
|
||||
def main(args):
|
||||
|
||||
cmd = ["./clef", "--stdio-ui"]
|
||||
if len(args) > 0 and args[0] == "test":
|
||||
cmd.extend(["--stdio-ui-test"])
|
||||
print("cmd: {}".format(" ".join(cmd)))
|
||||
dispatcher = RPCDispatcher()
|
||||
dispatcher.register_instance(StdIOHandler(), '')
|
||||
# line buffered
|
||||
p = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
|
||||
rpc_server = RPCServer(
|
||||
PipeTransport(p.stdout, p.stdin),
|
||||
JSONRPCProtocol(),
|
||||
dispatcher
|
||||
)
|
||||
rpc_server.serve_forever()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
236
vendor/github.com/ethereum/go-ethereum/cmd/clef/rules.md
generated
vendored
Normal file
236
vendor/github.com/ethereum/go-ethereum/cmd/clef/rules.md
generated
vendored
Normal file
|
@ -0,0 +1,236 @@
|
|||
# Rules
|
||||
|
||||
The `signer` binary contains a ruleset engine, implemented with [OttoVM](https://github.com/robertkrimen/otto)
|
||||
|
||||
It enables usecases like the following:
|
||||
|
||||
* I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period
|
||||
* I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei`
|
||||
|
||||
The two main features that are required for this to work well are;
|
||||
|
||||
1. Rule Implementation: how to create, manage and interpret rules in a flexible but secure manner
|
||||
2. Credential managements and credentials; how to provide auto-unlock without exposing keys unnecessarily.
|
||||
|
||||
The section below deals with both of them
|
||||
|
||||
## Rule Implementation
|
||||
|
||||
A ruleset file is implemented as a `js` file. Under the hood, the ruleset-engine is a `SignerUI`, implementing the same methods as the `json-rpc` methods
|
||||
defined in the UI protocol. Example:
|
||||
|
||||
```javascript
|
||||
|
||||
function asBig(str){
|
||||
if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)}
|
||||
return new BigNumber(str)
|
||||
}
|
||||
|
||||
// Approve transactions to a certain contract if value is below a certain limit
|
||||
function ApproveTx(req){
|
||||
|
||||
var limit = big.Newint("0xb1a2bc2ec50000")
|
||||
var value = asBig(req.transaction.value);
|
||||
|
||||
if(req.transaction.to.toLowerCase()=="0xae967917c465db8578ca9024c205720b1a3651a9")
|
||||
&& value.lt(limit) ){
|
||||
return "Approve"
|
||||
}
|
||||
// If we return "Reject", it will be rejected.
|
||||
// By not returning anything, it will be passed to the next UI, for manual processing
|
||||
}
|
||||
|
||||
//Approve listings if request made from IPC
|
||||
function ApproveListing(req){
|
||||
if (req.metadata.scheme == "ipc"){ return "Approve"}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Whenever the external API is called (and the ruleset is enabled), the `signer` calls the UI, which is an instance of a ruleset-engine. The ruleset-engine
|
||||
invokes the corresponding method. In doing so, there are three possible outcomes:
|
||||
|
||||
1. JS returns "Approve"
|
||||
* Auto-approve request
|
||||
2. JS returns "Reject"
|
||||
* Auto-reject request
|
||||
3. Error occurs, or something else is returned
|
||||
* Pass on to `next` ui: the regular UI channel.
|
||||
|
||||
A more advanced example can be found below, "Example 1: ruleset for a rate-limited window", using `storage` to `Put` and `Get` `string`s by key.
|
||||
|
||||
* At the time of writing, storage only exists as an ephemeral unencrypted implementation, to be used during testing.
|
||||
|
||||
### Things to note
|
||||
|
||||
The Otto vm has a few [caveats](https://github.com/robertkrimen/otto):
|
||||
|
||||
* "use strict" will parse, but does nothing.
|
||||
* The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification.
|
||||
* Otto targets ES5. ES6 features (eg: Typed Arrays) are not supported.
|
||||
|
||||
Additionally, a few more have been added
|
||||
|
||||
* The rule execution cannot load external javascript files.
|
||||
* The only preloaded libary is [`bignumber.js`](https://github.com/MikeMcl/bignumber.js) version `2.0.3`. This one is fairly old, and is not aligned with the documentation at the github repository.
|
||||
* Each invocation is made in a fresh virtual machine. This means that you cannot store data in global variables between invocations. This is a deliberate choice -- if you want to store data, use the disk-backed `storage`, since rules should not rely on ephemeral data.
|
||||
* Javascript API parameters are _always_ an object. This is also a design choice, to ensure that parameters are accessed by _key_ and not by order. This is to prevent mistakes due to missing parameters or parameter changes.
|
||||
* The JS engine has access to `storage` and `console`.
|
||||
|
||||
#### Security considerations
|
||||
|
||||
##### Security of ruleset
|
||||
|
||||
Some security precautions can be made, such as:
|
||||
|
||||
* Never load `ruleset.js` unless the file is `readonly` (`r-??-??-?`). If the user wishes to modify the ruleset, he must make it writeable and then set back to readonly.
|
||||
* This is to prevent attacks where files are dropped on the users disk.
|
||||
* Since we're going to have to have some form of secure storage (not defined in this section), we could also store the `sha3` of the `ruleset.js` file in there.
|
||||
* If the user wishes to modify the ruleset, he'd then have to perform e.g. `signer --attest /path/to/ruleset --credential <creds>`
|
||||
|
||||
##### Security of implementation
|
||||
|
||||
The drawbacks of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement, since it's already
|
||||
implemented for `geth`. There are no known security vulnerabilities in, nor have we had any security-problems with it so far.
|
||||
|
||||
The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered
|
||||
an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit
|
||||
to be gained from attacking the actual `signer` process from the `js` side would be if it could somehow extract cryptographic keys from memory.
|
||||
|
||||
##### Security in usability
|
||||
|
||||
Javascript is flexible, but also easy to get wrong, especially when users assume that `js` can handle large integers natively. Typical errors
|
||||
include trying to multiply `gasCost` with `gas` without using `bigint`:s.
|
||||
|
||||
It's unclear whether any other DSL could be more secure; since there's always the possibility of erroneously implementing a rule.
|
||||
|
||||
|
||||
## Credential management
|
||||
|
||||
The ability to auto-approve transaction means that the signer needs to have necessary credentials to decrypt keyfiles. These passwords are hereafter called `ksp` (keystore pass).
|
||||
|
||||
### Example implementation
|
||||
|
||||
Upon startup of the signer, the signer is given a switch: `--seed <path/to/masterseed>`
|
||||
The `seed` contains a blob of bytes, which is the master seed for the `signer`.
|
||||
|
||||
The `signer` uses the `seed` to:
|
||||
|
||||
* Generate the `path` where the settings are stored.
|
||||
* `./settings/1df094eb-c2b1-4689-90dd-790046d38025/vault.dat`
|
||||
* `./settings/1df094eb-c2b1-4689-90dd-790046d38025/rules.js`
|
||||
* Generate the encryption password for `vault.dat`.
|
||||
|
||||
The `vault.dat` would be an encrypted container storing the following information:
|
||||
|
||||
* `ksp` entries
|
||||
* `sha256` hash of `rules.js`
|
||||
* Information about pair:ed callers (not yet specified)
|
||||
|
||||
### Security considerations
|
||||
|
||||
This would leave it up to the user to ensure that the `path/to/masterseed` is handled in a secure way. It's difficult to get around this, although one could
|
||||
imagine leveraging OS-level keychains where supported. The setup is however in general similar to how ssh-keys are stored in `.ssh/`.
|
||||
|
||||
|
||||
# Implementation status
|
||||
|
||||
This is now implemented (with ephemeral non-encrypted storage for now, so not yet enabled).
|
||||
|
||||
## Example 1: ruleset for a rate-limited window
|
||||
|
||||
|
||||
```javascript
|
||||
|
||||
function big(str){
|
||||
if(str.slice(0,2) == "0x"){ return new BigNumber(str.slice(2),16)}
|
||||
return new BigNumber(str)
|
||||
}
|
||||
|
||||
// Time window: 1 week
|
||||
var window = 1000* 3600*24*7;
|
||||
|
||||
// Limit : 1 ether
|
||||
var limit = new BigNumber("1e18");
|
||||
|
||||
function isLimitOk(transaction){
|
||||
var value = big(transaction.value)
|
||||
// Start of our window function
|
||||
var windowstart = new Date().getTime() - window;
|
||||
|
||||
var txs = [];
|
||||
var stored = storage.Get('txs');
|
||||
|
||||
if(stored != ""){
|
||||
txs = JSON.parse(stored)
|
||||
}
|
||||
// First, remove all that have passed out of the time-window
|
||||
var newtxs = txs.filter(function(tx){return tx.tstamp > windowstart});
|
||||
console.log(txs, newtxs.length);
|
||||
|
||||
// Secondly, aggregate the current sum
|
||||
sum = new BigNumber(0)
|
||||
|
||||
sum = newtxs.reduce(function(agg, tx){ return big(tx.value).plus(agg)}, sum);
|
||||
console.log("ApproveTx > Sum so far", sum);
|
||||
console.log("ApproveTx > Requested", value.toNumber());
|
||||
|
||||
// Would we exceed weekly limit ?
|
||||
return sum.plus(value).lt(limit)
|
||||
|
||||
}
|
||||
function ApproveTx(r){
|
||||
if (isLimitOk(r.transaction)){
|
||||
return "Approve"
|
||||
}
|
||||
return "Nope"
|
||||
}
|
||||
|
||||
/**
|
||||
* OnApprovedTx(str) is called when a transaction has been approved and signed. The parameter
|
||||
* 'response_str' contains the return value that will be sent to the external caller.
|
||||
* The return value from this method is ignore - the reason for having this callback is to allow the
|
||||
* ruleset to keep track of approved transactions.
|
||||
*
|
||||
* When implementing rate-limited rules, this callback should be used.
|
||||
* If a rule responds with neither 'Approve' nor 'Reject' - the tx goes to manual processing. If the user
|
||||
* then accepts the transaction, this method will be called.
|
||||
*
|
||||
* TLDR; Use this method to keep track of signed transactions, instead of using the data in ApproveTx.
|
||||
*/
|
||||
function OnApprovedTx(resp){
|
||||
var value = big(resp.tx.value)
|
||||
var txs = []
|
||||
// Load stored transactions
|
||||
var stored = storage.Get('txs');
|
||||
if(stored != ""){
|
||||
txs = JSON.parse(stored)
|
||||
}
|
||||
// Add this to the storage
|
||||
txs.push({tstamp: new Date().getTime(), value: value});
|
||||
storage.Put("txs", JSON.stringify(txs));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Example 2: allow destination
|
||||
|
||||
```javascript
|
||||
|
||||
function ApproveTx(r){
|
||||
if(r.transaction.from.toLowerCase()=="0x0000000000000000000000000000000000001337"){ return "Approve"}
|
||||
if(r.transaction.from.toLowerCase()=="0x000000000000000000000000000000000000dead"){ return "Reject"}
|
||||
// Otherwise goes to manual processing
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Example 3: Allow listing
|
||||
|
||||
```javascript
|
||||
|
||||
function ApproveListing(){
|
||||
return "Approve"
|
||||
}
|
||||
|
||||
```
|
BIN
vendor/github.com/ethereum/go-ethereum/cmd/clef/sign_flow.png
generated
vendored
Normal file
BIN
vendor/github.com/ethereum/go-ethereum/cmd/clef/sign_flow.png
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
198
vendor/github.com/ethereum/go-ethereum/cmd/clef/tutorial.md
generated
vendored
Normal file
198
vendor/github.com/ethereum/go-ethereum/cmd/clef/tutorial.md
generated
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
## Initializing the signer
|
||||
|
||||
First, initialize the master seed.
|
||||
|
||||
```text
|
||||
#./signer init
|
||||
|
||||
WARNING!
|
||||
|
||||
The signer is alpha software, and not yet publically released. This software has _not_ been audited, and there
|
||||
are no guarantees about the workings of this software. It may contain severe flaws. You should not use this software
|
||||
unless you agree to take full responsibility for doing so, and know what you are doing.
|
||||
|
||||
TLDR; THIS IS NOT PRODUCTION-READY SOFTWARE!
|
||||
|
||||
|
||||
Enter 'ok' to proceed:
|
||||
>ok
|
||||
A master seed has been generated into /home/martin/.signer/secrets.dat
|
||||
|
||||
This is required to be able to store credentials, such as :
|
||||
* Passwords for keystores (used by rule engine)
|
||||
* Storage for javascript rules
|
||||
* Hash of rule-file
|
||||
|
||||
You should treat that file with utmost secrecy, and make a backup of it.
|
||||
NOTE: This file does not contain your accounts. Those need to be backed up separately!
|
||||
```
|
||||
|
||||
(for readability purposes, we'll remove the WARNING printout in the rest of this document)
|
||||
|
||||
## Creating rules
|
||||
|
||||
Now, you can create a rule-file.
|
||||
|
||||
```javascript
|
||||
function ApproveListing(){
|
||||
return "Approve"
|
||||
}
|
||||
```
|
||||
Get the `sha256` hash....
|
||||
```text
|
||||
#sha256sum rules.js
|
||||
6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72 rules.js
|
||||
```
|
||||
...And then `attest` the file:
|
||||
```text
|
||||
#./signer attest 6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72
|
||||
|
||||
INFO [02-21|12:14:38] Ruleset attestation updated sha256=6c21d1737429d6d4f2e55146da0797782f3c0a0355227f19d702df377c165d72
|
||||
```
|
||||
At this point, we then start the signer with the rule-file:
|
||||
|
||||
```text
|
||||
#./signer --rules rules.json
|
||||
|
||||
INFO [02-21|12:15:18] Using CLI as UI-channel
|
||||
INFO [02-21|12:15:18] Loaded 4byte db signatures=5509 file=./4byte.json
|
||||
INFO [02-21|12:15:18] Could not load rulefile, rules not enabled file=rulefile
|
||||
DEBUG[02-21|12:15:18] FS scan times list=35.335µs set=5.536µs diff=5.073µs
|
||||
DEBUG[02-21|12:15:18] Ledger support enabled
|
||||
DEBUG[02-21|12:15:18] Trezor support enabled
|
||||
INFO [02-21|12:15:18] Audit logs configured file=audit.log
|
||||
INFO [02-21|12:15:18] HTTP endpoint opened url=http://localhost:8550
|
||||
------- Signer info -------
|
||||
* extapi_http : http://localhost:8550
|
||||
* extapi_ipc : <nil>
|
||||
* extapi_version : 2.0.0
|
||||
* intapi_version : 1.2.0
|
||||
|
||||
```
|
||||
|
||||
Any list-requests will now be auto-approved by our rule-file.
|
||||
|
||||
## Under the hood
|
||||
|
||||
While doing the operations above, these files have been created:
|
||||
|
||||
```text
|
||||
#ls -laR ~/.signer/
|
||||
/home/martin/.signer/:
|
||||
total 16
|
||||
drwx------ 3 martin martin 4096 feb 21 12:14 .
|
||||
drwxr-xr-x 71 martin martin 4096 feb 21 12:12 ..
|
||||
drwx------ 2 martin martin 4096 feb 21 12:14 43f73718397aa54d1b22
|
||||
-rwx------ 1 martin martin 256 feb 21 12:12 secrets.dat
|
||||
|
||||
/home/martin/.signer/43f73718397aa54d1b22:
|
||||
total 12
|
||||
drwx------ 2 martin martin 4096 feb 21 12:14 .
|
||||
drwx------ 3 martin martin 4096 feb 21 12:14 ..
|
||||
-rw------- 1 martin martin 159 feb 21 12:14 config.json
|
||||
|
||||
#cat /home/martin/.signer/43f73718397aa54d1b22/config.json
|
||||
{"ruleset_sha256":{"iv":"6v4W4tfJxj3zZFbl","c":"6dt5RTDiTq93yh1qDEjpsat/tsKG7cb+vr3sza26IPL2fvsQ6ZoqFx++CPUa8yy6fD9Bbq41L01ehkKHTG3pOAeqTW6zc/+t0wv3AB6xPmU="}}
|
||||
|
||||
```
|
||||
|
||||
In `~/.signer`, the `secrets.dat` file was created, containing the `master_seed`.
|
||||
The `master_seed` was then used to derive a few other things:
|
||||
|
||||
- `vault_location` : in this case `43f73718397aa54d1b22` .
|
||||
- Thus, if you use a different `master_seed`, another `vault_location` will be used that does not conflict with each other.
|
||||
- Example: `signer --signersecret /path/to/afile ...`
|
||||
- `config.json` which is the encrypted key/value storage for configuration data, containing the key `ruleset_sha256`.
|
||||
|
||||
|
||||
## Adding credentials
|
||||
|
||||
In order to make more useful rules; sign transactions, the signer needs access to the passwords needed to unlock keystores.
|
||||
|
||||
```text
|
||||
#./signer addpw 0x694267f14675d7e1b9494fd8d72fefe1755710fa test
|
||||
|
||||
INFO [02-21|13:43:21] Credential store updated key=0x694267f14675d7e1b9494fd8d72fefe1755710fa
|
||||
```
|
||||
## More advanced rules
|
||||
|
||||
Now let's update the rules to make use of credentials
|
||||
|
||||
```javascript
|
||||
function ApproveListing(){
|
||||
return "Approve"
|
||||
}
|
||||
function ApproveSignData(r){
|
||||
if( r.address.toLowerCase() == "0x694267f14675d7e1b9494fd8d72fefe1755710fa")
|
||||
{
|
||||
if(r.message.indexOf("bazonk") >= 0){
|
||||
return "Approve"
|
||||
}
|
||||
return "Reject"
|
||||
}
|
||||
// Otherwise goes to manual processing
|
||||
}
|
||||
|
||||
```
|
||||
In this example,
|
||||
* any requests to sign data with the account `0x694...` will be
|
||||
* auto-approved if the message contains with `bazonk`,
|
||||
* and auto-rejected if it does not.
|
||||
* Any other signing-requests will be passed along for manual approve/reject.
|
||||
|
||||
..attest the new file
|
||||
```text
|
||||
#sha256sum rules.js
|
||||
2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f rules.js
|
||||
|
||||
#./signer attest 2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f
|
||||
|
||||
INFO [02-21|14:36:30] Ruleset attestation updated sha256=2a0cb661dacfc804b6e95d935d813fd17c0997a7170e4092ffbc34ca976acd9f
|
||||
```
|
||||
|
||||
And start the signer:
|
||||
|
||||
```
|
||||
#./signer --rules rules.js
|
||||
|
||||
INFO [02-21|14:41:56] Using CLI as UI-channel
|
||||
INFO [02-21|14:41:56] Loaded 4byte db signatures=5509 file=./4byte.json
|
||||
INFO [02-21|14:41:56] Rule engine configured file=rules.js
|
||||
DEBUG[02-21|14:41:56] FS scan times list=34.607µs set=4.509µs diff=4.87µs
|
||||
DEBUG[02-21|14:41:56] Ledger support enabled
|
||||
DEBUG[02-21|14:41:56] Trezor support enabled
|
||||
INFO [02-21|14:41:56] Audit logs configured file=audit.log
|
||||
INFO [02-21|14:41:56] HTTP endpoint opened url=http://localhost:8550
|
||||
------- Signer info -------
|
||||
* extapi_version : 2.0.0
|
||||
* intapi_version : 1.2.0
|
||||
* extapi_http : http://localhost:8550
|
||||
* extapi_ipc : <nil>
|
||||
INFO [02-21|14:41:56] error occurred during execution error="ReferenceError: 'OnSignerStartup' is not defined"
|
||||
```
|
||||
And then test signing, once with `bazonk` and once without:
|
||||
|
||||
```
|
||||
#curl -H "Content-Type: application/json" -X POST --data "{\"jsonrpc\":\"2.0\",\"method\":\"account_sign\",\"params\":[\"0x694267f14675d7e1b9494fd8d72fefe1755710fa\",\"0x$(xxd -pu <<< ' bazonk baz gaz')\"],\"id\":67}" http://localhost:8550/
|
||||
{"jsonrpc":"2.0","id":67,"result":"0x93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c"}
|
||||
|
||||
#curl -H "Content-Type: application/json" -X POST --data "{\"jsonrpc\":\"2.0\",\"method\":\"account_sign\",\"params\":[\"0x694267f14675d7e1b9494fd8d72fefe1755710fa\",\"0x$(xxd -pu <<< ' bonk baz gaz')\"],\"id\":67}" http://localhost:8550/
|
||||
{"jsonrpc":"2.0","id":67,"error":{"code":-32000,"message":"Request denied"}}
|
||||
|
||||
```
|
||||
|
||||
Meanwhile, in the signer output:
|
||||
```text
|
||||
INFO [02-21|14:42:41] Op approved
|
||||
INFO [02-21|14:42:56] Op rejected
|
||||
```
|
||||
|
||||
The signer also stores all traffic over the external API in a log file. The last 4 lines shows the two requests and their responses:
|
||||
|
||||
```text
|
||||
#tail audit.log -n 4
|
||||
t=2018-02-21T14:42:41+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49706\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=202062617a6f6e6b2062617a2067617a0a
|
||||
t=2018-02-21T14:42:42+0100 lvl=info msg=Sign api=signer type=response data=93e6161840c3ae1efc26dc68dedab6e8fc233bb3fefa1b4645dbf6609b93dace160572ea4ab33240256bb6d3dadb60dcd9c515d6374d3cf614ee897408d41d541c error=nil
|
||||
t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=request metadata="{\"remote\":\"127.0.0.1:49708\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\"}" addr="0x694267f14675d7e1b9494fd8d72fefe1755710fa [chksum INVALID]" data=2020626f6e6b2062617a2067617a0a
|
||||
t=2018-02-21T14:42:56+0100 lvl=info msg=Sign api=signer type=response data= error="Request denied"
|
||||
```
|
4
vendor/github.com/ethereum/go-ethereum/cmd/ethkey/main.go
generated
vendored
4
vendor/github.com/ethereum/go-ethereum/cmd/ethkey/main.go
generated
vendored
|
@ -53,10 +53,6 @@ var (
|
|||
Name: "json",
|
||||
Usage: "output JSON instead of human-readable format",
|
||||
}
|
||||
messageFlag = cli.StringFlag{
|
||||
Name: "message",
|
||||
Usage: "the file that contains the message to sign/verify",
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
5
vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go
generated
vendored
5
vendor/github.com/ethereum/go-ethereum/cmd/evm/main.go
generated
vendored
|
@ -86,10 +86,6 @@ var (
|
|||
Name: "create",
|
||||
Usage: "indicates the action should be create rather than call",
|
||||
}
|
||||
DisableGasMeteringFlag = cli.BoolFlag{
|
||||
Name: "nogasmetering",
|
||||
Usage: "disable gas metering",
|
||||
}
|
||||
GenesisFlag = cli.StringFlag{
|
||||
Name: "prestate",
|
||||
Usage: "JSON file with prestate (genesis) config",
|
||||
|
@ -128,7 +124,6 @@ func init() {
|
|||
ValueFlag,
|
||||
DumpFlag,
|
||||
InputFlag,
|
||||
DisableGasMeteringFlag,
|
||||
MemProfileFlag,
|
||||
CPUProfileFlag,
|
||||
StatDumpFlag,
|
||||
|
|
14
vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go
generated
vendored
14
vendor/github.com/ethereum/go-ethereum/cmd/evm/runner.go
generated
vendored
|
@ -76,6 +76,7 @@ func runCmd(ctx *cli.Context) error {
|
|||
logconfig := &vm.LogConfig{
|
||||
DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name),
|
||||
DisableStack: ctx.GlobalBool(DisableStackFlag.Name),
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name),
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -83,8 +84,8 @@ func runCmd(ctx *cli.Context) error {
|
|||
debugLogger *vm.StructLogger
|
||||
statedb *state.StateDB
|
||||
chainConfig *params.ChainConfig
|
||||
sender = common.StringToAddress("sender")
|
||||
receiver = common.StringToAddress("receiver")
|
||||
sender = common.BytesToAddress([]byte("sender"))
|
||||
receiver = common.BytesToAddress([]byte("receiver"))
|
||||
)
|
||||
if ctx.GlobalBool(MachineFlag.Name) {
|
||||
tracer = NewJSONLogger(logconfig, os.Stdout)
|
||||
|
@ -161,9 +162,8 @@ func runCmd(ctx *cli.Context) error {
|
|||
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
|
||||
Value: utils.GlobalBig(ctx, ValueFlag.Name),
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: tracer,
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||
Tracer: tracer,
|
||||
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -235,9 +235,7 @@ Gas used: %d
|
|||
|
||||
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
|
||||
}
|
||||
if tracer != nil {
|
||||
tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err)
|
||||
} else {
|
||||
if tracer == nil {
|
||||
fmt.Printf("0x%x\n", ret)
|
||||
if err != nil {
|
||||
fmt.Printf(" error: %v\n", err)
|
||||
|
|
28
vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go
generated
vendored
28
vendor/github.com/ethereum/go-ethereum/cmd/faucet/faucet.go
generated
vendored
|
@ -533,9 +533,11 @@ func (f *faucet) loop() {
|
|||
}
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
for {
|
||||
select {
|
||||
case head := <-heads:
|
||||
// Start a goroutine to update the state from head notifications in the background
|
||||
update := make(chan *types.Header)
|
||||
|
||||
go func() {
|
||||
for head := range update {
|
||||
// New chain head arrived, query the current stats and stream to clients
|
||||
var (
|
||||
balance *big.Int
|
||||
|
@ -588,6 +590,17 @@ func (f *faucet) loop() {
|
|||
}
|
||||
}
|
||||
f.lock.RUnlock()
|
||||
}
|
||||
}()
|
||||
// Wait for various events and assing to the appropriate background threads
|
||||
for {
|
||||
select {
|
||||
case head := <-heads:
|
||||
// New head arrived, send if for state update if there's none running
|
||||
select {
|
||||
case update <- head:
|
||||
default:
|
||||
}
|
||||
|
||||
case <-f.update:
|
||||
// Pending requests updated, stream to clients
|
||||
|
@ -686,8 +699,6 @@ func authTwitter(url string) (string, string, common.Address, error) {
|
|||
if len(parts) < 4 || parts[len(parts)-2] != "status" {
|
||||
return "", "", common.Address{}, errors.New("Invalid Twitter status URL")
|
||||
}
|
||||
username := parts[len(parts)-3]
|
||||
|
||||
// Twitter's API isn't really friendly with direct links. Still, we don't
|
||||
// want to do ask read permissions from users, so just load the public posts and
|
||||
// scrape it for the Ethereum address and profile URL.
|
||||
|
@ -697,6 +708,13 @@ func authTwitter(url string) (string, string, common.Address, error) {
|
|||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// Resolve the username from the final redirect, no intermediate junk
|
||||
parts = strings.Split(res.Request.URL.String(), "/")
|
||||
if len(parts) < 4 || parts[len(parts)-2] != "status" {
|
||||
return "", "", common.Address{}, errors.New("Invalid Twitter status URL")
|
||||
}
|
||||
username := parts[len(parts)-3]
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", common.Address{}, err
|
||||
|
|
24
vendor/github.com/ethereum/go-ethereum/cmd/geth/bugcmd.go
generated
vendored
24
vendor/github.com/ethereum/go-ethereum/cmd/geth/bugcmd.go
generated
vendored
|
@ -49,15 +49,17 @@ func reportBug(ctx *cli.Context) error {
|
|||
// execute template and write contents to buff
|
||||
var buff bytes.Buffer
|
||||
|
||||
fmt.Fprintln(&buff, header)
|
||||
fmt.Fprintln(&buff, "#### System information")
|
||||
fmt.Fprintln(&buff)
|
||||
fmt.Fprintln(&buff, "Version:", params.Version)
|
||||
fmt.Fprintln(&buff, "Go Version:", runtime.Version())
|
||||
fmt.Fprintln(&buff, "OS:", runtime.GOOS)
|
||||
printOSDetails(&buff)
|
||||
fmt.Fprintln(&buff, header)
|
||||
|
||||
// open a new GH issue
|
||||
if !browser.Open(issueUrl + "?body=" + url.QueryEscape(buff.String())) {
|
||||
fmt.Printf("Please file a new issue at %s using this template:\n%s", issueUrl, buff.String())
|
||||
fmt.Printf("Please file a new issue at %s using this template:\n\n%s", issueUrl, buff.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -97,13 +99,15 @@ func printCmdOut(w io.Writer, prefix, path string, args ...string) {
|
|||
fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
|
||||
}
|
||||
|
||||
const header = `Please answer these questions before submitting your issue. Thanks!
|
||||
const header = `
|
||||
#### Expected behaviour
|
||||
|
||||
#### What did you do?
|
||||
|
||||
#### What did you expect to see?
|
||||
|
||||
#### What did you see instead?
|
||||
|
||||
#### System details
|
||||
|
||||
#### Actual behaviour
|
||||
|
||||
|
||||
#### Steps to reproduce the behaviour
|
||||
|
||||
|
||||
#### Backtrace
|
||||
`
|
||||
|
|
75
vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go
generated
vendored
75
vendor/github.com/ethereum/go-ethereum/cmd/geth/chaincmd.go
generated
vendored
|
@ -95,6 +95,34 @@ Requires a first argument of the file to write to.
|
|||
Optional second and third arguments control the first and
|
||||
last block to write. In this mode, the file will be appended
|
||||
if already existing.`,
|
||||
}
|
||||
importPreimagesCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(importPreimages),
|
||||
Name: "import-preimages",
|
||||
Usage: "Import the preimage database from an RLP stream",
|
||||
ArgsUsage: "<datafile>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.CacheFlag,
|
||||
utils.LightModeFlag,
|
||||
},
|
||||
Category: "BLOCKCHAIN COMMANDS",
|
||||
Description: `
|
||||
The import-preimages command imports hash preimages from an RLP encoded stream.`,
|
||||
}
|
||||
exportPreimagesCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(exportPreimages),
|
||||
Name: "export-preimages",
|
||||
Usage: "Export the preimage database into an RLP stream",
|
||||
ArgsUsage: "<dumpfile>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.CacheFlag,
|
||||
utils.LightModeFlag,
|
||||
},
|
||||
Category: "BLOCKCHAIN COMMANDS",
|
||||
Description: `
|
||||
The export-preimages command export hash preimages to an RLP encoded stream`,
|
||||
}
|
||||
copydbCommand = cli.Command{
|
||||
Action: utils.MigrateFlags(copyDb),
|
||||
|
@ -225,6 +253,13 @@ func importChain(ctx *cli.Context) error {
|
|||
utils.Fatalf("Failed to read database stats: %v", err)
|
||||
}
|
||||
fmt.Println(stats)
|
||||
|
||||
ioStats, err := db.LDB().GetProperty("leveldb.iostats")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||
}
|
||||
fmt.Println(ioStats)
|
||||
|
||||
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
||||
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
||||
|
||||
|
@ -255,6 +290,12 @@ func importChain(ctx *cli.Context) error {
|
|||
}
|
||||
fmt.Println(stats)
|
||||
|
||||
ioStats, err = db.LDB().GetProperty("leveldb.iostats")
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||
}
|
||||
fmt.Println(ioStats)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -286,7 +327,39 @@ func exportChain(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
utils.Fatalf("Export error: %v\n", err)
|
||||
}
|
||||
fmt.Printf("Export done in %v", time.Since(start))
|
||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||
return nil
|
||||
}
|
||||
|
||||
// importPreimages imports preimage data from the specified file.
|
||||
func importPreimages(ctx *cli.Context) error {
|
||||
if len(ctx.Args()) < 1 {
|
||||
utils.Fatalf("This command requires an argument.")
|
||||
}
|
||||
stack := makeFullNode(ctx)
|
||||
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||
|
||||
start := time.Now()
|
||||
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||
utils.Fatalf("Export error: %v\n", err)
|
||||
}
|
||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||
return nil
|
||||
}
|
||||
|
||||
// exportPreimages dumps the preimage data to specified json file in streaming way.
|
||||
func exportPreimages(ctx *cli.Context) error {
|
||||
if len(ctx.Args()) < 1 {
|
||||
utils.Fatalf("This command requires an argument.")
|
||||
}
|
||||
stack := makeFullNode(ctx)
|
||||
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||
|
||||
start := time.Now()
|
||||
if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||
utils.Fatalf("Export error: %v\n", err)
|
||||
}
|
||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/cmd/geth/config.go
generated
vendored
|
@ -32,7 +32,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
|
|
9
vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go
generated
vendored
9
vendor/github.com/ethereum/go-ethereum/cmd/geth/consolecmd.go
generated
vendored
|
@ -22,6 +22,7 @@ import (
|
|||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
|
@ -42,7 +43,7 @@ var (
|
|||
Description: `
|
||||
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
||||
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`,
|
||||
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
|
||||
}
|
||||
|
||||
attachCommand = cli.Command{
|
||||
|
@ -55,7 +56,7 @@ See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.`,
|
|||
Description: `
|
||||
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
||||
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
|
||||
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.
|
||||
This command allows to open a console on a running geth node.`,
|
||||
}
|
||||
|
||||
|
@ -68,7 +69,7 @@ This command allows to open a console on a running geth node.`,
|
|||
Category: "CONSOLE COMMANDS",
|
||||
Description: `
|
||||
The JavaScript VM exposes a node admin interface as well as the Ðapp
|
||||
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console`,
|
||||
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console`,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -207,7 +208,7 @@ func ephemeralConsole(ctx *cli.Context) error {
|
|||
}
|
||||
// Wait for pending callbacks, but stop for Ctrl-C.
|
||||
abort := make(chan os.Signal, 1)
|
||||
signal.Notify(abort, os.Interrupt)
|
||||
signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
go func() {
|
||||
<-abort
|
||||
|
|
8
vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go
generated
vendored
8
vendor/github.com/ethereum/go-ethereum/cmd/geth/main.go
generated
vendored
|
@ -28,7 +28,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
|
@ -46,8 +45,6 @@ const (
|
|||
var (
|
||||
// Git SHA1 commit hash of the release (set via linker flags)
|
||||
gitCommit = ""
|
||||
// Ethereum address of the Geth release oracle.
|
||||
relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf")
|
||||
// The app that holds all commands and flags.
|
||||
app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
|
||||
// flags that configure the node
|
||||
|
@ -65,7 +62,6 @@ var (
|
|||
utils.DashboardAddrFlag,
|
||||
utils.DashboardPortFlag,
|
||||
utils.DashboardRefreshFlag,
|
||||
utils.DashboardAssetsFlag,
|
||||
utils.EthashCacheDirFlag,
|
||||
utils.EthashCachesInMemoryFlag,
|
||||
utils.EthashCachesOnDiskFlag,
|
||||
|
@ -156,6 +152,8 @@ func init() {
|
|||
initCommand,
|
||||
importCommand,
|
||||
exportCommand,
|
||||
importPreimagesCommand,
|
||||
exportPreimagesCommand,
|
||||
copydbCommand,
|
||||
removedbCommand,
|
||||
dumpCommand,
|
||||
|
@ -243,7 +241,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
|||
stack.AccountManager().Subscribe(events)
|
||||
|
||||
go func() {
|
||||
// Create an chain state reader for self-derivation
|
||||
// Create a chain state reader for self-derivation
|
||||
rpcClient, err := stack.Attach()
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to attach to self: %v", err)
|
||||
|
|
28
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go
generated
vendored
28
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/genesis.go
generated
vendored
|
@ -168,19 +168,18 @@ type parityChainSpec struct {
|
|||
Engine struct {
|
||||
Ethash struct {
|
||||
Params struct {
|
||||
MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
|
||||
DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
|
||||
GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
|
||||
DurationLimit *hexutil.Big `json:"durationLimit"`
|
||||
BlockReward *hexutil.Big `json:"blockReward"`
|
||||
HomesteadTransition uint64 `json:"homesteadTransition"`
|
||||
EIP150Transition uint64 `json:"eip150Transition"`
|
||||
EIP160Transition uint64 `json:"eip160Transition"`
|
||||
EIP161abcTransition uint64 `json:"eip161abcTransition"`
|
||||
EIP161dTransition uint64 `json:"eip161dTransition"`
|
||||
EIP649Reward *hexutil.Big `json:"eip649Reward"`
|
||||
EIP100bTransition uint64 `json:"eip100bTransition"`
|
||||
EIP649Transition uint64 `json:"eip649Transition"`
|
||||
MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
|
||||
DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
|
||||
DurationLimit *hexutil.Big `json:"durationLimit"`
|
||||
BlockReward *hexutil.Big `json:"blockReward"`
|
||||
HomesteadTransition uint64 `json:"homesteadTransition"`
|
||||
EIP150Transition uint64 `json:"eip150Transition"`
|
||||
EIP160Transition uint64 `json:"eip160Transition"`
|
||||
EIP161abcTransition uint64 `json:"eip161abcTransition"`
|
||||
EIP161dTransition uint64 `json:"eip161dTransition"`
|
||||
EIP649Reward *hexutil.Big `json:"eip649Reward"`
|
||||
EIP100bTransition uint64 `json:"eip100bTransition"`
|
||||
EIP649Transition uint64 `json:"eip649Transition"`
|
||||
} `json:"params"`
|
||||
} `json:"Ethash"`
|
||||
} `json:"engine"`
|
||||
|
@ -188,6 +187,7 @@ type parityChainSpec struct {
|
|||
Params struct {
|
||||
MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
|
||||
MinGasLimit hexutil.Uint64 `json:"minGasLimit"`
|
||||
GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
|
||||
NetworkID hexutil.Uint64 `json:"networkID"`
|
||||
MaxCodeSize uint64 `json:"maxCodeSize"`
|
||||
EIP155Transition uint64 `json:"eip155Transition"`
|
||||
|
@ -270,7 +270,6 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
|
|||
}
|
||||
spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
|
||||
spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor)
|
||||
spec.Engine.Ethash.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
|
||||
spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit)
|
||||
spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)
|
||||
spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64()
|
||||
|
@ -284,6 +283,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
|
|||
|
||||
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
|
||||
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
|
||||
spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
|
||||
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64())
|
||||
spec.Params.MaxCodeSize = params.MaxCodeSize
|
||||
spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
|
||||
|
|
3
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_dashboard.go
generated
vendored
|
@ -631,6 +631,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
|
|||
"Tangerine": conf.Genesis.Config.EIP150Block,
|
||||
"Spurious": conf.Genesis.Config.EIP155Block,
|
||||
"Byzantium": conf.Genesis.Config.ByzantiumBlock,
|
||||
"Constantinople": conf.Genesis.Config.ConstantinopleBlock,
|
||||
})
|
||||
files[filepath.Join(workdir, "index.html")] = indexfile.Bytes()
|
||||
|
||||
|
@ -682,7 +683,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
|
|||
return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
|
||||
}
|
||||
|
||||
// dashboardInfos is returned from an dashboard status check to allow reporting
|
||||
// dashboardInfos is returned from a dashboard status check to allow reporting
|
||||
// various configuration parameters.
|
||||
type dashboardInfos struct {
|
||||
host string
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_explorer.go
generated
vendored
|
@ -168,7 +168,7 @@ func (info *explorerInfos) Report() map[string]string {
|
|||
return report
|
||||
}
|
||||
|
||||
// checkExplorer does a health-check against an block explorer server to verify
|
||||
// checkExplorer does a health-check against a block explorer server to verify
|
||||
// whether it's running, and if yes, whether it's responsive.
|
||||
func checkExplorer(client *sshClient, network string) (*explorerInfos, error) {
|
||||
// Inspect a possible block explorer container on the host
|
||||
|
|
6
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go
generated
vendored
6
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_faucet.go
generated
vendored
|
@ -30,7 +30,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// faucetDockerfile is the Dockerfile required to build an faucet container to
|
||||
// faucetDockerfile is the Dockerfile required to build a faucet container to
|
||||
// grant crypto tokens based on GitHub authentications.
|
||||
var faucetDockerfile = `
|
||||
FROM ethereum/client-go:alltools-latest
|
||||
|
@ -138,7 +138,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config
|
|||
return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate", workdir, network))
|
||||
}
|
||||
|
||||
// faucetInfos is returned from an faucet status check to allow reporting various
|
||||
// faucetInfos is returned from a faucet status check to allow reporting various
|
||||
// configuration parameters.
|
||||
type faucetInfos struct {
|
||||
node *nodeInfos
|
||||
|
@ -181,7 +181,7 @@ func (info *faucetInfos) Report() map[string]string {
|
|||
return report
|
||||
}
|
||||
|
||||
// checkFaucet does a health-check against an faucet server to verify whether
|
||||
// checkFaucet does a health-check against a faucet server to verify whether
|
||||
// it's running, and if yes, gathering a collection of useful infos about it.
|
||||
func checkFaucet(client *sshClient, network string) (*faucetInfos, error) {
|
||||
// Inspect a possible faucet container on the host
|
||||
|
|
10
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go
generated
vendored
10
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_node.go
generated
vendored
|
@ -40,11 +40,11 @@ ADD genesis.json /genesis.json
|
|||
ADD signer.pass /signer.pass
|
||||
{{end}}
|
||||
RUN \
|
||||
echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}}
|
||||
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}}
|
||||
echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> geth.sh
|
||||
echo 'geth --cache 512 init /genesis.json' > /root/geth.sh && \{{if .Unlock}}
|
||||
echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> /root/geth.sh && \{{end}}
|
||||
echo $'geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--etherbase {{.Etherbase}} --mine --minerthreads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --targetgaslimit {{.GasTarget}} --gasprice {{.GasPrice}}' >> /root/geth.sh
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "geth.sh"]
|
||||
ENTRYPOINT ["/bin/sh", "/root/geth.sh"]
|
||||
`
|
||||
|
||||
// nodeComposefile is the docker-compose.yml file required to deploy and maintain
|
||||
|
@ -198,7 +198,7 @@ func (info *nodeInfos) Report() map[string]string {
|
|||
return report
|
||||
}
|
||||
|
||||
// checkNode does a health-check against an boot or seal node server to verify
|
||||
// checkNode does a health-check against a boot or seal node server to verify
|
||||
// whether it's running, and if yes, whether it's responsive.
|
||||
func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) {
|
||||
kind := "bootnode"
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/module_wallet.go
generated
vendored
|
@ -37,7 +37,7 @@ ADD genesis.json /genesis.json
|
|||
RUN \
|
||||
echo 'node server.js &' > wallet.sh && \
|
||||
echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
|
||||
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*"' >> wallet.sh
|
||||
echo $'geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
|
||||
|
||||
RUN \
|
||||
sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
|
||||
|
|
7
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go
generated
vendored
7
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/puppeth.go
generated
vendored
|
@ -20,6 +20,7 @@ package main
|
|||
import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
@ -34,7 +35,7 @@ func main() {
|
|||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "network",
|
||||
Usage: "name of the network to administer",
|
||||
Usage: "name of the network to administer (no spaces or hyphens, please)",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "loglevel",
|
||||
|
@ -47,6 +48,10 @@ func main() {
|
|||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
network := c.String("network")
|
||||
if strings.Contains(network, " ") || strings.Contains(network, "-") {
|
||||
log.Crit("No spaces or hyphens allowed in network name")
|
||||
}
|
||||
// Start the wizard and relinquish control
|
||||
makeWizard(c.String("network")).run()
|
||||
return nil
|
||||
|
|
7
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go
generated
vendored
7
vendor/github.com/ethereum/go-ethereum/cmd/puppeth/wizard_intro.go
generated
vendored
|
@ -59,15 +59,16 @@ func (w *wizard) run() {
|
|||
fmt.Println()
|
||||
|
||||
// Make sure we have a good network name to work with fmt.Println()
|
||||
// Docker accepts hyphens in image names, but doesn't like it for container names
|
||||
if w.network == "" {
|
||||
fmt.Println("Please specify a network name to administer (no spaces, please)")
|
||||
fmt.Println("Please specify a network name to administer (no spaces or hyphens, please)")
|
||||
for {
|
||||
w.network = w.readString()
|
||||
if !strings.Contains(w.network, " ") {
|
||||
if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") {
|
||||
fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network)
|
||||
break
|
||||
}
|
||||
log.Error("I also like to live dangerously, still no spaces")
|
||||
log.Error("I also like to live dangerously, still no spaces or hyphens")
|
||||
}
|
||||
}
|
||||
log.Info("Administering Ethereum network", "name", w.network)
|
||||
|
|
58
vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go
generated
vendored
58
vendor/github.com/ethereum/go-ethereum/cmd/swarm/config.go
generated
vendored
|
@ -23,6 +23,7 @@ import (
|
|||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
cli "gopkg.in/urfave/cli.v1"
|
||||
|
@ -97,10 +98,15 @@ func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) {
|
|||
config = bzzapi.NewDefaultConfig()
|
||||
//first load settings from config file (if provided)
|
||||
config, err = configFileOverride(config, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//override settings provided by environment variables
|
||||
config = envVarsOverride(config)
|
||||
//override settings provided by command line
|
||||
config = cmdLineOverride(config, ctx)
|
||||
//validate configuration parameters
|
||||
err = validateConfig(config)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -194,12 +200,16 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
|
|||
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
|
||||
}
|
||||
|
||||
//EnsApi can be set to "", so can't check for empty string, as it is allowed!
|
||||
if ctx.GlobalIsSet(EnsAPIFlag.Name) {
|
||||
currentConfig.EnsApi = ctx.GlobalString(EnsAPIFlag.Name)
|
||||
ensAPIs := ctx.GlobalStringSlice(EnsAPIFlag.Name)
|
||||
// preserve backward compatibility to disable ENS with --ens-api=""
|
||||
if len(ensAPIs) == 1 && ensAPIs[0] == "" {
|
||||
ensAPIs = nil
|
||||
}
|
||||
currentConfig.EnsAPIs = ensAPIs
|
||||
}
|
||||
|
||||
if ensaddr := ctx.GlobalString(EnsAddrFlag.Name); ensaddr != "" {
|
||||
if ensaddr := ctx.GlobalString(DeprecatedEnsAddrFlag.Name); ensaddr != "" {
|
||||
currentConfig.EnsRoot = common.HexToAddress(ensaddr)
|
||||
}
|
||||
|
||||
|
@ -266,9 +276,8 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
|
|||
utils.Fatalf(SWARM_ERR_SWAP_SET_NO_API)
|
||||
}
|
||||
|
||||
//EnsApi can be set to "", so can't check for empty string, as it is allowed
|
||||
if ensapi, exists := os.LookupEnv(SWARM_ENV_ENS_API); exists {
|
||||
currentConfig.EnsApi = ensapi
|
||||
if ensapi := os.Getenv(SWARM_ENV_ENS_API); ensapi != "" {
|
||||
currentConfig.EnsAPIs = strings.Split(ensapi, ",")
|
||||
}
|
||||
|
||||
if ensaddr := os.Getenv(SWARM_ENV_ENS_ADDR); ensaddr != "" {
|
||||
|
@ -309,6 +318,43 @@ func checkDeprecated(ctx *cli.Context) {
|
|||
if ctx.GlobalString(DeprecatedEthAPIFlag.Name) != "" {
|
||||
utils.Fatalf("--ethapi is no longer a valid command line flag, please use --ens-api and/or --swap-api.")
|
||||
}
|
||||
// warn if --ens-api flag is set
|
||||
if ctx.GlobalString(DeprecatedEnsAddrFlag.Name) != "" {
|
||||
log.Warn("--ens-addr is no longer a valid command line flag, please use --ens-api to specify contract address.")
|
||||
}
|
||||
}
|
||||
|
||||
//validate configuration parameters
|
||||
func validateConfig(cfg *bzzapi.Config) (err error) {
|
||||
for _, ensAPI := range cfg.EnsAPIs {
|
||||
if ensAPI != "" {
|
||||
if err := validateEnsAPIs(ensAPI); err != nil {
|
||||
return fmt.Errorf("invalid format [tld:][contract-addr@]url for ENS API endpoint configuration %q: %v", ensAPI, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//validate EnsAPIs configuration parameter
|
||||
func validateEnsAPIs(s string) (err error) {
|
||||
// missing contract address
|
||||
if strings.HasPrefix(s, "@") {
|
||||
return errors.New("missing contract address")
|
||||
}
|
||||
// missing url
|
||||
if strings.HasSuffix(s, "@") {
|
||||
return errors.New("missing url")
|
||||
}
|
||||
// missing tld
|
||||
if strings.HasPrefix(s, ":") {
|
||||
return errors.New("missing tld")
|
||||
}
|
||||
// missing url
|
||||
if strings.HasSuffix(s, ":") {
|
||||
return errors.New("missing url")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//print a Config as string
|
||||
|
|
82
vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go
generated
vendored
82
vendor/github.com/ethereum/go-ethereum/cmd/swarm/main.go
generated
vendored
|
@ -17,11 +17,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
|
@ -29,14 +27,12 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
"github.com/ethereum/go-ethereum/contracts/ens"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
|
@ -45,9 +41,9 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/swarm"
|
||||
bzzapi "github.com/ethereum/go-ethereum/swarm/api"
|
||||
swarmmetrics "github.com/ethereum/go-ethereum/swarm/metrics"
|
||||
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
@ -110,16 +106,11 @@ var (
|
|||
Usage: "Swarm Syncing enabled (default true)",
|
||||
EnvVar: SWARM_ENV_SYNC_ENABLE,
|
||||
}
|
||||
EnsAPIFlag = cli.StringFlag{
|
||||
EnsAPIFlag = cli.StringSliceFlag{
|
||||
Name: "ens-api",
|
||||
Usage: "URL of the Ethereum API provider to use for ENS record lookups",
|
||||
Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url",
|
||||
EnvVar: SWARM_ENV_ENS_API,
|
||||
}
|
||||
EnsAddrFlag = cli.StringFlag{
|
||||
Name: "ens-addr",
|
||||
Usage: "ENS contract address (default is detected as testnet or mainnet using --ens-api)",
|
||||
EnvVar: SWARM_ENV_ENS_ADDR,
|
||||
}
|
||||
SwarmApiFlag = cli.StringFlag{
|
||||
Name: "bzzapi",
|
||||
Usage: "Swarm HTTP endpoint",
|
||||
|
@ -156,6 +147,10 @@ var (
|
|||
Name: "ethapi",
|
||||
Usage: "DEPRECATED: please use --ens-api and --swap-api",
|
||||
}
|
||||
DeprecatedEnsAddrFlag = cli.StringFlag{
|
||||
Name: "ens-addr",
|
||||
Usage: "DEPRECATED: ENS contract address, please use --ens-api with contract address according to its format",
|
||||
}
|
||||
)
|
||||
|
||||
//declare a few constant error messages, useful for later error check comparisons in test
|
||||
|
@ -343,7 +338,6 @@ DEPRECATED: use 'swarm db clean'.
|
|||
// bzzd-specific flags
|
||||
CorsStringFlag,
|
||||
EnsAPIFlag,
|
||||
EnsAddrFlag,
|
||||
SwarmTomlConfigPathFlag,
|
||||
SwarmConfigPathFlag,
|
||||
SwarmSwapEnabledFlag,
|
||||
|
@ -363,11 +357,17 @@ DEPRECATED: use 'swarm db clean'.
|
|||
SwarmUploadMimeType,
|
||||
//deprecated flags
|
||||
DeprecatedEthAPIFlag,
|
||||
DeprecatedEnsAddrFlag,
|
||||
}
|
||||
app.Flags = append(app.Flags, debug.Flags...)
|
||||
app.Flags = append(app.Flags, swarmmetrics.Flags...)
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
return debug.Setup(ctx)
|
||||
if err := debug.Setup(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
swarmmetrics.Setup(ctx)
|
||||
return nil
|
||||
}
|
||||
app.After = func(ctx *cli.Context) error {
|
||||
debug.Exit()
|
||||
|
@ -448,38 +448,6 @@ func bzzd(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// detectEnsAddr determines the ENS contract address by getting both the
|
||||
// version and genesis hash using the client and matching them to either
|
||||
// mainnet or testnet addresses
|
||||
func detectEnsAddr(client *rpc.Client) (common.Address, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var version string
|
||||
if err := client.CallContext(ctx, &version, "net_version"); err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
||||
block, err := ethclient.NewClient(client).BlockByNumber(ctx, big.NewInt(0))
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
case version == "1" && block.Hash() == params.MainnetGenesisHash:
|
||||
log.Info("using Mainnet ENS contract address", "addr", ens.MainNetAddress)
|
||||
return ens.MainNetAddress, nil
|
||||
|
||||
case version == "3" && block.Hash() == params.TestnetGenesisHash:
|
||||
log.Info("using Testnet ENS contract address", "addr", ens.TestNetAddress)
|
||||
return ens.TestNetAddress, nil
|
||||
|
||||
default:
|
||||
return common.Address{}, fmt.Errorf("unknown version and genesis hash: %s %s", version, block.Hash())
|
||||
}
|
||||
}
|
||||
|
||||
func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.Node) {
|
||||
|
||||
//define the swarm service boot function
|
||||
|
@ -494,27 +462,7 @@ func registerBzzService(bzzconfig *bzzapi.Config, ctx *cli.Context, stack *node.
|
|||
}
|
||||
}
|
||||
|
||||
var ensClient *ethclient.Client
|
||||
if bzzconfig.EnsApi != "" {
|
||||
log.Info("connecting to ENS API", "url", bzzconfig.EnsApi)
|
||||
client, err := rpc.Dial(bzzconfig.EnsApi)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error connecting to ENS API %s: %s", bzzconfig.EnsApi, err)
|
||||
}
|
||||
ensClient = ethclient.NewClient(client)
|
||||
|
||||
//no ENS root address set yet
|
||||
if bzzconfig.EnsRoot == (common.Address{}) {
|
||||
ensAddr, err := detectEnsAddr(client)
|
||||
if err == nil {
|
||||
bzzconfig.EnsRoot = ensAddr
|
||||
} else {
|
||||
log.Warn(fmt.Sprintf("could not determine ENS contract address, using default %s", bzzconfig.EnsRoot), "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return swarm.NewSwarm(ctx, swapClient, ensClient, bzzconfig, bzzconfig.SwapEnabled, bzzconfig.SyncEnabled, bzzconfig.Cors)
|
||||
return swarm.NewSwarm(ctx, swapClient, bzzconfig)
|
||||
}
|
||||
//register within the ethereum node
|
||||
if err := stack.Register(boot); err != nil {
|
||||
|
|
6
vendor/github.com/ethereum/go-ethereum/cmd/swarm/manifest.go
generated
vendored
6
vendor/github.com/ethereum/go-ethereum/cmd/swarm/manifest.go
generated
vendored
|
@ -35,7 +35,7 @@ const bzzManifestJSON = "application/bzz-manifest+json"
|
|||
func add(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
if len(args) < 3 {
|
||||
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||
utils.Fatalf("Need at least three arguments <MHASH> <path> <HASH> [<content-type>]")
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -69,7 +69,7 @@ func update(ctx *cli.Context) {
|
|||
|
||||
args := ctx.Args()
|
||||
if len(args) < 3 {
|
||||
utils.Fatalf("Need atleast three arguments <MHASH> <path> <HASH>")
|
||||
utils.Fatalf("Need at least three arguments <MHASH> <path> <HASH>")
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -101,7 +101,7 @@ func update(ctx *cli.Context) {
|
|||
func remove(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
if len(args) < 2 {
|
||||
utils.Fatalf("Need atleast two arguments <MHASH> <path>")
|
||||
utils.Fatalf("Need at least two arguments <MHASH> <path>")
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
99
vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go
generated
vendored
99
vendor/github.com/ethereum/go-ethereum/cmd/utils/cmd.go
generated
vendored
|
@ -25,9 +25,13 @@ import (
|
|||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
|
@ -64,7 +68,7 @@ func StartNode(stack *node.Node) {
|
|||
}
|
||||
go func() {
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, os.Interrupt)
|
||||
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer signal.Stop(sigc)
|
||||
<-sigc
|
||||
log.Info("Got interrupt, shutting down...")
|
||||
|
@ -85,7 +89,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
|||
// If a signal is received, the import will stop at the next batch.
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
stop := make(chan struct{})
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer signal.Stop(interrupt)
|
||||
defer close(interrupt)
|
||||
go func() {
|
||||
|
@ -104,6 +108,8 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
|||
}
|
||||
|
||||
log.Info("Importing blockchain", "file", fn)
|
||||
|
||||
// Open the file handle and potentially unwrap the gzip stream
|
||||
fh, err := os.Open(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -179,8 +185,12 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
|
|||
return nil
|
||||
}
|
||||
|
||||
// ExportChain exports a blockchain into the specified file, truncating any data
|
||||
// already present in the file.
|
||||
func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||
log.Info("Exporting blockchain", "file", fn)
|
||||
|
||||
// Open the file handle and potentially wrap with a gzip stream
|
||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -192,7 +202,7 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
|||
writer = gzip.NewWriter(writer)
|
||||
defer writer.(*gzip.Writer).Close()
|
||||
}
|
||||
|
||||
// Iterate over the blocks and export them
|
||||
if err := blockchain.Export(writer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -201,9 +211,12 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ExportAppendChain exports a blockchain into the specified file, appending to
|
||||
// the file if data already exists in it.
|
||||
func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
|
||||
log.Info("Exporting blockchain", "file", fn)
|
||||
// TODO verify mode perms
|
||||
|
||||
// Open the file handle and potentially wrap with a gzip stream
|
||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -215,10 +228,86 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
|||
writer = gzip.NewWriter(writer)
|
||||
defer writer.(*gzip.Writer).Close()
|
||||
}
|
||||
|
||||
// Iterate over the blocks and export them
|
||||
if err := blockchain.ExportN(writer, first, last); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Exported blockchain to", "file", fn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImportPreimages imports a batch of exported hash preimages into the database.
|
||||
func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
|
||||
log.Info("Importing preimages", "file", fn)
|
||||
|
||||
// Open the file handle and potentially unwrap the gzip stream
|
||||
fh, err := os.Open(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
var reader io.Reader = fh
|
||||
if strings.HasSuffix(fn, ".gz") {
|
||||
if reader, err = gzip.NewReader(reader); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
stream := rlp.NewStream(reader, 0)
|
||||
|
||||
// Import the preimages in batches to prevent disk trashing
|
||||
preimages := make(map[common.Hash][]byte)
|
||||
|
||||
for {
|
||||
// Read the next entry and ensure it's not junk
|
||||
var blob []byte
|
||||
|
||||
if err := stream.Decode(&blob); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Accumulate the preimages and flush when enough ws gathered
|
||||
preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
|
||||
if len(preimages) > 1024 {
|
||||
if err := core.WritePreimages(db, 0, preimages); err != nil {
|
||||
return err
|
||||
}
|
||||
preimages = make(map[common.Hash][]byte)
|
||||
}
|
||||
}
|
||||
// Flush the last batch preimage data
|
||||
if len(preimages) > 0 {
|
||||
return core.WritePreimages(db, 0, preimages)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportPreimages exports all known hash preimages into the specified file,
|
||||
// truncating any data already present in the file.
|
||||
func ExportPreimages(db *ethdb.LDBDatabase, fn string) error {
|
||||
log.Info("Exporting preimages", "file", fn)
|
||||
|
||||
// Open the file handle and potentially wrap with a gzip stream
|
||||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
var writer io.Writer = fh
|
||||
if strings.HasSuffix(fn, ".gz") {
|
||||
writer = gzip.NewWriter(writer)
|
||||
defer writer.(*gzip.Writer).Close()
|
||||
}
|
||||
// Iterate over the preimages and export them
|
||||
it := db.NewIteratorWithPrefix([]byte("secure-key-"))
|
||||
for it.Next() {
|
||||
if err := rlp.Encode(writer, it.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Info("Exported preimages", "file", fn)
|
||||
return nil
|
||||
}
|
||||
|
|
20
vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go
generated
vendored
20
vendor/github.com/ethereum/go-ethereum/cmd/utils/flags.go
generated
vendored
|
@ -55,7 +55,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
|
@ -64,7 +64,7 @@ var (
|
|||
{{if .cmd.Description}}{{.cmd.Description}}
|
||||
{{end}}{{if .cmd.Subcommands}}
|
||||
SUBCOMMANDS:
|
||||
{{range .cmd.Subcommands}}{{.cmd.Name}}{{with .cmd.ShortName}}, {{.cmd}}{{end}}{{ "\t" }}{{.cmd.Usage}}
|
||||
{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{end}}{{if .categorizedFlags}}
|
||||
{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
|
||||
{{range $categorized.Flags}}{{"\t"}}{{.}}
|
||||
|
@ -209,11 +209,6 @@ var (
|
|||
Usage: "Dashboard metrics collection refresh rate",
|
||||
Value: dashboard.DefaultConfig.Refresh,
|
||||
}
|
||||
DashboardAssetsFlag = cli.StringFlag{
|
||||
Name: "dashboard.assets",
|
||||
Usage: "Developer flag to serve the dashboard from the local file system",
|
||||
Value: dashboard.DefaultConfig.Assets,
|
||||
}
|
||||
// Ethash settings
|
||||
EthashCacheDirFlag = DirectoryFlag{
|
||||
Name: "ethash.cachedir",
|
||||
|
@ -400,7 +395,7 @@ var (
|
|||
RPCVirtualHostsFlag = cli.StringFlag{
|
||||
Name: "rpcvhosts",
|
||||
Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
|
||||
Value: "localhost",
|
||||
Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
|
||||
}
|
||||
RPCApiFlag = cli.StringFlag{
|
||||
Name: "rpcapi",
|
||||
|
@ -695,8 +690,9 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
|
|||
if ctx.GlobalIsSet(RPCApiFlag.Name) {
|
||||
cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
|
||||
}
|
||||
|
||||
cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
|
||||
if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
|
||||
cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// setWS creates the WebSocket RPC listener interface string from the set
|
||||
|
@ -818,6 +814,9 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
|
|||
|
||||
if ctx.GlobalIsSet(MaxPeersFlag.Name) {
|
||||
cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
|
||||
if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
|
||||
cfg.MaxPeers += lightPeers
|
||||
}
|
||||
} else {
|
||||
if lightServer {
|
||||
cfg.MaxPeers += lightPeers
|
||||
|
@ -1119,7 +1118,6 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
|
|||
cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
|
||||
cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
|
||||
cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
|
||||
cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name)
|
||||
}
|
||||
|
||||
// RegisterEthService adds an Ethereum client to the stack.
|
||||
|
|
211
vendor/github.com/ethereum/go-ethereum/cmd/wnode/main.go
generated
vendored
211
vendor/github.com/ethereum/go-ethereum/cmd/wnode/main.go
generated
vendored
|
@ -22,6 +22,7 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
|
@ -48,6 +49,7 @@ import (
|
|||
)
|
||||
|
||||
const quitCommand = "~Q"
|
||||
const entropySize = 32
|
||||
|
||||
// singletons
|
||||
var (
|
||||
|
@ -55,6 +57,7 @@ var (
|
|||
shh *whisper.Whisper
|
||||
done chan struct{}
|
||||
mailServer mailserver.WMailServer
|
||||
entropy [entropySize]byte
|
||||
|
||||
input = bufio.NewReader(os.Stdin)
|
||||
)
|
||||
|
@ -76,14 +79,15 @@ var (
|
|||
|
||||
// cmd arguments
|
||||
var (
|
||||
bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't actively connect to peers, wait for incoming connections")
|
||||
forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither send nor decrypt messages")
|
||||
bootstrapMode = flag.Bool("standalone", false, "boostrap node: don't initiate connection to peers, just wait for incoming connections")
|
||||
forwarderMode = flag.Bool("forwarder", false, "forwarder mode: only forward messages, neither encrypt nor decrypt messages")
|
||||
mailServerMode = flag.Bool("mailserver", false, "mail server mode: delivers expired messages on demand")
|
||||
requestMail = flag.Bool("mailclient", false, "request expired messages from the bootstrap server")
|
||||
asymmetricMode = flag.Bool("asym", false, "use asymmetric encryption")
|
||||
generateKey = flag.Bool("generatekey", false, "generate and show the private key")
|
||||
fileExMode = flag.Bool("fileexchange", false, "file exchange mode")
|
||||
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics")
|
||||
fileReader = flag.Bool("filereader", false, "load and decrypt messages saved as files, display as plain text")
|
||||
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics (password, etc.)")
|
||||
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
|
||||
|
||||
argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level")
|
||||
|
@ -99,13 +103,14 @@ var (
|
|||
argIDFile = flag.String("idfile", "", "file name with node id (private key)")
|
||||
argEnode = flag.String("boot", "", "bootstrap node you want to connect to (e.g. enode://e454......08d50@52.176.211.200:16428)")
|
||||
argTopic = flag.String("topic", "", "topic in hexadecimal format (e.g. 70a4beef)")
|
||||
argSaveDir = flag.String("savedir", "", "directory where incoming messages will be saved as files")
|
||||
argSaveDir = flag.String("savedir", "", "directory where all incoming messages will be saved as files")
|
||||
)
|
||||
|
||||
func main() {
|
||||
processArgs()
|
||||
initialize()
|
||||
run()
|
||||
shutdown()
|
||||
}
|
||||
|
||||
func processArgs() {
|
||||
|
@ -192,6 +197,8 @@ func initialize() {
|
|||
if len(*argIP) == 0 {
|
||||
argIP = scanLineA("Please enter your IP and port (e.g. 127.0.0.1:30348): ")
|
||||
}
|
||||
} else if *fileReader {
|
||||
*bootstrapMode = true
|
||||
} else {
|
||||
if len(*argEnode) == 0 {
|
||||
argEnode = scanLineA("Please enter the peer's enode: ")
|
||||
|
@ -200,11 +207,6 @@ func initialize() {
|
|||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
cfg := &whisper.Config{
|
||||
MaxMessageSize: uint32(*argMaxSize),
|
||||
MinimumAcceptedPOW: *argPoW,
|
||||
}
|
||||
|
||||
if *mailServerMode {
|
||||
if len(msPassword) == 0 {
|
||||
msPassword, err = console.Stdin.PromptPassword("Please enter the Mail Server password: ")
|
||||
|
@ -212,14 +214,15 @@ func initialize() {
|
|||
utils.Fatalf("Failed to read Mail Server password: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
shh = whisper.New(cfg)
|
||||
shh.RegisterServer(&mailServer)
|
||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||
} else {
|
||||
shh = whisper.New(cfg)
|
||||
}
|
||||
|
||||
cfg := &whisper.Config{
|
||||
MaxMessageSize: uint32(*argMaxSize),
|
||||
MinimumAcceptedPOW: *argPoW,
|
||||
}
|
||||
|
||||
shh = whisper.New(cfg)
|
||||
|
||||
if *argPoW != whisper.DefaultMinimumPoW {
|
||||
err := shh.SetMinimumPoW(*argPoW)
|
||||
if err != nil {
|
||||
|
@ -261,6 +264,16 @@ func initialize() {
|
|||
maxPeers = 800
|
||||
}
|
||||
|
||||
_, err = crand.Read(entropy[:])
|
||||
if err != nil {
|
||||
utils.Fatalf("crypto/rand failed: %s", err)
|
||||
}
|
||||
|
||||
if *mailServerMode {
|
||||
shh.RegisterServer(&mailServer)
|
||||
mailServer.Init(shh, *argDBPath, msPassword, *argServerPoW)
|
||||
}
|
||||
|
||||
server = &p2p.Server{
|
||||
Config: p2p.Config{
|
||||
PrivateKey: nodeid,
|
||||
|
@ -276,10 +289,11 @@ func initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
func startServer() {
|
||||
func startServer() error {
|
||||
err := server.Start()
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to start Whisper peer: %s.", err)
|
||||
fmt.Printf("Failed to start Whisper peer: %s.", err)
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("my public key: %s \n", common.ToHex(crypto.FromECDSAPub(&asymKey.PublicKey)))
|
||||
|
@ -295,9 +309,14 @@ func startServer() {
|
|||
configureNode()
|
||||
}
|
||||
|
||||
if !*forwarderMode {
|
||||
if *fileExMode {
|
||||
fmt.Printf("Please type the file name to be send. To quit type: '%s'\n", quitCommand)
|
||||
} else if *fileReader {
|
||||
fmt.Printf("Please type the file name to be decrypted. To quit type: '%s'\n", quitCommand)
|
||||
} else if !*forwarderMode {
|
||||
fmt.Printf("Please type the message. To quit type: '%s'\n", quitCommand)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isKeyValid(k *ecdsa.PublicKey) bool {
|
||||
|
@ -411,8 +430,10 @@ func waitForConnection(timeout bool) {
|
|||
}
|
||||
|
||||
func run() {
|
||||
defer mailServer.Close()
|
||||
startServer()
|
||||
err := startServer()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer server.Stop()
|
||||
shh.Start(nil)
|
||||
defer shh.Stop()
|
||||
|
@ -425,21 +446,26 @@ func run() {
|
|||
requestExpiredMessagesLoop()
|
||||
} else if *fileExMode {
|
||||
sendFilesLoop()
|
||||
} else if *fileReader {
|
||||
fileReaderLoop()
|
||||
} else {
|
||||
sendLoop()
|
||||
}
|
||||
}
|
||||
|
||||
func shutdown() {
|
||||
close(done)
|
||||
mailServer.Close()
|
||||
}
|
||||
|
||||
func sendLoop() {
|
||||
for {
|
||||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
close(done)
|
||||
break
|
||||
return
|
||||
}
|
||||
sendMsg([]byte(s))
|
||||
|
||||
if *asymmetricMode {
|
||||
// print your own message for convenience,
|
||||
// because in asymmetric mode it is impossible to decrypt it
|
||||
|
@ -455,13 +481,11 @@ func sendFilesLoop() {
|
|||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
close(done)
|
||||
break
|
||||
return
|
||||
}
|
||||
b, err := ioutil.ReadFile(s)
|
||||
if err != nil {
|
||||
fmt.Printf(">>> Error: %s \n", err)
|
||||
continue
|
||||
} else {
|
||||
h := sendMsg(b)
|
||||
if (h == common.Hash{}) {
|
||||
|
@ -475,6 +499,38 @@ func sendFilesLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
func fileReaderLoop() {
|
||||
watcher1 := shh.GetFilter(symFilterID)
|
||||
watcher2 := shh.GetFilter(asymFilterID)
|
||||
if watcher1 == nil && watcher2 == nil {
|
||||
fmt.Println("Error: neither symmetric nor asymmetric filter is installed")
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
s := scanLine("")
|
||||
if s == quitCommand {
|
||||
fmt.Println("Quit command received")
|
||||
return
|
||||
}
|
||||
raw, err := ioutil.ReadFile(s)
|
||||
if err != nil {
|
||||
fmt.Printf(">>> Error: %s \n", err)
|
||||
} else {
|
||||
env := whisper.Envelope{Data: raw} // the topic is zero
|
||||
msg := env.Open(watcher1) // force-open envelope regardless of the topic
|
||||
if msg == nil {
|
||||
msg = env.Open(watcher2)
|
||||
}
|
||||
if msg == nil {
|
||||
fmt.Printf(">>> Error: failed to decrypt the message \n")
|
||||
} else {
|
||||
printMessageInfo(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scanLine(prompt string) string {
|
||||
if len(prompt) > 0 {
|
||||
fmt.Print(prompt)
|
||||
|
@ -517,6 +573,7 @@ func sendMsg(payload []byte) common.Hash {
|
|||
if err != nil {
|
||||
utils.Fatalf("failed to create new message: %s", err)
|
||||
}
|
||||
|
||||
envelope, err := msg.Wrap(¶ms)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to seal message: %v \n", err)
|
||||
|
@ -548,21 +605,21 @@ func messageLoop() {
|
|||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
messages := sf.Retrieve()
|
||||
m1 := sf.Retrieve()
|
||||
m2 := af.Retrieve()
|
||||
messages := append(m1, m2...)
|
||||
for _, msg := range messages {
|
||||
if *fileExMode || len(msg.Payload) > 2048 {
|
||||
writeMessageToFile(*argSaveDir, msg)
|
||||
} else {
|
||||
reportedOnce := false
|
||||
if !*fileExMode && len(msg.Payload) <= 2048 {
|
||||
printMessageInfo(msg)
|
||||
reportedOnce = true
|
||||
}
|
||||
}
|
||||
|
||||
messages = af.Retrieve()
|
||||
for _, msg := range messages {
|
||||
if *fileExMode || len(msg.Payload) > 2048 {
|
||||
writeMessageToFile(*argSaveDir, msg)
|
||||
} else {
|
||||
printMessageInfo(msg)
|
||||
// All messages are saved upon specifying argSaveDir.
|
||||
// fileExMode only specifies how messages are displayed on the console after they are saved.
|
||||
// if fileExMode == true, only the hashes are displayed, since messages might be too big.
|
||||
if len(*argSaveDir) > 0 {
|
||||
writeMessageToFile(*argSaveDir, msg, !reportedOnce)
|
||||
}
|
||||
}
|
||||
case <-done:
|
||||
|
@ -587,7 +644,11 @@ func printMessageInfo(msg *whisper.ReceivedMessage) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
||||
func writeMessageToFile(dir string, msg *whisper.ReceivedMessage, show bool) {
|
||||
if len(dir) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
timestamp := fmt.Sprintf("%d", msg.Sent)
|
||||
name := fmt.Sprintf("%x", msg.EnvelopeHash)
|
||||
|
||||
|
@ -596,27 +657,32 @@ func writeMessageToFile(dir string, msg *whisper.ReceivedMessage) {
|
|||
address = crypto.PubkeyToAddress(*msg.Src)
|
||||
}
|
||||
|
||||
if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||
// message from myself: don't save, only report
|
||||
fmt.Printf("\n%s <%x>: message received: '%s'\n", timestamp, address, name)
|
||||
} else if len(dir) > 0 {
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, msg.Payload, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(msg.Payload))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("\n%s {%x}: big message received (%d bytes), but not saved: %s\n", timestamp, address, len(msg.Payload), name)
|
||||
env := shh.GetEnvelope(msg.EnvelopeHash)
|
||||
if env == nil {
|
||||
fmt.Printf("\nUnexpected error: envelope not found: %x\n", msg.EnvelopeHash)
|
||||
return
|
||||
}
|
||||
|
||||
// this is a sample code; uncomment if you don't want to save your own messages.
|
||||
//if whisper.IsPubKeyEqual(msg.Src, &asymKey.PublicKey) {
|
||||
// fmt.Printf("\n%s <%x>: message from myself received, not saved: '%s'\n", timestamp, address, name)
|
||||
// return
|
||||
//}
|
||||
|
||||
fullpath := filepath.Join(dir, name)
|
||||
err := ioutil.WriteFile(fullpath, env.Data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("\n%s {%x}: message received but not saved: %s\n", timestamp, address, err)
|
||||
} else if show {
|
||||
fmt.Printf("\n%s {%x}: message received and saved as '%s' (%d bytes)\n", timestamp, address, name, len(env.Data))
|
||||
}
|
||||
}
|
||||
|
||||
func requestExpiredMessagesLoop() {
|
||||
var key, peerID []byte
|
||||
var key, peerID, bloom []byte
|
||||
var timeLow, timeUpp uint32
|
||||
var t string
|
||||
var xt, empty whisper.TopicType
|
||||
var xt whisper.TopicType
|
||||
|
||||
keyID, err := shh.AddSymKeyFromPassword(msPassword)
|
||||
if err != nil {
|
||||
|
@ -632,25 +698,31 @@ func requestExpiredMessagesLoop() {
|
|||
for {
|
||||
timeLow = scanUint("Please enter the lower limit of the time range (unix timestamp): ")
|
||||
timeUpp = scanUint("Please enter the upper limit of the time range (unix timestamp): ")
|
||||
t = scanLine("Please enter the topic (hexadecimal): ")
|
||||
if len(t) >= whisper.TopicLength*2 {
|
||||
t = scanLine("Enter the topic (hex). Press enter to request all messages, regardless of the topic: ")
|
||||
if len(t) == whisper.TopicLength*2 {
|
||||
x, err := hex.DecodeString(t)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to parse the topic: %s", err)
|
||||
fmt.Printf("Failed to parse the topic: %s \n", err)
|
||||
continue
|
||||
}
|
||||
xt = whisper.BytesToTopic(x)
|
||||
bloom = whisper.TopicToBloom(xt)
|
||||
obfuscateBloom(bloom)
|
||||
} else if len(t) == 0 {
|
||||
bloom = whisper.MakeFullNodeBloom()
|
||||
} else {
|
||||
fmt.Println("Error: topic is invalid, request aborted")
|
||||
continue
|
||||
}
|
||||
|
||||
if timeUpp == 0 {
|
||||
timeUpp = 0xFFFFFFFF
|
||||
}
|
||||
|
||||
data := make([]byte, 8+whisper.TopicLength)
|
||||
data := make([]byte, 8, 8+whisper.BloomFilterSize)
|
||||
binary.BigEndian.PutUint32(data, timeLow)
|
||||
binary.BigEndian.PutUint32(data[4:], timeUpp)
|
||||
copy(data[8:], xt[:])
|
||||
if xt == empty {
|
||||
data = data[:8]
|
||||
}
|
||||
data = append(data, bloom...)
|
||||
|
||||
var params whisper.MessageParams
|
||||
params.PoW = *argServerPoW
|
||||
|
@ -684,3 +756,20 @@ func extractIDFromEnode(s string) []byte {
|
|||
}
|
||||
return n.ID[:]
|
||||
}
|
||||
|
||||
// obfuscateBloom adds 16 random bits to the the bloom
|
||||
// filter, in order to obfuscate the containing topics.
|
||||
// it does so deterministically within every session.
|
||||
// despite additional bits, it will match on average
|
||||
// 32000 times less messages than full node's bloom filter.
|
||||
func obfuscateBloom(bloom []byte) {
|
||||
const half = entropySize / 2
|
||||
for i := 0; i < half; i++ {
|
||||
x := int(entropy[i])
|
||||
if entropy[half+i] < 128 {
|
||||
x += 256
|
||||
}
|
||||
|
||||
bloom[x/8] = 1 << uint(x%8) // set the bit number X
|
||||
}
|
||||
}
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/common/big.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/common/big.go
generated
vendored
|
@ -25,6 +25,6 @@ var (
|
|||
Big3 = big.NewInt(3)
|
||||
Big0 = big.NewInt(0)
|
||||
Big32 = big.NewInt(32)
|
||||
Big256 = big.NewInt(0xff)
|
||||
Big256 = big.NewInt(256)
|
||||
Big257 = big.NewInt(257)
|
||||
)
|
||||
|
|
1
vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go
generated
vendored
1
vendor/github.com/ethereum/go-ethereum/common/compiler/solidity.go
generated
vendored
|
@ -65,7 +65,6 @@ type solcOutput struct {
|
|||
func (s *Solidity) makeArgs() []string {
|
||||
p := []string{
|
||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||
"--add-std", // include standard lib contracts
|
||||
"--optimize", // code optimizer switched on
|
||||
}
|
||||
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
|
||||
|
|
72
vendor/github.com/ethereum/go-ethereum/common/types.go
generated
vendored
72
vendor/github.com/ethereum/go-ethereum/common/types.go
generated
vendored
|
@ -18,10 +18,12 @@ package common
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
|
@ -45,9 +47,8 @@ func BytesToHash(b []byte) Hash {
|
|||
h.SetBytes(b)
|
||||
return h
|
||||
}
|
||||
func StringToHash(s string) Hash { return BytesToHash([]byte(s)) }
|
||||
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||
|
||||
// Get the string representation of the underlying hash
|
||||
func (h Hash) Str() string { return string(h[:]) }
|
||||
|
@ -143,9 +144,8 @@ func BytesToAddress(b []byte) Address {
|
|||
a.SetBytes(b)
|
||||
return a
|
||||
}
|
||||
func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) }
|
||||
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
|
||||
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
|
||||
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
|
||||
func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
|
||||
|
||||
// IsHexAddress verifies whether a string can represent a valid hex-encoded
|
||||
// Ethereum address or not.
|
||||
|
@ -240,3 +240,63 @@ func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
|
|||
func (a UnprefixedAddress) MarshalText() ([]byte, error) {
|
||||
return []byte(hex.EncodeToString(a[:])), nil
|
||||
}
|
||||
|
||||
// MixedcaseAddress retains the original string, which may or may not be
|
||||
// correctly checksummed
|
||||
type MixedcaseAddress struct {
|
||||
addr Address
|
||||
original string
|
||||
}
|
||||
|
||||
// NewMixedcaseAddress constructor (mainly for testing)
|
||||
func NewMixedcaseAddress(addr Address) MixedcaseAddress {
|
||||
return MixedcaseAddress{addr: addr, original: addr.Hex()}
|
||||
}
|
||||
|
||||
// NewMixedcaseAddressFromString is mainly meant for unit-testing
|
||||
func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) {
|
||||
if !IsHexAddress(hexaddr) {
|
||||
return nil, fmt.Errorf("Invalid address")
|
||||
}
|
||||
a := FromHex(hexaddr)
|
||||
return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses MixedcaseAddress
|
||||
func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error {
|
||||
if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(input, &ma.original)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the original value
|
||||
func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) {
|
||||
if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") {
|
||||
return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:]))
|
||||
}
|
||||
return json.Marshal(fmt.Sprintf("0x%s", ma.original))
|
||||
}
|
||||
|
||||
// Address returns the address
|
||||
func (ma *MixedcaseAddress) Address() Address {
|
||||
return ma.addr
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (ma *MixedcaseAddress) String() string {
|
||||
if ma.ValidChecksum() {
|
||||
return fmt.Sprintf("%s [chksum ok]", ma.original)
|
||||
}
|
||||
return fmt.Sprintf("%s [chksum INVALID]", ma.original)
|
||||
}
|
||||
|
||||
// ValidChecksum returns true if the address has valid checksum
|
||||
func (ma *MixedcaseAddress) ValidChecksum() bool {
|
||||
return ma.original == ma.addr.Hex()
|
||||
}
|
||||
|
||||
// Original returns the mixed-case input string
|
||||
func (ma *MixedcaseAddress) Original() string {
|
||||
return ma.original
|
||||
}
|
||||
|
|
101
vendor/github.com/ethereum/go-ethereum/compression/rle/read_write.go
generated
vendored
101
vendor/github.com/ethereum/go-ethereum/compression/rle/read_write.go
generated
vendored
|
@ -1,101 +0,0 @@
|
|||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package rle implements the run-length encoding used for Ethereum data.
|
||||
package rle
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
token byte = 0xfe
|
||||
emptyShaToken = 0xfd
|
||||
emptyListShaToken = 0xfe
|
||||
tokenToken = 0xff
|
||||
)
|
||||
|
||||
var empty = crypto.Keccak256([]byte(""))
|
||||
var emptyList = crypto.Keccak256([]byte{0x80})
|
||||
|
||||
func Decompress(dat []byte) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
for i := 0; i < len(dat); i++ {
|
||||
if dat[i] == token {
|
||||
if i+1 < len(dat) {
|
||||
switch dat[i+1] {
|
||||
case emptyShaToken:
|
||||
buf.Write(empty)
|
||||
case emptyListShaToken:
|
||||
buf.Write(emptyList)
|
||||
case tokenToken:
|
||||
buf.WriteByte(token)
|
||||
default:
|
||||
buf.Write(make([]byte, int(dat[i+1]-2)))
|
||||
}
|
||||
i++
|
||||
} else {
|
||||
return nil, errors.New("error reading bytes. token encountered without proceeding bytes")
|
||||
}
|
||||
} else {
|
||||
buf.WriteByte(dat[i])
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func compressChunk(dat []byte) (ret []byte, n int) {
|
||||
switch {
|
||||
case dat[0] == token:
|
||||
return []byte{token, tokenToken}, 1
|
||||
case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0:
|
||||
j := 0
|
||||
for j <= 254 && j < len(dat) {
|
||||
if dat[j] != 0 {
|
||||
break
|
||||
}
|
||||
j++
|
||||
}
|
||||
return []byte{token, byte(j + 2)}, j
|
||||
case len(dat) >= 32:
|
||||
if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) {
|
||||
return []byte{token, emptyShaToken}, 32
|
||||
} else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) {
|
||||
return []byte{token, emptyListShaToken}, 32
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
return dat[:1], 1
|
||||
}
|
||||
}
|
||||
|
||||
func Compress(dat []byte) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
i := 0
|
||||
for i < len(dat) {
|
||||
b, n := compressChunk(dat[i:])
|
||||
buf.Write(b)
|
||||
i += n
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
3
vendor/github.com/ethereum/go-ethereum/consensus/consensus.go
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/consensus/consensus.go
generated
vendored
|
@ -18,12 +18,13 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// ChainReader defines a small collection of methods needed to access the local
|
||||
|
|
43
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go
generated
vendored
43
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm.go
generated
vendored
|
@ -19,6 +19,7 @@ package ethash
|
|||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
@ -47,6 +48,48 @@ const (
|
|||
loopAccesses = 64 // Number of accesses in hashimoto loop
|
||||
)
|
||||
|
||||
// cacheSize returns the size of the ethash verification cache that belongs to a certain
|
||||
// block number.
|
||||
func cacheSize(block uint64) uint64 {
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return cacheSizes[epoch]
|
||||
}
|
||||
return calcCacheSize(epoch)
|
||||
}
|
||||
|
||||
// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
|
||||
// however, we always take the highest prime below the linearly growing threshold in order
|
||||
// to reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func calcCacheSize(epoch int) uint64 {
|
||||
size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
|
||||
for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
|
||||
size -= 2 * hashBytes
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// datasetSize returns the size of the ethash mining dataset that belongs to a certain
|
||||
// block number.
|
||||
func datasetSize(block uint64) uint64 {
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return datasetSizes[epoch]
|
||||
}
|
||||
return calcDatasetSize(epoch)
|
||||
}
|
||||
|
||||
// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
|
||||
// however, we always take the highest prime below the linearly growing threshold in order
|
||||
// to reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func calcDatasetSize(epoch int) uint64 {
|
||||
size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
|
||||
for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
|
||||
size -= 2 * mixBytes
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// hasher is a repetitive hasher allowing the same hash data structures to be
|
||||
// reused between hash runs instead of requiring new ones to be created.
|
||||
type hasher func(dest []byte, data []byte)
|
||||
|
|
47
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm_go1.7.go
generated
vendored
47
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm_go1.7.go
generated
vendored
|
@ -1,47 +0,0 @@
|
|||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package ethash
|
||||
|
||||
// cacheSize calculates and returns the size of the ethash verification cache that
|
||||
// belongs to a certain block number. The cache size grows linearly, however, we
|
||||
// always take the highest prime below the linearly growing threshold in order to
|
||||
// reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func cacheSize(block uint64) uint64 {
|
||||
// If we have a pre-generated value, use that
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return cacheSizes[epoch]
|
||||
}
|
||||
// We don't have a way to verify primes fast before Go 1.8
|
||||
panic("fast prime testing unsupported in Go < 1.8")
|
||||
}
|
||||
|
||||
// datasetSize calculates and returns the size of the ethash mining dataset that
|
||||
// belongs to a certain block number. The dataset size grows linearly, however, we
|
||||
// always take the highest prime below the linearly growing threshold in order to
|
||||
// reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func datasetSize(block uint64) uint64 {
|
||||
// If we have a pre-generated value, use that
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return datasetSizes[epoch]
|
||||
}
|
||||
// We don't have a way to verify primes fast before Go 1.8
|
||||
panic("fast prime testing unsupported in Go < 1.8")
|
||||
}
|
63
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm_go1.8.go
generated
vendored
63
vendor/github.com/ethereum/go-ethereum/consensus/ethash/algorithm_go1.8.go
generated
vendored
|
@ -1,63 +0,0 @@
|
|||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package ethash
|
||||
|
||||
import "math/big"
|
||||
|
||||
// cacheSize returns the size of the ethash verification cache that belongs to a certain
|
||||
// block number.
|
||||
func cacheSize(block uint64) uint64 {
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return cacheSizes[epoch]
|
||||
}
|
||||
return calcCacheSize(epoch)
|
||||
}
|
||||
|
||||
// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
|
||||
// however, we always take the highest prime below the linearly growing threshold in order
|
||||
// to reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func calcCacheSize(epoch int) uint64 {
|
||||
size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
|
||||
for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
|
||||
size -= 2 * hashBytes
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// datasetSize returns the size of the ethash mining dataset that belongs to a certain
|
||||
// block number.
|
||||
func datasetSize(block uint64) uint64 {
|
||||
epoch := int(block / epochLength)
|
||||
if epoch < maxEpoch {
|
||||
return datasetSizes[epoch]
|
||||
}
|
||||
return calcDatasetSize(epoch)
|
||||
}
|
||||
|
||||
// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
|
||||
// however, we always take the highest prime below the linearly growing threshold in order
|
||||
// to reduce the risk of accidental regularities leading to cyclic behavior.
|
||||
func calcDatasetSize(epoch int) uint64 {
|
||||
size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
|
||||
for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
|
||||
size -= 2 * mixBytes
|
||||
}
|
||||
return size
|
||||
}
|
12
vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go
generated
vendored
12
vendor/github.com/ethereum/go-ethereum/consensus/ethash/consensus.go
generated
vendored
|
@ -53,7 +53,6 @@ var (
|
|||
errDuplicateUncle = errors.New("duplicate uncle")
|
||||
errUncleIsAncestor = errors.New("uncle is ancestor")
|
||||
errDanglingUncle = errors.New("uncle's parent is not ancestor")
|
||||
errNonceOutOfRange = errors.New("nonce out of range")
|
||||
errInvalidDifficulty = errors.New("non-positive difficulty")
|
||||
errInvalidMixDigest = errors.New("invalid mix digest")
|
||||
errInvalidPoW = errors.New("invalid proof-of-work")
|
||||
|
@ -356,7 +355,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int {
|
|||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||
x.Set(params.MinimumDifficulty)
|
||||
}
|
||||
// calculate a fake block numer for the ice-age delay:
|
||||
// calculate a fake block number for the ice-age delay:
|
||||
// https://github.com/ethereum/EIPs/pull/669
|
||||
// fake_block_number = min(0, block.number - 3_000_000
|
||||
fakeBlockNumber := new(big.Int)
|
||||
|
@ -474,18 +473,13 @@ func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Head
|
|||
if ethash.shared != nil {
|
||||
return ethash.shared.VerifySeal(chain, header)
|
||||
}
|
||||
// Sanity check that the block number is below the lookup table size (60M blocks)
|
||||
number := header.Number.Uint64()
|
||||
if number/epochLength >= maxEpoch {
|
||||
// Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
|
||||
return errNonceOutOfRange
|
||||
}
|
||||
// Ensure that we have a valid difficulty for the block
|
||||
if header.Difficulty.Sign() <= 0 {
|
||||
return errInvalidDifficulty
|
||||
}
|
||||
|
||||
// Recompute the digest and PoW value and verify against the header
|
||||
number := header.Number.Uint64()
|
||||
|
||||
cache := ethash.cache(number)
|
||||
size := datasetSize(number)
|
||||
if ethash.config.PowMode == ModeTest {
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/consensus/ethash/ethash.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/consensus/ethash/ethash.go
generated
vendored
|
@ -35,9 +35,9 @@ import (
|
|||
mmap "github.com/edsrzf/mmap-go"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/hashicorp/golang-lru/simplelru"
|
||||
metrics "github.com/rcrowley/go-metrics"
|
||||
)
|
||||
|
||||
var ErrInvalidDumpMagic = errors.New("invalid dump magic")
|
||||
|
|
2
vendor/github.com/ethereum/go-ethereum/console/bridge.go
generated
vendored
2
vendor/github.com/ethereum/go-ethereum/console/bridge.go
generated
vendored
|
@ -87,7 +87,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
|||
// OpenWallet is a wrapper around personal.openWallet which can interpret and
|
||||
// react to certain error messages, such as the Trezor PIN matrix request.
|
||||
func (b *bridge) OpenWallet(call otto.FunctionCall) (response otto.Value) {
|
||||
// Make sure we have an wallet specified to open
|
||||
// Make sure we have a wallet specified to open
|
||||
if !call.Argument(0).IsString() {
|
||||
throwJSException("first argument must be the wallet URL to open")
|
||||
}
|
||||
|
|
3
vendor/github.com/ethereum/go-ethereum/console/console.go
generated
vendored
3
vendor/github.com/ethereum/go-ethereum/console/console.go
generated
vendored
|
@ -26,6 +26,7 @@ import (
|
|||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/ethereum/go-ethereum/internal/jsre"
|
||||
"github.com/ethereum/go-ethereum/internal/web3ext"
|
||||
|
@ -332,7 +333,7 @@ func (c *Console) Interactive() {
|
|||
}()
|
||||
// Monitor Ctrl-C too in case the input is empty and we need to bail
|
||||
abort := make(chan os.Signal, 1)
|
||||
signal.Notify(abort, os.Interrupt)
|
||||
signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// Start sending prompts to the user and reading back inputs
|
||||
for {
|
||||
|
|
1
vendor/github.com/ethereum/go-ethereum/containers/vagrant/.gitignore
generated
vendored
1
vendor/github.com/ethereum/go-ethereum/containers/vagrant/.gitignore
generated
vendored
|
@ -1 +0,0 @@
|
|||
.vagrant
|
38
vendor/github.com/ethereum/go-ethereum/containers/vagrant/Vagrantfile
generated
vendored
38
vendor/github.com/ethereum/go-ethereum/containers/vagrant/Vagrantfile
generated
vendored
|
@ -1,38 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
require 'yaml'
|
||||
|
||||
VAGRANTFILE_API_VERSION = 2
|
||||
VM_RAM = 2048
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.define "ubuntu", :primary => true do |ubuntu|
|
||||
ubuntu.vm.box = "ubuntu/trusty64"
|
||||
ubuntu.vm.provision "shell", :path => "provisioners/shell/ubuntu.sh"
|
||||
end
|
||||
|
||||
config.vm.define "debian", :primary => true do |debian|
|
||||
debian.vm.box = "debian/jessie64"
|
||||
debian.vm.provision "shell", :path => "provisioners/shell/debian.sh"
|
||||
end
|
||||
|
||||
config.vm.define "centos", :autostart => false do |centos|
|
||||
centos.vm.box = "centos/7"
|
||||
centos.vm.provision "shell", :path => "provisioners/shell/centos.sh"
|
||||
end
|
||||
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
vb.memory = VM_RAM
|
||||
end
|
||||
|
||||
config.vm.provider "libvirt" do |lv|
|
||||
lv.memory = VM_RAM
|
||||
|
||||
config.vm.synced_folder ".", "/home/vagrant/sync", :disabled => true
|
||||
end
|
||||
|
||||
config.vm.synced_folder ".", "/vagrant", :disabled => true
|
||||
config.vm.synced_folder "../../", "/home/vagrant/go/src/github.com/ethereum/go-ethereum"
|
||||
end
|
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/centos.sh
generated
vendored
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/centos.sh
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo yum install -y git wget
|
||||
sudo yum update -y
|
||||
|
||||
wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
|
||||
|
||||
GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
|
||||
|
||||
echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
|
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/debian.sh
generated
vendored
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/debian.sh
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo apt-get install -y build-essential git-all wget
|
||||
sudo apt-get update
|
||||
|
||||
wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
|
||||
|
||||
GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
|
||||
|
||||
echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
|
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/ubuntu.sh
generated
vendored
11
vendor/github.com/ethereum/go-ethereum/containers/vagrant/provisioners/shell/ubuntu.sh
generated
vendored
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo apt-get install -y build-essential git-all wget
|
||||
sudo apt-get update
|
||||
|
||||
wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
|
||||
sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
|
||||
|
||||
GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
|
||||
|
||||
echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue