diff --git a/cmd/node-canary/main.go b/cmd/node-canary/main.go index ab1441b3d..fbd91425e 100644 --- a/cmd/node-canary/main.go +++ b/cmd/node-canary/main.go @@ -271,6 +271,7 @@ func makeNodeConfig() (*params.NodeConfig, error) { nodeConfig.LogFile = *logFile } + nodeConfig.EnableNTPSync = true nodeConfig.NoDiscovery = true nodeConfig.ListenAddr = "" if *staticEnodeAddr != "" { @@ -291,7 +292,6 @@ func whisperConfig(nodeConfig *params.NodeConfig) (*params.NodeConfig, error) { whisperConfig.LightClient = true whisperConfig.MinimumPoW = *minPow whisperConfig.TTL = *ttl - whisperConfig.EnableNTPSync = true return nodeConfig, nil } diff --git a/eth-node/bridge/geth/envelope.go b/eth-node/bridge/geth/envelope.go index 884760b06..64b9306bf 100644 --- a/eth-node/bridge/geth/envelope.go +++ b/eth-node/bridge/geth/envelope.go @@ -2,29 +2,102 @@ package gethbridge import ( "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/waku" "github.com/status-im/status-go/whisper/v6" ) -type gethEnvelopeWrapper struct { - envelope *whisper.Envelope +type whisperEnvelope struct { + env *whisper.Envelope } -// NewGethEnvelopeWrapper returns an object that wraps Geth's Envelope in a types interface -func NewGethEnvelopeWrapper(e *whisper.Envelope) types.Envelope { - return &gethEnvelopeWrapper{ - envelope: e, +// NewWhisperEnvelope returns an object that wraps Geth's Whisper Envelope in a types interface. +func NewWhisperEnvelope(e *whisper.Envelope) types.Envelope { + return &whisperEnvelope{env: e} +} + +func UnwrapWhisperEnvelope(e types.Envelope) (*whisper.Envelope, bool) { + if env, ok := e.(*whisperEnvelope); ok { + return env.env, true } + return nil, false } -// GetGethEnvelopeFrom retrieves the underlying whisper Envelope struct from a wrapped Envelope interface -func GetGethEnvelopeFrom(f types.Envelope) *whisper.Envelope { - return f.(*gethEnvelopeWrapper).envelope +func MustUnwrapWhisperEnvelope(e types.Envelope) *whisper.Envelope { + return e.(*whisperEnvelope).env } -func (w *gethEnvelopeWrapper) Hash() types.Hash { - return types.Hash(w.envelope.Hash()) +func (w *whisperEnvelope) Hash() types.Hash { + return types.Hash(w.env.Hash()) } -func (w *gethEnvelopeWrapper) Bloom() []byte { - return w.envelope.Bloom() +func (w *whisperEnvelope) Bloom() []byte { + return w.env.Bloom() +} + +func (w *whisperEnvelope) PoW() float64 { + return w.env.PoW() +} + +func (w *whisperEnvelope) Expiry() uint32 { + return w.env.Expiry +} + +func (w *whisperEnvelope) TTL() uint32 { + return w.env.TTL +} + +func (w *whisperEnvelope) Topic() types.TopicType { + return types.TopicType(w.env.Topic) +} + +func (w *whisperEnvelope) Size() int { + return len(w.env.Data) +} + +type wakuEnvelope struct { + env *waku.Envelope +} + +// NewWakuEnvelope returns an object that wraps Geth's Waku Envelope in a types interface. +func NewWakuEnvelope(e *waku.Envelope) types.Envelope { + return &wakuEnvelope{env: e} +} + +func UnwrapWakuEnvelope(e types.Envelope) (*waku.Envelope, bool) { + if env, ok := e.(*wakuEnvelope); ok { + return env.env, true + } + return nil, false +} + +func MustUnwrapWakuEnvelope(e types.Envelope) *waku.Envelope { + return e.(*wakuEnvelope).env +} + +func (w *wakuEnvelope) Hash() types.Hash { + return types.Hash(w.env.Hash()) +} + +func (w *wakuEnvelope) Bloom() []byte { + return w.env.Bloom() +} + +func (w *wakuEnvelope) PoW() float64 { + return w.env.PoW() +} + +func (w *wakuEnvelope) Expiry() uint32 { + return w.env.Expiry +} + +func (w *wakuEnvelope) TTL() uint32 { + return w.env.TTL +} + +func (w *wakuEnvelope) Topic() types.TopicType { + return types.TopicType(w.env.Topic) +} + +func (w *wakuEnvelope) Size() int { + return len(w.env.Data) } diff --git a/eth-node/bridge/geth/whisper.go b/eth-node/bridge/geth/whisper.go index 53e9bf005..8e64db81c 100644 --- a/eth-node/bridge/geth/whisper.go +++ b/eth-node/bridge/geth/whisper.go @@ -166,7 +166,7 @@ func (w *gethWhisperWrapper) SendMessagesRequest(peerID []byte, r types.Messages // which are not supposed to be forwarded any further. // The whisper protocol is agnostic of the format and contents of envelope. func (w *gethWhisperWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, envelope types.Envelope, timeout time.Duration) error { - return w.whisper.RequestHistoricMessagesWithTimeout(peerID, GetGethEnvelopeFrom(envelope), timeout) + return w.whisper.RequestHistoricMessagesWithTimeout(peerID, MustUnwrapWhisperEnvelope(envelope), timeout) } // SyncMessages can be sent between two Mail Servers and syncs envelopes between them. diff --git a/eth-node/go.mod b/eth-node/go.mod index b007a0c3c..2edd418de 100644 --- a/eth-node/go.mod +++ b/eth-node/go.mod @@ -8,13 +8,16 @@ replace github.com/status-im/status-go/extkeys => ../extkeys replace github.com/status-im/status-go/whisper/v6 => ../whisper +replace github.com/status-im/status-go/waku => ../waku + require ( github.com/ethereum/go-ethereum v1.9.5 github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f github.com/status-im/doubleratchet v3.0.0+incompatible + github.com/status-im/status-go/waku v1.0.0 github.com/status-im/status-go/whisper/v6 v6.0.1 // indirect github.com/stretchr/testify v1.4.0 github.com/wealdtech/go-ens/v3 v3.0.9 go.uber.org/zap v1.13.0 - golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c ) diff --git a/eth-node/go.sum b/eth-node/go.sum index 106d0dc88..f603ee835 100644 --- a/eth-node/go.sum +++ b/eth-node/go.sum @@ -1,9 +1,13 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/azure-pipeline-go v0.0.0-20180607212504-7571e8eb0876/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= github.com/Azure/azure-storage-blob-go v0.0.0-20180712005634-eaae161d9d5e/go.mod h1:x2mtS6O3mnMEZOJp7d7oldh8IvatBrMfReiyQ+cKgKY= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -16,11 +20,15 @@ github.com/allegro/bigcache v1.1.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2uc github.com/allegro/bigcache v1.2.0 h1:qDaE0QoF29wKBb3+pXFrJFy1ihe5OT9OiXhg1t85SxM= github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7 h1:6TQIK3K21/HnYLp+TAI6fjQ1YeH+KgLZbrFJwUjVrnQ= github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -44,6 +52,7 @@ github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -56,12 +65,16 @@ github.com/dgrijalva/jwt-go v0.0.0-20170201225849-2268707a8f08/go.mod h1:E3ru+11 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/docker v0.0.0-20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo= github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= @@ -69,6 +82,7 @@ github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a h1:1znxn4+q2MrEdTk1eCk github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= @@ -83,6 +97,8 @@ github.com/go-stack/stack v1.5.4/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= @@ -93,6 +109,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -101,6 +118,7 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -113,9 +131,12 @@ github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7 github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -127,6 +148,8 @@ github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8u github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -135,6 +158,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= @@ -177,6 +201,8 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opentracing/opentracing-go v0.0.0-20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY= @@ -184,27 +210,33 @@ github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7ir github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/peterh/liner v0.0.0-20170902204657-a37ad3984311/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e h1:+RHxT/gm0O3UF7nLJbdNzAmULvCFt4XfXHWzh3XI/zs= github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= @@ -213,7 +245,9 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -247,6 +281,9 @@ github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2 h1:GnOzE5fEFN3b2z github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 h1:kjbwitOGH46vD01f2s3leBfrMnePQa3NSAIlW35MvY8= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9/go.mod h1:EcGP24b8DY+bWHnpfJDP7fM+o8Nmz4fYH0l2xTtNr3I= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= @@ -261,6 +298,10 @@ github.com/wealdtech/go-string2eth v1.0.0 h1:jY6b1MVqU6k2Uw/kvcU1Y9/3dDyXfPzZrOF github.com/wealdtech/go-string2eth v1.0.0/go.mod h1:UZA/snEybGcD6n+Pl+yoDjmexlEJ6dtoS9myfM83Ol4= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= @@ -274,12 +315,15 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M= golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIoF2s4qxv0xSSS0BVZUE/ss= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -293,12 +337,15 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -306,22 +353,32 @@ golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405 h1:829vOVxxusYHC+IqBtkX5mbKtsY9fheQiQn0MZRVLfQ= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -330,11 +387,17 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -344,5 +407,6 @@ gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/eth-node/types/envelopes.go b/eth-node/types/envelopes.go index 997343330..7f1cb424f 100644 --- a/eth-node/types/envelopes.go +++ b/eth-node/types/envelopes.go @@ -5,6 +5,11 @@ package types type Envelope interface { Hash() Hash // Cached hash of the envelope to avoid rehashing every time. Bloom() []byte + PoW() float64 + Expiry() uint32 + TTL() uint32 + Topic() TopicType + Size() int } // EventType used to define known envelope events. diff --git a/eth-node/types/hash.go b/eth-node/types/hash.go index 2b5dec17c..5c9d7c0e8 100644 --- a/eth-node/types/hash.go +++ b/eth-node/types/hash.go @@ -50,7 +50,7 @@ func (h Hash) Bytes() []byte { return h[:] } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. -func (h *Hash) String() string { +func (h Hash) String() string { return h.Hex() } diff --git a/go.mod b/go.mod index e15295cb2..d5ae49d7e 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,8 @@ replace github.com/status-im/status-go/eth-node => ./eth-node replace github.com/status-im/status-go/whisper/v6 => ./whisper +replace github.com/status-im/status-go/waku => ./waku + require ( github.com/beevik/ntp v0.2.0 github.com/ethereum/go-ethereum v1.9.5 @@ -41,14 +43,14 @@ require ( github.com/status-im/status-go/eth-node v1.0.0 github.com/status-im/status-go/extkeys v1.0.0 github.com/status-im/status-go/protocol v1.0.1 + github.com/status-im/status-go/waku v1.0.0 github.com/status-im/status-go/whisper/v6 v6.0.1 github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501 github.com/stretchr/testify v1.4.0 github.com/syndtr/goleveldb v1.0.0 go.uber.org/zap v1.13.0 - golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 // indirect - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect golang.org/x/tools v0.0.0-20191213032237-7093a17b0467 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v9 v9.29.1 diff --git a/go.sum b/go.sum index 53a1d07fd..8742cc1d2 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= @@ -19,23 +20,31 @@ github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcy github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v0.0.0-20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.0 h1:qDaE0QoF29wKBb3+pXFrJFy1ihe5OT9OiXhg1t85SxM= github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 h1:tS7jSmwRqSxTnonTRlDD1oHo6Q9YOK4xHS9/v4L56eg= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 h1:ZdRuixFqR3mfx4FHzclG3COrRgWrYq0VhNgIoYoObcM= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= @@ -130,6 +139,8 @@ github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa h1:o8OuEkracbk3qH6 github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo= github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo= +github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= @@ -141,6 +152,7 @@ github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= @@ -169,6 +181,7 @@ github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k= github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -216,6 +229,7 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= @@ -231,6 +245,7 @@ github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= @@ -253,6 +268,8 @@ github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQ github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -261,6 +278,7 @@ github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s= @@ -282,6 +300,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -295,6 +315,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -496,9 +517,15 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -515,17 +542,20 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v0.0.0-20170902204657-a37ad3984311/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -536,12 +566,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= @@ -558,6 +590,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315 h1:H3hCXwP92pH/hSgNrCLtjxvsKJ50sq26nICbZuoR1tQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315/go.mod h1:ZbKa3zlLnhGF1dAeJtMSoNtM5LgFQnqzq8eYH3uYYkU= @@ -622,7 +656,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 h1:kjbwitOGH46vD01f2s3leBfrMnePQa3NSAIlW35MvY8= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9/go.mod h1:EcGP24b8DY+bWHnpfJDP7fM+o8Nmz4fYH0l2xTtNr3I= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= @@ -656,6 +693,8 @@ github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVT github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -683,6 +722,7 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -692,6 +732,8 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -719,6 +761,7 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -745,11 +788,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk= @@ -772,7 +818,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 h1:LCmXVkvpQCDj724eX6irUTPCJP5GelFHxqGSWL2D1R0= @@ -797,7 +845,11 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= @@ -810,6 +862,11 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= @@ -818,6 +875,7 @@ gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5 h1:VWXVtmkY4Y gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= @@ -833,5 +891,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/mailserver/cleaner_test.go b/mailserver/cleaner_test.go index ce91d028b..a7b4c8d87 100644 --- a/mailserver/cleaner_test.go +++ b/mailserver/cleaner_test.go @@ -19,7 +19,7 @@ func TestCleaner(t *testing.T) { now := time.Now() server := setupTestServer(t) defer server.Close() - cleaner := newDBCleaner(server.db, time.Hour) + cleaner := newDBCleaner(server.ms.db, time.Hour) archiveEnvelope(t, now.Add(-10*time.Second), server) archiveEnvelope(t, now.Add(-3*time.Second), server) @@ -27,9 +27,9 @@ func TestCleaner(t *testing.T) { testMessagesCount(t, 3, server) - testPrune(t, now.Add(-5*time.Second), 1, cleaner, server) - testPrune(t, now.Add(-2*time.Second), 1, cleaner, server) - testPrune(t, now, 1, cleaner, server) + testPrune(t, now.Add(-5*time.Second), 1, cleaner) + testPrune(t, now.Add(-2*time.Second), 1, cleaner) + testPrune(t, now, 1, cleaner) testMessagesCount(t, 0, server) } @@ -39,7 +39,7 @@ func TestCleanerSchedule(t *testing.T) { server := setupTestServer(t) defer server.Close() - cleaner := newDBCleaner(server.db, time.Hour) + cleaner := newDBCleaner(server.ms.db, time.Hour) cleaner.period = time.Millisecond * 10 cleaner.Start() defer cleaner.Stop() @@ -60,7 +60,7 @@ func benchmarkCleanerPrune(b *testing.B, messages int, batchSize int) { server := setupTestServer(t) defer server.Close() - cleaner := newDBCleaner(server.db, time.Hour) + cleaner := newDBCleaner(server.ms.db, time.Hour) cleaner.batchSize = batchSize for i := 0; i < messages; i++ { @@ -68,7 +68,7 @@ func benchmarkCleanerPrune(b *testing.B, messages int, batchSize int) { } for i := 0; i < b.N; i++ { - testPrune(t, now, 0, cleaner, server) + testPrune(t, now, 0, cleaner) } } @@ -88,16 +88,19 @@ func BenchmarkCleanerPruneM100_000_B100(b *testing.B) { benchmarkCleanerPrune(b, 100000, 100) } -func setupTestServer(t *testing.T) *WMailServer { - var s WMailServer +func setupTestServer(t *testing.T) *WhisperMailServer { + var s WhisperMailServer db, _ := leveldb.Open(storage.NewMemStorage(), nil) - s.db = &LevelDB{ldb: db} - s.pow = powRequirement + s.ms = &mailServer{ + db: &LevelDB{ldb: db}, + adapter: &whisperAdapter{}, + } + s.minRequestPoW = powRequirement return &s } -func archiveEnvelope(t *testing.T, sentTime time.Time, server *WMailServer) *whisper.Envelope { +func archiveEnvelope(t *testing.T, sentTime time.Time, server *WhisperMailServer) *whisper.Envelope { env, err := generateEnvelope(sentTime) require.NoError(t, err) server.Archive(env) @@ -105,14 +108,14 @@ func archiveEnvelope(t *testing.T, sentTime time.Time, server *WMailServer) *whi return env } -func testPrune(t *testing.T, u time.Time, expected int, c *dbCleaner, s *WMailServer) { +func testPrune(t *testing.T, u time.Time, expected int, c *dbCleaner) { n, err := c.PruneEntriesOlderThan(u) require.NoError(t, err) require.Equal(t, expected, n) } -func testMessagesCount(t *testing.T, expected int, s *WMailServer) { - count := countMessages(t, s.db) +func testMessagesCount(t *testing.T, expected int, s *WhisperMailServer) { + count := countMessages(t, s.ms.db) require.Equal(t, expected, count, fmt.Sprintf("expected %d message, got: %d", expected, count)) } diff --git a/mailserver/mailserver.go b/mailserver/mailserver.go index 174b0564d..f9e6bf2d2 100644 --- a/mailserver/mailserver.go +++ b/mailserver/mailserver.go @@ -17,29 +17,31 @@ package mailserver import ( + "crypto/ecdsa" "encoding/binary" "errors" "fmt" "math/rand" + "reflect" "sync" - "time" + prom "github.com/prometheus/client_golang/prometheus" + "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" - + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" + "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/params" + "github.com/status-im/status-go/waku" "github.com/status-im/status-go/whisper/v6" - - prom "github.com/prometheus/client_golang/prometheus" ) const ( maxQueryRange = 24 * time.Hour - defaultLimit = 2000 + maxQueryLimit = 1000 // When we default the upper limit, we want to extend the range a bit // to accommodate for envelopes with slightly higher timestamp, in seconds whisperTTLSafeThreshold = 60 @@ -57,95 +59,136 @@ const ( processRequestTimeout = time.Minute ) -// WMailServer whisper mailserver. -type WMailServer struct { - db DB - w *whisper.Whisper - pow float64 - symFilter *whisper.Filter - asymFilter *whisper.Filter - - muRateLimiter sync.RWMutex - rateLimiter *rateLimiter - - cleaner *dbCleaner // removes old envelopes +type Config struct { + // DataDir points to a directory where mailserver's data is stored. + DataDir string + // Password is used to create a symmetric key to decrypt requests. + Password string + // AsymKey is an asymmetric key to decrypt requests. + AsymKey string + // MininumPoW is a minimum PoW for requests. + MinimumPoW float64 + // RateLimit is a maximum number of requests per second from a peer. + RateLimit int + // DataRetention specifies a number of days an envelope should be stored for. + DataRetention int + PostgresEnabled bool + PostgresURI string } -var _ whisper.MailServer = (*WMailServer)(nil) +// ----------------- +// WhisperMailServer +// ----------------- -// Init initializes mailServer. -func (s *WMailServer) Init(shh *whisper.Whisper, config *params.WhisperConfig) error { - if len(config.DataDir) == 0 { - return errDirectoryNotProvided +type WhisperMailServer struct { + ms *mailServer + shh *whisper.Whisper + minRequestPoW float64 + + symFilter *whisper.Filter + asymFilter *whisper.Filter +} + +func (s *WhisperMailServer) Init(shh *whisper.Whisper, cfg *params.WhisperConfig) error { + s.shh = shh + s.minRequestPoW = cfg.MinimumPoW + + config := Config{ + DataDir: cfg.DataDir, + Password: cfg.MailServerPassword, + AsymKey: cfg.MailServerAsymKey, + MinimumPoW: cfg.MinimumPoW, + DataRetention: cfg.MailServerDataRetention, + RateLimit: cfg.MailServerRateLimit, + PostgresEnabled: cfg.DatabaseConfig.PGConfig.Enabled, + PostgresURI: cfg.DatabaseConfig.PGConfig.URI, } - - if len(config.MailServerPassword) == 0 && len(config.MailServerAsymKey) == 0 { - return errDecryptionMethodNotProvided - } - - s.w = shh - s.pow = config.MinimumPoW - - if err := s.setupRequestMessageDecryptor(config); err != nil { + var err error + s.ms, err = newMailServer( + config, + &whisperAdapter{}, + &whisperService{Whisper: shh}, + ) + if err != nil { return err } - if config.MailServerRateLimit > 0 { - s.setupRateLimiter(time.Duration(config.MailServerRateLimit) * time.Second) - } - - // Open database in the last step in order not to init with error - // and leave the database open by accident. - if config.DatabaseConfig.PGConfig.Enabled { - log.Info("Connecting to postgres database") - database, err := NewPostgresDB(config) - if err != nil { - return fmt.Errorf("open DB: %s", err) - } - s.db = database - log.Info("Connected to postgres database") - } else { - // Defaults to LevelDB - database, err := NewLevelDB(config) - if err != nil { - return fmt.Errorf("open DB: %s", err) - } - s.db = database - } - - if config.MailServerDataRetention > 0 { - // MailServerDataRetention is a number of days. - s.setupCleaner(time.Duration(config.MailServerDataRetention) * time.Hour * 24) + if err := s.setupDecryptor(config.Password, config.AsymKey); err != nil { + return err } return nil } -// setupRateLimiter in case limit is bigger than 0 it will setup an automated -// limit db cleanup. -func (s *WMailServer) setupRateLimiter(limit time.Duration) { - s.rateLimiter = newRateLimiter(limit) - s.rateLimiter.Start() +func (s *WhisperMailServer) Close() { + if s.ms != nil { + s.ms.Close() + } } -func (s *WMailServer) setupCleaner(retention time.Duration) { - s.cleaner = newDBCleaner(s.db, retention) - s.cleaner.Start() +func (s *WhisperMailServer) Archive(env *whisper.Envelope) { + s.ms.Archive(gethbridge.NewWhisperEnvelope(env)) } -// setupRequestMessageDecryptor setup a Whisper filter to decrypt -// incoming Whisper requests. -func (s *WMailServer) setupRequestMessageDecryptor(config *params.WhisperConfig) error { +// DEPRECATED; user Deliver instead +func (s *WhisperMailServer) DeliverMail(peerID []byte, req *whisper.Envelope) { + payload, err := s.decodeRequest(peerID, req) + if err != nil { + log.Debug( + "[mailserver:DeliverMail] failed to decode request", + "err", err, + "peerID", peerID, + "requestID", req.Hash().String(), + ) + payload, err = s.decompositeRequest(peerID, req) + } + if err != nil { + deliveryFailuresCounter.WithLabelValues("validation").Inc() + log.Error( + "[mailserver:DeliverMail] request failed validaton", + "peerID", peerID, + "requestID", req.Hash().String(), + "err", err, + ) + s.ms.sendHistoricMessageErrorResponse(types.BytesToHash(peerID), types.Hash(req.Hash()), err) + return + } + + s.ms.DeliverMail(types.BytesToHash(peerID), types.Hash(req.Hash()), payload) +} + +func (s *WhisperMailServer) Deliver(peerID []byte, req whisper.MessagesRequest) { + s.ms.DeliverMail(types.BytesToHash(peerID), types.BytesToHash(req.ID), MessagesRequestPayload{ + Lower: req.From, + Upper: req.To, + Bloom: req.Bloom, + Limit: req.Limit, + Cursor: req.Cursor, + Batch: true, + }) +} + +func (s *WhisperMailServer) SyncMail(peerID []byte, req whisper.SyncMailRequest) error { + return s.ms.SyncMail(types.BytesToHash(peerID), MessagesRequestPayload{ + Lower: req.Lower, + Upper: req.Upper, + Bloom: req.Bloom, + Limit: req.Limit, + Cursor: req.Cursor, + }) +} + +func (s *WhisperMailServer) setupDecryptor(password, asymKey string) error { s.symFilter = nil s.asymFilter = nil - if config.MailServerPassword != "" { - keyID, err := s.w.AddSymKeyFromPassword(config.MailServerPassword) + if password != "" { + keyID, err := s.shh.AddSymKeyFromPassword(password) if err != nil { return fmt.Errorf("create symmetric key: %v", err) } - symKey, err := s.w.GetSymKey(keyID) + symKey, err := s.shh.GetSymKey(keyID) if err != nil { return fmt.Errorf("save symmetric key: %v", err) } @@ -153,8 +196,8 @@ func (s *WMailServer) setupRequestMessageDecryptor(config *params.WhisperConfig) s.symFilter = &whisper.Filter{KeySym: symKey} } - if config.MailServerAsymKey != "" { - keyAsym, err := crypto.HexToECDSA(config.MailServerAsymKey) + if asymKey != "" { + keyAsym, err := crypto.HexToECDSA(asymKey) if err != nil { return err } @@ -164,119 +207,544 @@ func (s *WMailServer) setupRequestMessageDecryptor(config *params.WhisperConfig) return nil } -// Close the mailserver and its associated db connection. -func (s *WMailServer) Close() { - if s.db != nil { - if err := s.db.Close(); err != nil { - log.Error(fmt.Sprintf("s.db.Close failed: %s", err)) +func (s *WhisperMailServer) decodeRequest(peerID []byte, request *whisper.Envelope) (MessagesRequestPayload, error) { + var payload MessagesRequestPayload + + if s.minRequestPoW > 0.0 && request.PoW() < s.minRequestPoW { + return payload, errors.New("PoW too low") + } + + decrypted := s.openEnvelope(request) + if decrypted == nil { + log.Warn("Failed to decrypt p2p request") + return payload, errors.New("failed to decrypt p2p request") + } + + if err := checkMsgSignature(decrypted.Src, peerID); err != nil { + log.Warn("Check message signature failed", "err", err.Error()) + return payload, fmt.Errorf("check message signature failed: %v", err) + } + + if err := rlp.DecodeBytes(decrypted.Payload, &payload); err != nil { + return payload, fmt.Errorf("failed to decode data: %v", err) + } + + if payload.Upper == 0 { + payload.Upper = uint32(time.Now().Unix() + whisperTTLSafeThreshold) + } + + if payload.Upper < payload.Lower { + log.Error("Query range is invalid: lower > upper", "lower", payload.Lower, "upper", payload.Upper) + return payload, errors.New("query range is invalid: lower > upper") + } + + return payload, nil +} + +// openEnvelope tries to decrypt an envelope, first based on asymmetric key (if +// provided) and second on the symmetric key (if provided) +func (s *WhisperMailServer) openEnvelope(request *whisper.Envelope) *whisper.ReceivedMessage { + if s.asymFilter != nil { + if d := request.Open(s.asymFilter); d != nil { + return d } } - if s.rateLimiter != nil { - s.rateLimiter.Stop() + if s.symFilter != nil { + if d := request.Open(s.symFilter); d != nil { + return d + } } - if s.cleaner != nil { - s.cleaner.Stop() + return nil +} + +func (s *WhisperMailServer) decompositeRequest(peerID []byte, request *whisper.Envelope) (MessagesRequestPayload, error) { + var ( + payload MessagesRequestPayload + err error + ) + + if s.minRequestPoW > 0.0 && request.PoW() < s.minRequestPoW { + return payload, fmt.Errorf("PoW() is too low") + } + + decrypted := s.openEnvelope(request) + if decrypted == nil { + return payload, fmt.Errorf("failed to decrypt p2p request") + } + + if err := checkMsgSignature(decrypted.Src, peerID); err != nil { + return payload, err + } + + payload.Bloom, err = s.bloomFromReceivedMessage(decrypted) + if err != nil { + return payload, err + } + + payload.Lower = binary.BigEndian.Uint32(decrypted.Payload[:4]) + payload.Upper = binary.BigEndian.Uint32(decrypted.Payload[4:8]) + + if payload.Upper < payload.Lower { + err := fmt.Errorf("query range is invalid: from > to (%d > %d)", payload.Lower, payload.Upper) + return payload, err + } + + lowerTime := time.Unix(int64(payload.Lower), 0) + upperTime := time.Unix(int64(payload.Upper), 0) + if upperTime.Sub(lowerTime) > maxQueryRange { + err := fmt.Errorf("query range too big for peer %s", string(peerID)) + return payload, err + } + + if len(decrypted.Payload) >= requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength { + payload.Limit = binary.BigEndian.Uint32(decrypted.Payload[requestTimeRangeLength+whisper.BloomFilterSize:]) + } + + if len(decrypted.Payload) == requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength+DBKeyLength { + payload.Cursor = decrypted.Payload[requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength:] + } + + return payload, nil +} + +// bloomFromReceivedMessage for a given whisper.ReceivedMessage it extracts the +// used bloom filter. +func (s *WhisperMailServer) bloomFromReceivedMessage(msg *whisper.ReceivedMessage) ([]byte, error) { + payloadSize := len(msg.Payload) + + if payloadSize < 8 { + return nil, errors.New("Undersized p2p request") + } else if payloadSize == 8 { + return whisper.MakeFullNodeBloom(), nil + } else if payloadSize < 8+whisper.BloomFilterSize { + return nil, errors.New("Undersized bloom filter in p2p request") + } + + return msg.Payload[8 : 8+whisper.BloomFilterSize], nil +} + +// -------------- +// WakuMailServer +// -------------- + +type WakuMailServer struct { + ms *mailServer + shh *waku.Waku + minRequestPoW float64 + + symFilter *waku.Filter + asymFilter *waku.Filter +} + +func (s *WakuMailServer) Init(waku *waku.Waku, cfg *params.WakuConfig) error { + s.shh = waku + s.minRequestPoW = cfg.MinimumPoW + + config := Config{ + DataDir: cfg.DataDir, + Password: cfg.MailServerPassword, + MinimumPoW: cfg.MinimumPoW, + DataRetention: cfg.MailServerDataRetention, + RateLimit: cfg.MailServerRateLimit, + PostgresEnabled: cfg.DatabaseConfig.PGConfig.Enabled, + PostgresURI: cfg.DatabaseConfig.PGConfig.URI, + } + var err error + s.ms, err = newMailServer( + config, + &wakuAdapter{}, + &wakuService{Waku: waku}, + ) + if err != nil { + return err + } + + if err := s.setupDecryptor(config.Password, config.AsymKey); err != nil { + return err + } + + return nil +} + +func (s *WakuMailServer) Close() { + s.ms.Close() +} + +func (s *WakuMailServer) Archive(env *waku.Envelope) { + s.ms.Archive(gethbridge.NewWakuEnvelope(env)) +} + +func (s *WakuMailServer) Deliver(peerID []byte, req waku.MessagesRequest) { + s.ms.DeliverMail(types.BytesToHash(peerID), types.BytesToHash(req.ID), MessagesRequestPayload{ + Lower: req.From, + Upper: req.To, + Bloom: req.Bloom, + Limit: req.Limit, + Cursor: req.Cursor, + Batch: true, + }) +} + +// DEPRECATED; user Deliver instead +func (s *WakuMailServer) DeliverMail(peerID []byte, req *waku.Envelope) { + payload, err := s.decodeRequest(peerID, req) + if err != nil { + deliveryFailuresCounter.WithLabelValues("validation").Inc() + log.Error( + "[mailserver:DeliverMail] request failed validaton", + "peerID", peerID, + "requestID", req.Hash().String(), + "err", err, + ) + s.ms.sendHistoricMessageErrorResponse(types.BytesToHash(peerID), types.Hash(req.Hash()), err) + return + } + + s.ms.DeliverMail(types.BytesToHash(peerID), types.Hash(req.Hash()), payload) +} + +func (s *WakuMailServer) setupDecryptor(password, asymKey string) error { + s.symFilter = nil + s.asymFilter = nil + + if password != "" { + keyID, err := s.shh.AddSymKeyFromPassword(password) + if err != nil { + return fmt.Errorf("create symmetric key: %v", err) + } + + symKey, err := s.shh.GetSymKey(keyID) + if err != nil { + return fmt.Errorf("save symmetric key: %v", err) + } + + s.symFilter = &waku.Filter{KeySym: symKey} + } + + if asymKey != "" { + keyAsym, err := crypto.HexToECDSA(asymKey) + if err != nil { + return err + } + s.asymFilter = &waku.Filter{KeyAsym: keyAsym} + } + + return nil +} + +// openEnvelope tries to decrypt an envelope, first based on asymetric key (if +// provided) and second on the symetric key (if provided) +func (s *WakuMailServer) openEnvelope(request *waku.Envelope) *waku.ReceivedMessage { + if s.asymFilter != nil { + if d := request.Open(s.asymFilter); d != nil { + return d + } + } + if s.symFilter != nil { + if d := request.Open(s.symFilter); d != nil { + return d + } + } + return nil +} + +func (s *WakuMailServer) decodeRequest(peerID []byte, request *waku.Envelope) (MessagesRequestPayload, error) { + var payload MessagesRequestPayload + + if s.minRequestPoW > 0.0 && request.PoW() < s.minRequestPoW { + return payload, errors.New("PoW too low") + } + + decrypted := s.openEnvelope(request) + if decrypted == nil { + log.Warn("Failed to decrypt p2p request") + return payload, errors.New("failed to decrypt p2p request") + } + + if err := checkMsgSignature(decrypted.Src, peerID); err != nil { + log.Warn("Check message signature failed", "err", err.Error()) + return payload, fmt.Errorf("check message signature failed: %v", err) + } + + if err := rlp.DecodeBytes(decrypted.Payload, &payload); err != nil { + return payload, fmt.Errorf("failed to decode data: %v", err) + } + + if payload.Upper == 0 { + payload.Upper = uint32(time.Now().Unix() + whisperTTLSafeThreshold) + } + + if payload.Upper < payload.Lower { + log.Error("Query range is invalid: lower > upper", "lower", payload.Lower, "upper", payload.Upper) + return payload, errors.New("query range is invalid: lower > upper") + } + + return payload, nil +} + +// ------- +// adapter +// ------- + +type adapter interface { + CreateRequestFailedPayload(reqID types.Hash, err error) []byte + CreateRequestCompletedPayload(reqID, lastEnvelopeHash types.Hash, cursor []byte) []byte + CreateSyncResponse(envelopes []types.Envelope, cursor []byte, final bool, err string) interface{} + CreateRawSyncResponse(envelopes []rlp.RawValue, cursor []byte, final bool, err string) interface{} +} + +// -------------- +// whisperAdapter +// -------------- + +type whisperAdapter struct{} + +var _ adapter = (*whisperAdapter)(nil) + +func (whisperAdapter) CreateRequestFailedPayload(reqID types.Hash, err error) []byte { + return whisper.CreateMailServerRequestFailedPayload(common.Hash(reqID), err) +} + +func (whisperAdapter) CreateRequestCompletedPayload(reqID, lastEnvelopeHash types.Hash, cursor []byte) []byte { + return whisper.CreateMailServerRequestCompletedPayload(common.Hash(reqID), common.Hash(lastEnvelopeHash), cursor) +} + +func (whisperAdapter) CreateSyncResponse(envelopes []types.Envelope, cursor []byte, final bool, err string) interface{} { + whisperEnvelopes := make([]*whisper.Envelope, len(envelopes)) + for i, env := range envelopes { + whisperEnvelopes[i] = gethbridge.MustUnwrapWhisperEnvelope(env) + } + return whisper.SyncResponse{ + Envelopes: whisperEnvelopes, + Cursor: cursor, + Final: final, + Error: err, } } -// Archive a whisper envelope. -func (s *WMailServer) Archive(env *whisper.Envelope) { - if err := s.db.SaveEnvelope(env); err != nil { - log.Error("Could not save envelope", "hash", env.Hash()) +func (whisperAdapter) CreateRawSyncResponse(envelopes []rlp.RawValue, cursor []byte, final bool, err string) interface{} { + return whisper.RawSyncResponse{ + Envelopes: envelopes, + Cursor: cursor, + Final: final, + Error: err, } } -// DeliverMail sends mail to specified whisper peer. -func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) { +// ----------- +// wakuAdapter +// ----------- + +type wakuAdapter struct{} + +var _ adapter = (*wakuAdapter)(nil) + +func (wakuAdapter) CreateRequestFailedPayload(reqID types.Hash, err error) []byte { + return waku.CreateMailServerRequestFailedPayload(common.Hash(reqID), err) +} + +func (wakuAdapter) CreateRequestCompletedPayload(reqID, lastEnvelopeHash types.Hash, cursor []byte) []byte { + return waku.CreateMailServerRequestCompletedPayload(common.Hash(reqID), common.Hash(lastEnvelopeHash), cursor) +} + +func (wakuAdapter) CreateSyncResponse(_ []types.Envelope, _ []byte, _ bool, _ string) interface{} { + return nil +} + +func (wakuAdapter) CreateRawSyncResponse(_ []rlp.RawValue, _ []byte, _ bool, _ string) interface{} { + return nil +} + +// ------- +// service +// ------- + +type service interface { + SendHistoricMessageResponse(peerID []byte, payload []byte) error + SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error + MaxMessageSize() uint32 + SendRawSyncResponse(peerID []byte, data interface{}) error // optional + SendSyncResponse(peerID []byte, data interface{}) error // optional +} + +// -------------- +// whisperService +// -------------- + +type whisperService struct { + *whisper.Whisper +} + +func (s *whisperService) SendRawSyncResponse(peerID []byte, data interface{}) error { + resp, ok := data.(whisper.RawSyncResponse) + if !ok { + panic(fmt.Sprintf("invalid data type, got %s", reflect.TypeOf(data))) + } + return s.Whisper.SendRawSyncResponse(peerID, resp) +} + +func (s *whisperService) SendSyncResponse(peerID []byte, data interface{}) error { + resp, ok := data.(whisper.SyncResponse) + if !ok { + panic(fmt.Sprintf("invalid data type, got %s", reflect.TypeOf(data))) + } + return s.Whisper.SendSyncResponse(peerID, resp) +} + +// ----------- +// wakuService +// ----------- + +type wakuService struct { + *waku.Waku +} + +func (s *wakuService) SendRawSyncResponse(peerID []byte, data interface{}) error { + return errors.New("syncing mailservers is not support by Waku") +} + +func (s *wakuService) SendSyncResponse(peerID []byte, data interface{}) error { + return errors.New("syncing mailservers is not support by Waku") +} + +// ---------- +// mailServer +// ---------- + +type mailServer struct { + adapter adapter + service service + db DB + cleaner *dbCleaner // removes old envelopes + muRateLimiter sync.RWMutex + rateLimiter *rateLimiter +} + +func newMailServer(cfg Config, adapter adapter, service service) (*mailServer, error) { + if len(cfg.DataDir) == 0 { + return nil, errDirectoryNotProvided + } + + // TODO: move out + if len(cfg.Password) == 0 && len(cfg.AsymKey) == 0 { + return nil, errDecryptionMethodNotProvided + } + + s := mailServer{ + adapter: adapter, + service: service, + } + + if cfg.RateLimit > 0 { + s.setupRateLimiter(time.Duration(cfg.RateLimit) * time.Second) + } + + // Open database in the last step in order not to init with error + // and leave the database open by accident. + if cfg.PostgresEnabled { + log.Info("Connecting to postgres database") + database, err := NewPostgresDB(cfg.PostgresURI) + if err != nil { + return nil, fmt.Errorf("open DB: %s", err) + } + s.db = database + log.Info("Connected to postgres database") + } else { + // Defaults to LevelDB + database, err := NewLevelDB(cfg.DataDir) + if err != nil { + return nil, fmt.Errorf("open DB: %s", err) + } + s.db = database + } + + if cfg.DataRetention > 0 { + // MailServerDataRetention is a number of days. + s.setupCleaner(time.Duration(cfg.DataRetention) * time.Hour * 24) + } + + return &s, nil +} + +// setupRateLimiter in case limit is bigger than 0 it will setup an automated +// limit db cleanup. +func (s *mailServer) setupRateLimiter(limit time.Duration) { + s.rateLimiter = newRateLimiter(limit) + s.rateLimiter.Start() +} + +func (s *mailServer) setupCleaner(retention time.Duration) { + s.cleaner = newDBCleaner(s.db, retention) + s.cleaner.Start() +} + +func (s *mailServer) Archive(env types.Envelope) { + err := s.db.SaveEnvelope(env) + if err != nil { + log.Error("Could not save envelope", "hash", env.Hash().String()) + } +} + +func (s *mailServer) DeliverMail(peerID, reqID types.Hash, req MessagesRequestPayload) { timer := prom.NewTimer(mailDeliveryDuration) defer timer.ObserveDuration() deliveryAttemptsCounter.Inc() - - if peer == nil { - deliveryFailuresCounter.WithLabelValues("no_peer_set").Inc() - log.Error("[mailserver:DeliverMail] peer is nil") - return - } - - requestID := types.Hash(request.Hash()) - peerID := peerIDString(peer) - - log.Info("[mailserver:DeliverMail] delivering mail", - "peerID", peerID, - "requestID", requestID.String()) - - if s.exceedsPeerRequests(peer.ID()) { - deliveryFailuresCounter.WithLabelValues("peer_req_limit").Inc() - log.Error("[mailserver:DeliverMail] peer exceeded the limit", - "peerID", peerID, - "requestID", requestID.String()) - s.trySendHistoricMessageErrorResponse(peer, requestID, fmt.Errorf("rate limit exceeded")) - return - } - - var ( - lower, upper uint32 - bloom []byte - limit uint32 - cursor []byte - batch bool - err error + log.Info( + "[mailserver:DeliverMail] delivering mail", + "peerID", peerID.String(), + "requestID", reqID.String(), ) - payload, err := s.decodeRequest(peer.ID(), request) - if err == nil { - lower, upper = payload.Lower, payload.Upper - bloom = payload.Bloom - cursor = payload.Cursor - limit = payload.Limit - batch = payload.Batch - } else { - log.Debug("[mailserver:DeliverMail] failed to decode request", + req.SetDefaults() + + if err := req.Validate(); err != nil { + syncFailuresCounter.WithLabelValues("req_invalid").Inc() + log.Error( + "[mailserver:DeliverMail] request invalid", + "peerID", peerID.String(), + "requestID", reqID.String(), "err", err, - "peerID", peerID, - "requestID", requestID.String()) - lower, upper, bloom, limit, cursor, err = s.validateRequest(peer.ID(), request) - } - - if limit == 0 { - limit = defaultLimit - } - - if err != nil { - deliveryFailuresCounter.WithLabelValues("validation").Inc() - log.Error("[mailserver:DeliverMail] request failed validaton", - "peerID", peerID, - "requestID", requestID.String(), - "err", err) - s.trySendHistoricMessageErrorResponse(peer, requestID, err) + ) + s.sendHistoricMessageErrorResponse(peerID, reqID, fmt.Errorf("request is invalid: %v", err)) return } - log.Info("[mailserver:DeliverMail] processing request", - "peerID", peerID, - "requestID", requestID.String(), - "lower", lower, - "upper", upper, - "bloom", bloom, - "limit", limit, - "cursor", cursor, - "batch", batch, - ) + if s.exceedsPeerRequests(peerID) { + deliveryFailuresCounter.WithLabelValues("peer_req_limit").Inc() + log.Error( + "[mailserver:DeliverMail] peer exceeded the limit", + "peerID", peerID.String(), + "requestID", reqID.String(), + ) + s.sendHistoricMessageErrorResponse(peerID, reqID, fmt.Errorf("rate limit exceeded")) + return + } - if batch { + log.Info( + "[mailserver:DeliverMail] processing request", + "peerID", peerID.String(), + "requestID", reqID.String(), + "lower", req.Lower, + "upper", req.Upper, + "bloom", req.Bloom, + "limit", req.Limit, + "cursor", req.Cursor, + "batch", req.Batch, + ) + if req.Batch { requestsBatchedCounter.Inc() } - iter, err := s.createIterator(lower, upper, cursor, bloom, limit) + iter, err := s.createIterator(req) if err != nil { - log.Error("[mailserver:DeliverMail] request failed", - "peerID", peerID, - "requestID", requestID) - + log.Error( + "[mailserver:DeliverMail] request failed", + "peerID", peerID.String(), + "requestID", reqID.String(), + ) return } - defer iter.Release() bundles := make(chan []rlp.RawValue, 5) @@ -286,7 +754,7 @@ func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) go func() { counter := 0 for bundle := range bundles { - if err := s.sendRawEnvelopes(peer, bundle, batch); err != nil { + if err := s.sendRawEnvelopes(peerID, bundle, req.Batch); err != nil { close(cancelProcessing) errCh <- err break @@ -294,18 +762,20 @@ func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) counter++ } close(errCh) - log.Info("[mailserver:DeliverMail] finished sending bundles", + log.Info( + "[mailserver:DeliverMail] finished sending bundles", "peerID", peerID, - "requestID", requestID.String(), - "counter", counter) + "requestID", reqID.String(), + "counter", counter, + ) }() nextPageCursor, lastEnvelopeHash := s.processRequestInBundles( iter, - bloom, - int(limit), + req.Bloom, + int(req.Limit), processRequestTimeout, - requestID.String(), + reqID.String(), bundles, cancelProcessing, ) @@ -313,198 +783,62 @@ func (s *WMailServer) DeliverMail(peer *whisper.Peer, request *whisper.Envelope) // Wait for the goroutine to finish the work. It may return an error. if err := <-errCh; err != nil { deliveryFailuresCounter.WithLabelValues("process").Inc() - log.Error("[mailserver:DeliverMail] error while processing", + log.Error( + "[mailserver:DeliverMail] error while processing", "err", err, "peerID", peerID, - "requestID", requestID) - s.trySendHistoricMessageErrorResponse(peer, requestID, err) + "requestID", reqID, + ) + s.sendHistoricMessageErrorResponse(peerID, reqID, err) return } // Processing of the request could be finished earlier due to iterator error. if err := iter.Error(); err != nil { deliveryFailuresCounter.WithLabelValues("iterator").Inc() - log.Error("[mailserver:DeliverMail] iterator failed", + log.Error( + "[mailserver:DeliverMail] iterator failed", "err", err, "peerID", peerID, - "requestID", requestID) - s.trySendHistoricMessageErrorResponse(peer, requestID, err) - return - } - - log.Info("[mailserver:DeliverMail] sending historic message response", - "peerID", peerID, - "requestID", requestID, - "last", lastEnvelopeHash, - "next", nextPageCursor) - - if err := s.sendHistoricMessageResponse(peer, requestID, lastEnvelopeHash, nextPageCursor); err != nil { - deliveryFailuresCounter.WithLabelValues("historic_msg_resp").Inc() - log.Error("[mailserver:DeliverMail] error sending historic message response", - "err", err, - "peerID", peerID, - "requestID", requestID) - // we still want to try to report error even it it is a p2p error and it is unlikely - s.trySendHistoricMessageErrorResponse(peer, requestID, err) - } -} - -func (s *WMailServer) Deliver(peer *whisper.Peer, r whisper.MessagesRequest) { - timer := prom.NewTimer(mailDeliveryDuration) - defer timer.ObserveDuration() - - deliveryAttemptsCounter.Inc() - - var ( - requestIDHash = types.BytesToHash(r.ID) - requestIDStr = requestIDHash.String() - peerID = peerIDString(peer) - err error - ) - - defer func() { - if err != nil { - log.Error("[mailserver:DeliverMail] failed to process", - "err", err, - "peerID", peerID, - "requestID", requestIDStr, - ) - s.trySendHistoricMessageErrorResponse(peer, requestIDHash, err) - } - }() - - log.Info("[mailserver:Deliver] delivering mail", "peerID", peerID, "requestID", requestIDStr) - - if peer == nil { - deliveryFailuresCounter.WithLabelValues("no_peer_set").Inc() - log.Error("[mailserver:Deliver] peer is nil") - return - } - - if s.exceedsPeerRequests(peer.ID()) { - deliveryFailuresCounter.WithLabelValues("peer_req_limit").Inc() - err = errors.New("exceeded the number of requests limit") - return - } - - err = r.Validate() - if err != nil { - deliveryFailuresCounter.WithLabelValues("validation").Inc() - err = fmt.Errorf("invalid request: %v", err) - return - } - - var ( - lower, upper = r.From, r.To - bloom = r.Bloom - limit = r.Limit - cursor = r.Cursor - batch = true // batch requests are default - ) - - log.Info("[mailserver:Deliver] processing request", - "peerID", peerID, - "requestID", requestIDStr, - "lower", lower, - "upper", upper, - "bloom", bloom, - "limit", limit, - "cursor", cursor, - "batch", batch, - ) - requestsBatchedCounter.Inc() - - iter, err := s.createIterator(lower, upper, cursor, bloom, limit) - if err != nil { - err = fmt.Errorf("failed to create an iterator: %v", err) - return - } - defer iter.Release() - - bundles := make(chan []rlp.RawValue, 5) - errCh := make(chan error, 1) - cancelProcessing := make(chan struct{}) - - go func() { - counter := 0 - for bundle := range bundles { - if err := s.sendRawEnvelopes(peer, bundle, batch); err != nil { - close(cancelProcessing) - errCh <- err - break - } - counter++ - } - close(errCh) - log.Info("[mailserver:DeliverMail] finished sending bundles", - "peerID", peerID, - "requestID", requestIDStr, - "counter", counter, + "requestID", reqID, ) - }() - - nextPageCursor, lastEnvelopeHash := s.processRequestInBundles( - iter, - bloom, - int(limit), - processRequestTimeout, - requestIDStr, - bundles, - cancelProcessing, - ) - - // Wait for the goroutine to finish the work. It may return an error. - err = <-errCh - if err != nil { - deliveryFailuresCounter.WithLabelValues("process").Inc() - err = fmt.Errorf("failed to send envelopes: %v", err) + s.sendHistoricMessageErrorResponse(peerID, reqID, err) return } - // Processing of the request could be finished earlier due to iterator error. - err = iter.Error() - if err != nil { - deliveryFailuresCounter.WithLabelValues("iterator").Inc() - err = fmt.Errorf("failed to read all envelopes: %v", err) - return - } - - log.Info("[mailserver:Deliver] sending historic message response", + log.Info( + "[mailserver:DeliverMail] sending historic message response", "peerID", peerID, - "requestID", requestIDStr, + "requestID", reqID, "last", lastEnvelopeHash, "next", nextPageCursor, ) - err = s.sendHistoricMessageResponse(peer, requestIDHash, lastEnvelopeHash, nextPageCursor) - if err != nil { - deliveryFailuresCounter.WithLabelValues("historic_msg_resp").Inc() - err = fmt.Errorf("failed to send response: %v", err) - return - } + s.sendHistoricMessageResponse(peerID, reqID, lastEnvelopeHash, nextPageCursor) } -// SyncMail syncs mail servers between two Mail Servers. -func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailRequest) error { - log.Info("Started syncing envelopes", "peer", peerIDString(peer), "req", request) +func (s *mailServer) SyncMail(peerID types.Hash, req MessagesRequestPayload) error { + log.Info("Started syncing envelopes", "peer", peerID.String(), "req", req) requestID := fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Intn(1000)) syncAttemptsCounter.Inc() // Check rate limiting for a requesting peer. - if s.exceedsPeerRequests(peer.ID()) { + if s.exceedsPeerRequests(peerID) { syncFailuresCounter.WithLabelValues("req_per_sec_limit").Inc() - log.Error("Peer exceeded request per seconds limit", "peerID", peerIDString(peer)) + log.Error("Peer exceeded request per seconds limit", "peerID", peerID.String()) return fmt.Errorf("requests per seconds limit exceeded") } - if err := request.Validate(); err != nil { + req.SetDefaults() + + if err := req.Validate(); err != nil { syncFailuresCounter.WithLabelValues("req_invalid").Inc() return fmt.Errorf("request is invalid: %v", err) } - iter, err := s.createIterator(request.Lower, request.Upper, request.Cursor, nil, 0) + iter, err := s.createIterator(req) if err != nil { syncFailuresCounter.WithLabelValues("iterator").Inc() return err @@ -517,8 +851,8 @@ func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailReque go func() { for bundle := range bundles { - resp := whisper.RawSyncResponse{Envelopes: bundle} - if err := s.w.SendRawSyncResponse(peer, resp); err != nil { + resp := s.adapter.CreateRawSyncResponse(bundle, nil, false, "") + if err := s.service.SendRawSyncResponse(peerID.Bytes(), resp); err != nil { close(cancelProcessing) errCh <- fmt.Errorf("failed to send sync response: %v", err) break @@ -529,8 +863,8 @@ func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailReque nextCursor, _ := s.processRequestInBundles( iter, - request.Bloom, - int(request.Limit), + req.Bloom, + int(req.Limit), processRequestTimeout, requestID, bundles, @@ -540,9 +874,9 @@ func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailReque // Wait for the goroutine to finish the work. It may return an error. if err := <-errCh; err != nil { syncFailuresCounter.WithLabelValues("routine").Inc() - _ = s.w.SendSyncResponse( - peer, - whisper.SyncResponse{Error: "failed to send a response"}, + _ = s.service.SendSyncResponse( + peerID.Bytes(), + s.adapter.CreateSyncResponse(nil, nil, false, "failed to send a response"), ) return err } @@ -550,19 +884,20 @@ func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailReque // Processing of the request could be finished earlier due to iterator error. if err := iter.Error(); err != nil { syncFailuresCounter.WithLabelValues("iterator").Inc() - _ = s.w.SendSyncResponse( - peer, - whisper.SyncResponse{Error: "failed to process all envelopes"}, + _ = s.service.SendSyncResponse( + peerID.Bytes(), + s.adapter.CreateSyncResponse(nil, nil, false, "failed to process all envelopes"), ) return fmt.Errorf("LevelDB iterator failed: %v", err) } - log.Info("Finished syncing envelopes", "peer", peerIDString(peer)) + log.Info("Finished syncing envelopes", "peer", peerID.String()) - if err := s.w.SendSyncResponse(peer, whisper.SyncResponse{ - Cursor: nextCursor, - Final: true, - }); err != nil { + err = s.service.SendSyncResponse( + peerID.Bytes(), + s.adapter.CreateSyncResponse(nil, nextCursor, true, ""), + ) + if err != nil { syncFailuresCounter.WithLabelValues("response_send").Inc() return fmt.Errorf("failed to send the final sync response: %v", err) } @@ -570,9 +905,22 @@ func (s *WMailServer) SyncMail(peer *whisper.Peer, request whisper.SyncMailReque return nil } -// exceedsPeerRequests in case limit its been setup on the current server and limit -// allows the query, it will store/update new query time for the current peer. -func (s *WMailServer) exceedsPeerRequests(peer []byte) bool { +// Close the mailserver and its associated db connection. +func (s *mailServer) Close() { + if s.db != nil { + if err := s.db.Close(); err != nil { + log.Error("closing database failed", "err", err) + } + } + if s.rateLimiter != nil { + s.rateLimiter.Stop() + } + if s.cleaner != nil { + s.cleaner.Stop() + } +} + +func (s *mailServer) exceedsPeerRequests(peerID types.Hash) bool { s.muRateLimiter.RLock() defer s.muRateLimiter.RUnlock() @@ -580,39 +928,36 @@ func (s *WMailServer) exceedsPeerRequests(peer []byte) bool { return false } - peerID := string(peer) - if s.rateLimiter.IsAllowed(peerID) { - s.rateLimiter.Add(peerID) + if s.rateLimiter.IsAllowed(peerID.String()) { + s.rateLimiter.Add(peerID.String()) return false } - log.Info("peerID exceeded the number of requests per second") + log.Info("peerID exceeded the number of requests per second", "peerID", peerID.String()) return true } -func (s *WMailServer) createIterator(lower, upper uint32, cursor []byte, bloom []byte, limit uint32) (Iterator, error) { +func (s *mailServer) createIterator(req MessagesRequestPayload) (Iterator, error) { var ( emptyHash types.Hash emptyTopic types.TopicType ku, kl *DBKey ) - ku = NewDBKey(upper+1, emptyTopic, emptyHash) - kl = NewDBKey(lower, emptyTopic, emptyHash) + ku = NewDBKey(req.Upper+1, emptyTopic, emptyHash) + kl = NewDBKey(req.Lower, emptyTopic, emptyHash) query := CursorQuery{ start: kl.Bytes(), end: ku.Bytes(), - cursor: cursor, - bloom: bloom, - limit: limit, + cursor: req.Cursor, + bloom: req.Bloom, + limit: req.Limit, } return s.db.BuildIterator(query) } -// processRequestInBundles processes envelopes using an iterator and passes them -// to the output channel in bundles. -func (s *WMailServer) processRequestInBundles( +func (s *mailServer) processRequestInBundles( iter Iterator, bloom []byte, limit int, @@ -634,9 +979,11 @@ func (s *WMailServer) processRequestInBundles( lastEnvelopeHash types.Hash ) - log.Info("[mailserver:processRequestInBundles] processing request", + log.Info( + "[mailserver:processRequestInBundles] processing request", "requestID", requestID, - "limit", limit) + "limit", limit, + ) // We iterate over the envelopes. // We collect envelopes in batches. @@ -645,25 +992,25 @@ func (s *WMailServer) processRequestInBundles( // Otherwise publish what you have so far, reset the bundle to the // current envelope, and leave if we hit the limit for iter.Next() { - rawValue, err := iter.GetEnvelope(bloom) - if err != nil { - log.Error("Failed to get envelope from iterator", + log.Error( + "[mailserver:processRequestInBundles]Failed to get envelope from iterator", "err", err, - "requestID", requestID) + "requestID", requestID, + ) continue - } - if rawValue == nil { continue } key, err := iter.DBKey() if err != nil { - log.Error("[mailserver:processRequestInBundles] failed getting key", - "requestID", requestID) + log.Error( + "[mailserver:processRequestInBundles] failed getting key", + "requestID", requestID, + ) break } @@ -677,7 +1024,7 @@ func (s *WMailServer) processRequestInBundles( newSize := bundleSize + envelopeSize // If we still have some room for messages, add and continue - if !limitReached && newSize < s.w.MaxMessageSize() { + if !limitReached && newSize < s.service.MaxMessageSize() { bundle = append(bundle, rawValue) bundleSize = newSize continue @@ -706,12 +1053,14 @@ func (s *WMailServer) processRequestInBundles( processedEnvelopesSize += int64(bundleSize) } - log.Info("[mailserver:processRequestInBundles] publishing envelopes", + log.Info( + "[mailserver:processRequestInBundles] publishing envelopes", "requestID", requestID, "batchesCount", len(batches), "envelopeCount", processedEnvelopes, "processedEnvelopesSize", processedEnvelopesSize, - "cursor", nextCursor) + "cursor", nextCursor, + ) // Publish batchLoop: @@ -723,12 +1072,16 @@ batchLoop: // the consumer of `output` channel exits prematurely. // In such a case, we should stop pushing batches and exit. case <-cancel: - log.Info("[mailserver:processRequestInBundles] failed to push all batches", - "requestID", requestID) + log.Info( + "[mailserver:processRequestInBundles] failed to push all batches", + "requestID", requestID, + ) break batchLoop case <-time.After(timeout): - log.Error("[mailserver:processRequestInBundles] timed out pushing a batch", - "requestID", requestID) + log.Error( + "[mailserver:processRequestInBundles] timed out pushing a batch", + "requestID", requestID, + ) break batchLoop } } @@ -736,23 +1089,25 @@ batchLoop: envelopesCounter.Inc() sentEnvelopeBatchSizeMeter.Observe(float64(processedEnvelopesSize)) - log.Info("[mailserver:processRequestInBundles] envelopes published", - "requestID", requestID) + log.Info( + "[mailserver:processRequestInBundles] envelopes published", + "requestID", requestID, + ) close(output) return nextCursor, lastEnvelopeHash } -func (s *WMailServer) sendRawEnvelopes(peer *whisper.Peer, envelopes []rlp.RawValue, batch bool) error { +func (s *mailServer) sendRawEnvelopes(peerID types.Hash, envelopes []rlp.RawValue, batch bool) error { timer := prom.NewTimer(sendRawEnvelopeDuration) defer timer.ObserveDuration() if batch { - return s.w.SendRawP2PDirect(peer, envelopes...) + return s.service.SendRawP2PDirect(peerID.Bytes(), envelopes...) } for _, env := range envelopes { - if err := s.w.SendRawP2PDirect(peer, env); err != nil { + if err := s.service.SendRawP2PDirect(peerID.Bytes(), env); err != nil { return err } } @@ -760,174 +1115,30 @@ func (s *WMailServer) sendRawEnvelopes(peer *whisper.Peer, envelopes []rlp.RawVa return nil } -func (s *WMailServer) sendHistoricMessageResponse(peer *whisper.Peer, requestID, lastEnvelopeHash types.Hash, cursor []byte) error { - payload := whisper.CreateMailServerRequestCompletedPayload(common.Hash(requestID), common.Hash(lastEnvelopeHash), cursor) - return s.w.SendHistoricMessageResponse(peer, payload) +func (s *mailServer) sendHistoricMessageResponse(peerID, reqID, lastEnvelopeHash types.Hash, cursor []byte) { + payload := s.adapter.CreateRequestCompletedPayload(reqID, lastEnvelopeHash, cursor) + err := s.service.SendHistoricMessageResponse(peerID.Bytes(), payload) + if err != nil { + deliveryFailuresCounter.WithLabelValues("historic_msg_resp").Inc() + log.Error( + "[mailserver:DeliverMail] error sending historic message response", + "err", err, + "peerID", peerID, + "requestID", reqID, + ) + } } -// this method doesn't return an error because it is already in the error handling chain -func (s *WMailServer) trySendHistoricMessageErrorResponse(peer *whisper.Peer, requestID types.Hash, errorToReport error) { - payload := whisper.CreateMailServerRequestFailedPayload(common.Hash(requestID), errorToReport) - - err := s.w.SendHistoricMessageResponse(peer, payload) +func (s *mailServer) sendHistoricMessageErrorResponse(peerID, reqID types.Hash, errorToReport error) { + payload := s.adapter.CreateRequestFailedPayload(reqID, errorToReport) + err := s.service.SendHistoricMessageResponse(peerID.Bytes(), payload) // if we can't report an error, probably something is wrong with p2p connection, // so we just print a log entry to document this sad fact if err != nil { - log.Error("Error while reporting error response", "err", err, "peerID", peerIDString(peer)) + log.Error("Error while reporting error response", "err", err, "peerID", peerID.String()) } } -// openEnvelope tries to decrypt an envelope, first based on asymetric key (if -// provided) and second on the symetric key (if provided) -func (s *WMailServer) openEnvelope(request *whisper.Envelope) *whisper.ReceivedMessage { - if s.asymFilter != nil { - if d := request.Open(s.asymFilter); d != nil { - return d - } - } - if s.symFilter != nil { - if d := request.Open(s.symFilter); d != nil { - return d - } - } - return nil -} - -func (s *WMailServer) decodeRequest(peerID []byte, request *whisper.Envelope) (MessagesRequestPayload, error) { - var payload MessagesRequestPayload - - if s.pow > 0.0 && request.PoW() < s.pow { - return payload, errors.New("PoW too low") - } - - decrypted := s.openEnvelope(request) - if decrypted == nil { - log.Warn("Failed to decrypt p2p request") - return payload, errors.New("failed to decrypt p2p request") - } - - if err := s.checkMsgSignature(decrypted, peerID); err != nil { - log.Warn("Check message signature failed: %s", "err", err.Error()) - return payload, fmt.Errorf("check message signature failed: %v", err) - } - - if err := rlp.DecodeBytes(decrypted.Payload, &payload); err != nil { - return payload, fmt.Errorf("failed to decode data: %v", err) - } - - if payload.Upper == 0 { - payload.Upper = uint32(time.Now().Unix() + whisperTTLSafeThreshold) - } - - if payload.Upper < payload.Lower { - log.Error("Query range is invalid: lower > upper", "lower", payload.Lower, "upper", payload.Upper) - return payload, errors.New("query range is invalid: lower > upper") - } - - return payload, nil -} - -// validateRequest runs different validations on the current request. -// DEPRECATED -func (s *WMailServer) validateRequest( - peerID []byte, - request *whisper.Envelope, -) (uint32, uint32, []byte, uint32, []byte, error) { - if s.pow > 0.0 && request.PoW() < s.pow { - return 0, 0, nil, 0, nil, fmt.Errorf("PoW() is too low") - } - - decrypted := s.openEnvelope(request) - if decrypted == nil { - return 0, 0, nil, 0, nil, fmt.Errorf("failed to decrypt p2p request") - } - - if err := s.checkMsgSignature(decrypted, peerID); err != nil { - return 0, 0, nil, 0, nil, err - } - - bloom, err := s.bloomFromReceivedMessage(decrypted) - if err != nil { - return 0, 0, nil, 0, nil, err - } - - lower := binary.BigEndian.Uint32(decrypted.Payload[:4]) - upper := binary.BigEndian.Uint32(decrypted.Payload[4:8]) - - if upper < lower { - err := fmt.Errorf("query range is invalid: from > to (%d > %d)", lower, upper) - return 0, 0, nil, 0, nil, err - } - - lowerTime := time.Unix(int64(lower), 0) - upperTime := time.Unix(int64(upper), 0) - if upperTime.Sub(lowerTime) > maxQueryRange { - err := fmt.Errorf("query range too big for peer %s", string(peerID)) - return 0, 0, nil, 0, nil, err - } - - var limit uint32 - if len(decrypted.Payload) >= requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength { - limit = binary.BigEndian.Uint32(decrypted.Payload[requestTimeRangeLength+whisper.BloomFilterSize:]) - } - - var cursor []byte - if len(decrypted.Payload) == requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength+DBKeyLength { - cursor = decrypted.Payload[requestTimeRangeLength+whisper.BloomFilterSize+requestLimitLength:] - } - - err = nil - return lower, upper, bloom, limit, cursor, err -} - -// checkMsgSignature returns an error in case the message is not correcly signed -func (s *WMailServer) checkMsgSignature(msg *whisper.ReceivedMessage, id []byte) error { - src := crypto.FromECDSAPub(msg.Src) - if len(src)-len(id) == 1 { - src = src[1:] - } - - // if you want to check the signature, you can do it here. e.g.: - // if !bytes.Equal(peerID, src) { - if src == nil { - return errors.New("Wrong signature of p2p request") - } - - return nil -} - -// bloomFromReceivedMessage for a given whisper.ReceivedMessage it extracts the -// used bloom filter. -func (s *WMailServer) bloomFromReceivedMessage(msg *whisper.ReceivedMessage) ([]byte, error) { - payloadSize := len(msg.Payload) - - if payloadSize < 8 { - return nil, errors.New("Undersized p2p request") - } else if payloadSize == 8 { - return whisper.MakeFullNodeBloom(), nil - } else if payloadSize < 8+whisper.BloomFilterSize { - return nil, errors.New("Undersized bloom filter in p2p request") - } - - return msg.Payload[8 : 8+whisper.BloomFilterSize], nil -} - -// peerWithID is a generalization of whisper.Peer. -// whisper.Peer has all fields and methods, except for ID(), unexported. -// It makes it impossible to create an instance of it -// outside of whisper package and test properly. -type peerWithID interface { - ID() []byte -} - -func peerIDString(peer peerWithID) string { - return fmt.Sprintf("%x", peer.ID()) -} - -func peerIDBytesString(id []byte) string { - return fmt.Sprintf("%x", id) -} - func extractBloomFromEncodedEnvelope(rawValue rlp.RawValue) ([]byte, error) { var envelope whisper.Envelope decodeErr := rlp.DecodeBytes(rawValue, &envelope) @@ -936,3 +1147,19 @@ func extractBloomFromEncodedEnvelope(rawValue rlp.RawValue) ([]byte, error) { } return envelope.Bloom(), nil } + +// checkMsgSignature returns an error in case the message is not correctly signed. +func checkMsgSignature(reqSrc *ecdsa.PublicKey, id []byte) error { + src := crypto.FromECDSAPub(reqSrc) + if len(src)-len(id) == 1 { + src = src[1:] + } + + // if you want to check the signature, you can do it here. e.g.: + // if !bytes.Equal(peerID, src) { + if src == nil { + return errors.New("wrong signature of p2p request") + } + + return nil +} diff --git a/mailserver/mailserver_db.go b/mailserver/mailserver_db.go index 2be6172a0..b048ba19b 100644 --- a/mailserver/mailserver_db.go +++ b/mailserver/mailserver_db.go @@ -3,15 +3,15 @@ package mailserver import ( "time" - "github.com/status-im/status-go/whisper/v6" + "github.com/status-im/status-go/eth-node/types" ) // DB is an interface to abstract interactions with the db so that the mailserver -// is agnostic to the underlaying technology used +// is agnostic to the underlying technology used type DB interface { Close() error // SaveEnvelope stores an envelope - SaveEnvelope(*whisper.Envelope) error // TODO: Migrate to types.Envelope + SaveEnvelope(types.Envelope) error // GetEnvelope returns an rlp encoded envelope from the datastore GetEnvelope(*DBKey) ([]byte, error) // Prune removes envelopes older than time diff --git a/mailserver/mailserver_db_leveldb.go b/mailserver/mailserver_db_leveldb.go index 395547f37..17e33c58b 100644 --- a/mailserver/mailserver_db_leveldb.go +++ b/mailserver/mailserver_db_leveldb.go @@ -12,8 +12,8 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/params" "github.com/status-im/status-go/whisper/v6" ) @@ -58,12 +58,12 @@ func (i *LevelDBIterator) GetEnvelope(bloom []byte) ([]byte, error) { } -func NewLevelDB(config *params.WhisperConfig) (*LevelDB, error) { +func NewLevelDB(dataDir string) (*LevelDB, error) { // Open opens an existing leveldb database - db, err := leveldb.OpenFile(config.DataDir, nil) - if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted { - log.Info("database is corrupted trying to recover", "path", config.DataDir) - db, err = leveldb.RecoverFile(config.DataDir, nil) + db, err := leveldb.OpenFile(dataDir, nil) + if _, corrupted := err.(*errors.ErrCorrupted); corrupted { + log.Info("database is corrupted trying to recover", "path", dataDir) + db, err = leveldb.RecoverFile(dataDir, nil) } return &LevelDB{ldb: db}, err } @@ -138,11 +138,22 @@ func (db *LevelDB) Prune(t time.Time, batchSize int) (int, error) { } // SaveEnvelope stores an envelope in leveldb and increments the metrics -func (db *LevelDB) SaveEnvelope(env *whisper.Envelope) error { +func (db *LevelDB) SaveEnvelope(env types.Envelope) error { defer recoverLevelDBPanics("SaveEnvelope") - key := NewDBKey(env.Expiry-env.TTL, types.TopicType(env.Topic), types.Hash(env.Hash())) - rawEnvelope, err := rlp.EncodeToBytes(env) + key := NewDBKey(env.Expiry()-env.TTL(), env.Topic(), env.Hash()) + + var ( + rawEnvelope []byte + err error + ) + if whisperEnv, ok := gethbridge.UnwrapWhisperEnvelope(env); ok { + rawEnvelope, err = rlp.EncodeToBytes(whisperEnv) + } else if wakuEnv, ok := gethbridge.UnwrapWakuEnvelope(env); ok { + rawEnvelope, err = rlp.EncodeToBytes(wakuEnv) + } else { + return errors.New("unsupported underlying types.Envelope type") + } if err != nil { log.Error(fmt.Sprintf("rlp.EncodeToBytes failed: %s", err)) archivedErrorsCounter.Inc() @@ -154,7 +165,7 @@ func (db *LevelDB) SaveEnvelope(env *whisper.Envelope) error { archivedErrorsCounter.Inc() } archivedEnvelopesCounter.Inc() - archivedEnvelopeSizeMeter.Observe(float64(whisper.EnvelopeHeaderLength + len(env.Data))) + archivedEnvelopeSizeMeter.Observe(float64(whisper.EnvelopeHeaderLength + env.Size())) return err } diff --git a/mailserver/mailserver_db_postgres.go b/mailserver/mailserver_db_postgres.go index 60b57d210..cfe4c2105 100644 --- a/mailserver/mailserver_db_postgres.go +++ b/mailserver/mailserver_db_postgres.go @@ -12,7 +12,6 @@ import ( bindata "github.com/status-im/migrate/v4/source/go_bindata" "github.com/status-im/status-go/mailserver/migrations" - "github.com/status-im/status-go/params" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -21,8 +20,8 @@ import ( "github.com/status-im/status-go/whisper/v6" ) -func NewPostgresDB(config *params.WhisperConfig) (*PostgresDB, error) { - db, err := sql.Open("postgres", config.DatabaseConfig.PGConfig.URI) +func NewPostgresDB(uri string) (*PostgresDB, error) { + db, err := sql.Open("postgres", uri) if err != nil { return nil, err } @@ -179,9 +178,9 @@ func (i *PostgresDB) Prune(t time.Time, batch int) (int, error) { return 0, nil } -func (i *PostgresDB) SaveEnvelope(env *whisper.Envelope) error { - topic := types.TopicType(env.Topic) - key := NewDBKey(env.Expiry-env.TTL, topic, types.Hash(env.Hash())) +func (i *PostgresDB) SaveEnvelope(env types.Envelope) error { + topic := env.Topic() + key := NewDBKey(env.Expiry()-env.TTL(), topic, env.Hash()) rawEnvelope, err := rlp.EncodeToBytes(env) if err != nil { log.Error(fmt.Sprintf("rlp.EncodeToBytes failed: %s", err)) @@ -210,7 +209,7 @@ func (i *PostgresDB) SaveEnvelope(env *whisper.Envelope) error { } archivedEnvelopesCounter.Inc() - archivedEnvelopeSizeMeter.Observe(float64(whisper.EnvelopeHeaderLength + len(env.Data))) + archivedEnvelopeSizeMeter.Observe(float64(whisper.EnvelopeHeaderLength + env.Size())) return nil } diff --git a/mailserver/mailserver_test.go b/mailserver/mailserver_test.go index 00a3c298b..49f3c7e77 100644 --- a/mailserver/mailserver_test.go +++ b/mailserver/mailserver_test.go @@ -27,8 +27,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" "github.com/ethereum/go-ethereum/common" @@ -61,16 +59,16 @@ func TestMailserverSuite(t *testing.T) { type MailserverSuite struct { suite.Suite - server *WMailServer + server *WhisperMailServer shh *whisper.Whisper config *params.WhisperConfig dataDir string } func (s *MailserverSuite) SetupTest() { - s.server = &WMailServer{} + s.server = &WhisperMailServer{} s.shh = whisper.New(&whisper.DefaultConfig) - s.shh.RegisterServer(s.server) + s.shh.RegisterMailServer(s.server) tmpDir, err := ioutil.TempDir("", "mailserver-test") s.Require().NoError(err) @@ -152,9 +150,9 @@ func (s *MailserverSuite) TestInit() { for _, tc := range testCases { s.T().Run(tc.info, func(*testing.T) { - mailServer := &WMailServer{} + mailServer := &WhisperMailServer{} shh := whisper.New(&whisper.DefaultConfig) - shh.RegisterServer(mailServer) + shh.RegisterMailServer(mailServer) err := mailServer.Init(shh, &tc.config) s.Equal(tc.expectedError, err) @@ -162,13 +160,13 @@ func (s *MailserverSuite) TestInit() { // db should be open only if there was no error if tc.expectedError == nil { - s.NotNil(mailServer.db) + s.NotNil(mailServer.ms.db) } else { - s.Nil(mailServer.db) + s.Nil(mailServer.ms) } if tc.config.MailServerRateLimit > 0 { - s.NotNil(mailServer.rateLimiter) + s.NotNil(mailServer.ms.rateLimiter) } }) } @@ -228,7 +226,7 @@ func (s *MailserverSuite) TestOpenEnvelopeWithSymKey() { } func (s *MailserverSuite) TestOpenEnvelopeWithAsymKey() { - // Setup the server with an asymetric key + // Setup the server with an asymmetric key config := *s.config config.MailServerPassword = "" // clear password field s.NoError(s.server.Init(s.shh, &config)) @@ -239,7 +237,7 @@ func (s *MailserverSuite) TestOpenEnvelopeWithAsymKey() { env, err := generateEnvelopeWithKeys(time.Now(), nil, &pubKey) s.Require().NoError(err) - // Test openEnvelope with a valid asymetric key + // Test openEnvelope with a valid asymmetric key d := s.server.openEnvelope(env) s.NotNil(d) s.Equal(testPayload, d.Payload) @@ -261,22 +259,24 @@ func (s *MailserverSuite) TestArchive() { s.server.Archive(env) key := NewDBKey(env.Expiry-env.TTL, types.TopicType(env.Topic), types.Hash(env.Hash())) - archivedEnvelope, err := s.server.db.GetEnvelope(key) + archivedEnvelope, err := s.server.ms.db.GetEnvelope(key) s.NoError(err) s.Equal(rawEnvelope, archivedEnvelope) } func (s *MailserverSuite) TestManageLimits() { - s.server.rateLimiter = newRateLimiter(time.Duration(5) * time.Millisecond) - s.False(s.server.exceedsPeerRequests([]byte("peerID"))) - s.Equal(1, len(s.server.rateLimiter.db)) - firstSaved := s.server.rateLimiter.db["peerID"] + err := s.server.Init(s.shh, s.config) + s.NoError(err) + s.server.ms.rateLimiter = newRateLimiter(time.Duration(5) * time.Millisecond) + s.False(s.server.ms.exceedsPeerRequests(types.BytesToHash([]byte("peerID")))) + s.Equal(1, len(s.server.ms.rateLimiter.db)) + firstSaved := s.server.ms.rateLimiter.db["peerID"] // second call when limit is not accomplished does not store a new limit - s.True(s.server.exceedsPeerRequests([]byte("peerID"))) - s.Equal(1, len(s.server.rateLimiter.db)) - s.Equal(firstSaved, s.server.rateLimiter.db["peerID"]) + s.True(s.server.ms.exceedsPeerRequests(types.BytesToHash([]byte("peerID")))) + s.Equal(1, len(s.server.ms.rateLimiter.db)) + s.Equal(firstSaved, s.server.ms.rateLimiter.db["peerID"]) } func (s *MailserverSuite) TestDBKey() { @@ -317,31 +317,28 @@ func (s *MailserverSuite) TestRequestPaginationLimit() { reqLimit := uint32(6) peerID, request, err := s.prepareRequest(sentEnvelopes, reqLimit) s.NoError(err) - lower, upper, bloom, limit, cursor, err := s.server.validateRequest(peerID, request) + payload, err := s.server.decompositeRequest(peerID, request) s.NoError(err) - s.Nil(cursor) - s.Equal(reqLimit, limit) + s.Nil(payload.Cursor) + s.Equal(reqLimit, payload.Limit) - receivedHashes, cursor, _ = processRequestAndCollectHashes( - s.server, lower, upper, cursor, bloom, int(limit), - ) + receivedHashes, cursor, _ := processRequestAndCollectHashes(s.server, payload) // 10 envelopes sent s.Equal(count, uint32(len(sentEnvelopes))) // 6 envelopes received - s.Len(receivedHashes, int(limit)) + s.Len(receivedHashes, int(payload.Limit)) // the 6 envelopes received should be in forward order - s.Equal(sentHashes[:limit], receivedHashes) + s.Equal(sentHashes[:payload.Limit], receivedHashes) // cursor should be the key of the last envelope of the last page - s.Equal(archiveKeys[limit-1], fmt.Sprintf("%x", cursor)) + s.Equal(archiveKeys[payload.Limit-1], fmt.Sprintf("%x", cursor)) // second page - receivedHashes, cursor, _ = processRequestAndCollectHashes( - s.server, lower, upper, cursor, bloom, int(limit), - ) + payload.Cursor = cursor + receivedHashes, cursor, _ = processRequestAndCollectHashes(s.server, payload) // 4 envelopes received - s.Equal(int(count-limit), len(receivedHashes)) + s.Equal(int(count-payload.Limit), len(receivedHashes)) // cursor is nil because there are no other pages s.Nil(cursor) } @@ -418,17 +415,17 @@ func (s *MailserverSuite) TestMailServer() { s.T().Run(tc.info, func(*testing.T) { request := s.createRequest(tc.params) src := crypto.FromECDSAPub(&tc.params.key.PublicKey) - lower, upper, bloom, limit, _, err := s.server.validateRequest(src, request) + payload, err := s.server.decompositeRequest(src, request) s.Equal(tc.isOK, err == nil) if err == nil { - s.Equal(tc.params.low, lower) - s.Equal(tc.params.upp, upper) - s.Equal(tc.params.limit, limit) - s.Equal(types.TopicToBloom(tc.params.topic), bloom) - s.Equal(tc.expect, s.messageExists(env, tc.params.low, tc.params.upp, bloom, tc.params.limit)) + s.Equal(tc.params.low, payload.Lower) + s.Equal(tc.params.upp, payload.Upper) + s.Equal(tc.params.limit, payload.Limit) + s.Equal(types.TopicToBloom(tc.params.topic), payload.Bloom) + s.Equal(tc.expect, s.messageExists(env, tc.params.low, tc.params.upp, payload.Bloom, tc.params.limit)) src[0]++ - _, _, _, _, _, err = s.server.validateRequest(src, request) + _, err = s.server.decompositeRequest(src, request) s.True(err == nil) } }) @@ -509,7 +506,7 @@ func (s *MailserverSuite) TestProcessRequestDeadlockHandling() { // Prepare a request. peerID, request, err := s.prepareRequest(archievedEnvelopes, 5) s.NoError(err) - lower, upper, bloom, limit, cursor, err := s.server.validateRequest(peerID, request) + payload, err := s.server.decompositeRequest(peerID, request) s.NoError(err) testCases := []struct { @@ -533,7 +530,7 @@ func (s *MailserverSuite) TestProcessRequestDeadlockHandling() { processFinished := make(chan struct{}) go func() { - s.server.processRequestInBundles(iter, bloom, int(limit), timeout, "req-01", bundles, done) + s.server.ms.processRequestInBundles(iter, payload.Bloom, int(payload.Limit), timeout, "req-01", bundles, done) close(processFinished) }() go close(done) @@ -557,7 +554,7 @@ func (s *MailserverSuite) TestProcessRequestDeadlockHandling() { processFinished := make(chan struct{}) go func() { - s.server.processRequestInBundles(iter, bloom, int(limit), time.Second, "req-01", bundles, done) + s.server.ms.processRequestInBundles(iter, payload.Bloom, int(payload.Limit), time.Second, "req-01", bundles, done) close(processFinished) }() @@ -572,7 +569,7 @@ func (s *MailserverSuite) TestProcessRequestDeadlockHandling() { for _, tc := range testCases { s.T().Run(tc.Name, func(t *testing.T) { - iter, err := s.server.createIterator(lower, upper, cursor, nil, 0) + iter, err := s.server.ms.createIterator(payload) s.Require().NoError(err) defer iter.Release() @@ -587,9 +584,12 @@ func (s *MailserverSuite) TestProcessRequestDeadlockHandling() { } func (s *MailserverSuite) messageExists(envelope *whisper.Envelope, low, upp uint32, bloom []byte, limit uint32) bool { - receivedHashes, _, _ := processRequestAndCollectHashes( - s.server, low, upp, nil, bloom, int(limit), - ) + receivedHashes, _, _ := processRequestAndCollectHashes(s.server, MessagesRequestPayload{ + Lower: low, + Upper: upp, + Bloom: bloom, + Limit: limit, + }) for _, hash := range receivedHashes { if hash == envelope.Hash() { return true @@ -634,11 +634,11 @@ func (s *MailserverSuite) TestBloomFromReceivedMessage() { } } -func (s *MailserverSuite) setupServer(server *WMailServer) { +func (s *MailserverSuite) setupServer(server *WhisperMailServer) { const password = "password_for_this_test" s.shh = whisper.New(&whisper.DefaultConfig) - s.shh.RegisterServer(server) + s.shh.RegisterMailServer(server) err := server.Init(s.shh, ¶ms.WhisperConfig{ DataDir: s.dataDir, @@ -770,10 +770,8 @@ func generateEnvelope(sentTime time.Time) (*whisper.Envelope, error) { return generateEnvelopeWithKeys(sentTime, h[:], nil) } -func processRequestAndCollectHashes( - server *WMailServer, lower, upper uint32, cursor []byte, bloom []byte, limit int, -) ([]common.Hash, []byte, types.Hash) { - iter, _ := server.createIterator(lower, upper, cursor, nil, 0) +func processRequestAndCollectHashes(server *WhisperMailServer, payload MessagesRequestPayload) ([]common.Hash, []byte, types.Hash) { + iter, _ := server.ms.createIterator(payload) defer iter.Release() bundles := make(chan []rlp.RawValue, 10) done := make(chan struct{}) @@ -782,34 +780,19 @@ func processRequestAndCollectHashes( go func() { for bundle := range bundles { for _, rawEnvelope := range bundle { - var env *whisper.Envelope if err := rlp.DecodeBytes(rawEnvelope, &env); err != nil { panic(err) } - hashes = append(hashes, env.Hash()) } } close(done) }() - cursor, lastHash := server.processRequestInBundles(iter, bloom, limit, time.Minute, "req-01", bundles, done) + cursor, lastHash := server.ms.processRequestInBundles(iter, payload.Bloom, int(payload.Limit), time.Minute, "req-01", bundles, done) <-done return hashes, cursor, lastHash } - -// mockPeerWithID is a struct that conforms to peerWithID interface. -type mockPeerWithID struct { - id []byte -} - -func (p mockPeerWithID) ID() []byte { return p.id } - -func TestPeerIDString(t *testing.T) { - a := []byte{0x01, 0x02, 0x03} - require.Equal(t, "010203", peerIDString(&mockPeerWithID{a})) - require.Equal(t, "010203", peerIDBytesString(a)) -} diff --git a/mailserver/request.go b/mailserver/request.go index 9dbb76a50..903790200 100644 --- a/mailserver/request.go +++ b/mailserver/request.go @@ -1,5 +1,14 @@ package mailserver +import ( + "errors" + "time" +) + +const ( + maxMessagesRequestPayloadLimit = 1000 +) + // MessagesRequestPayload is a payload sent to the Mail Server. type MessagesRequestPayload struct { // Lower is a lower bound of time range for which messages are requested. @@ -15,3 +24,29 @@ type MessagesRequestPayload struct { // Batch set to true indicates that the client supports batched response. Batch bool } + +func (r *MessagesRequestPayload) SetDefaults() { + if r.Limit == 0 { + r.Limit = maxQueryLimit + } + + if r.Upper == 0 { + r.Upper = uint32(time.Now().Unix() + whisperTTLSafeThreshold) + } +} + +func (r MessagesRequestPayload) Validate() error { + if r.Upper < r.Lower { + return errors.New("query range is invalid: lower > upper") + } + if r.Upper-r.Lower > uint32(maxQueryRange.Seconds()) { + return errors.New("query range must be smaller or equal to 24 hours") + } + if len(r.Bloom) == 0 { + return errors.New("bloom filter is empty") + } + if r.Limit > maxMessagesRequestPayloadLimit { + return errors.New("limit exceeds the maximum allowed value") + } + return nil +} diff --git a/node/node.go b/node/node.go index cda02b22d..153cb2dce 100644 --- a/node/node.go +++ b/node/node.go @@ -37,6 +37,7 @@ import ( "github.com/status-im/status-go/services/status" "github.com/status-im/status-go/static" "github.com/status-im/status-go/timesource" + "github.com/status-im/status-go/waku" "github.com/status-im/status-go/whisper/v6" ) @@ -44,6 +45,7 @@ import ( var ( ErrNodeMakeFailureFormat = "error creating p2p node: %s" ErrWhisperServiceRegistrationFailure = errors.New("failed to register the Whisper service") + ErrWakuServiceRegistrationFailure = errors.New("failed to register the Waku service") ErrLightEthRegistrationFailure = errors.New("failed to register the LES service") ErrLightEthRegistrationFailureUpstreamEnabled = errors.New("failed to register the LES service, upstream is also configured") ErrPersonalServiceRegistrationFailure = errors.New("failed to register the personal api service") @@ -81,6 +83,14 @@ func MakeNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error()) } + if config.EnableNTPSync { + if err = stack.Register(func(*node.ServiceContext) (node.Service, error) { + return timesource.Default(), nil + }); err != nil { + return nil, fmt.Errorf("failed to register NTP time source: %v", err) + } + } + err = activateServices(stack, config, accs, db) if err != nil { return nil, err @@ -119,11 +129,24 @@ func activateServices(stack *node.Node, config *params.NodeConfig, accs *account } func activateNodeServices(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) error { + // Register eth-node node bridge + err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return &nodebridge.NodeService{Node: gethbridge.NewNodeBridge(stack)}, nil + }) + if err != nil { + return fmt.Errorf("failed to register NodeBridhe: %v", err) + } + // start Whisper service. if err := activateShhService(stack, config, db); err != nil { return fmt.Errorf("%v: %v", ErrWhisperServiceRegistrationFailure, err) } + // start Waku service + if err := activateWakuService(stack, config, db); err != nil { + return fmt.Errorf("%v: %v", ErrWakuServiceRegistrationFailure, err) + } + // start incentivisation service if err := activateIncentivisationService(stack, config); err != nil { return fmt.Errorf("%v: %v", ErrIncentivisationServiceRegistrationFailure, err) @@ -290,26 +313,26 @@ func activatePeerService(stack *node.Node) error { }) } -func registerMailServer(whisperService *whisper.Whisper, config *params.WhisperConfig) (err error) { - var mailServer mailserver.WMailServer - whisperService.RegisterServer(&mailServer) +func registerWhisperMailServer(whisperService *whisper.Whisper, config *params.WhisperConfig) (err error) { + var mailServer mailserver.WhisperMailServer + whisperService.RegisterMailServer(&mailServer) return mailServer.Init(whisperService, config) } +func registerWakuMailServer(wakuService *waku.Waku, config *params.WakuConfig) (err error) { + var mailServer mailserver.WakuMailServer + wakuService.RegisterMailServer(&mailServer) + + return mailServer.Init(wakuService, config) +} + // activateShhService configures Whisper and adds it to the given node. func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) { if !config.WhisperConfig.Enabled { logger.Info("SHH protocol is disabled") return nil } - if config.WhisperConfig.EnableNTPSync { - if err = stack.Register(func(*node.ServiceContext) (node.Service, error) { - return timesource.Default(), nil - }); err != nil { - return - } - } err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return createShhService(ctx, &config.WhisperConfig, &config.ClusterConfig) @@ -318,14 +341,6 @@ func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb return } - // Register eth-node node bridge - err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { - return &nodebridge.NodeService{Node: gethbridge.NewNodeBridge(stack)}, nil - }) - if err != nil { - return - } - // Register Whisper eth-node bridge err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { var ethnode *nodebridge.NodeService @@ -352,6 +367,25 @@ func activateShhService(stack *node.Node, config *params.NodeConfig, db *leveldb }) } +// activateWakuService configures Waku and adds it to the given node. +func activateWakuService(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) { + if !config.WakuConfig.Enabled { + logger.Info("Waku protocol is disabled") + return nil + } + + err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return createWakuService(ctx, &config.WakuConfig, &config.ClusterConfig) + }) + if err != nil { + return + } + + // TODO: what to do with shhext? + + return nil +} + func createShhService(ctx *node.ServiceContext, whisperConfig *params.WhisperConfig, clusterConfig *params.ClusterConfig) (*whisper.Whisper, error) { whisperServiceConfig := &whisper.Config{ MaxMessageSize: whisper.DefaultMaxMessageSize, @@ -372,17 +406,13 @@ func createShhService(ctx *node.ServiceContext, whisperConfig *params.WhisperCon whisperService.SetRateLimiter(r) } - if whisperConfig.EnableNTPSync { - timesource, err := whisperTimeSource(ctx) - if err != nil { - return nil, err - } + if timesource, err := timeSource(ctx); err == nil { whisperService.SetTimeSource(timesource) } // enable mail service if whisperConfig.EnableMailServer { - if err := registerMailServer(whisperService, whisperConfig); err != nil { + if err := registerWhisperMailServer(whisperService, whisperConfig); err != nil { return nil, fmt.Errorf("failed to register MailServer: %v", err) } } @@ -397,6 +427,48 @@ func createShhService(ctx *node.ServiceContext, whisperConfig *params.WhisperCon return whisperService, nil } +func createWakuService(ctx *node.ServiceContext, wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) (*waku.Waku, error) { + cfg := &waku.Config{ + MaxMessageSize: waku.DefaultMaxMessageSize, + MinimumAcceptedPoW: params.WakuMinimumPoW, + } + + if wakuCfg.MaxMessageSize > 0 { + cfg.MaxMessageSize = wakuCfg.MaxMessageSize + } + if wakuCfg.MinimumPoW > 0 { + cfg.MinimumAcceptedPoW = wakuCfg.MinimumPoW + } + + // TODO: provide a logger + w := waku.New(cfg, nil) + + if wakuCfg.EnableRateLimiter { + r := wakuRateLimiter(wakuCfg, clusterCfg) + w.RegisterRateLimiter(r) + } + + if timesource, err := timeSource(ctx); err == nil { + w.SetTimeSource(timesource) + } + + // enable mail service + if wakuCfg.EnableMailServer { + if err := registerWakuMailServer(w, wakuCfg); err != nil { + return nil, fmt.Errorf("failed to register WakuMailServer: %v", err) + } + } + + if wakuCfg.LightClient { + emptyBloomFilter := make([]byte, 64) + if err := w.SetBloomFilter(emptyBloomFilter); err != nil { + return nil, err + } + } + + return w, nil +} + // activateIncentivisationService configures Whisper and adds it to the given node. func activateIncentivisationService(stack *node.Node, config *params.NodeConfig) (err error) { if !config.WhisperConfig.Enabled { @@ -478,8 +550,8 @@ func parseNodesToNodeID(enodes []string) []enode.ID { return nodeIDs } -// whisperTimeSource get timeSource to be used by whisper -func whisperTimeSource(ctx *node.ServiceContext) (func() time.Time, error) { +// timeSource get timeSource to be used by whisper +func timeSource(ctx *node.ServiceContext) (func() time.Time, error) { var timeSource *timesource.NTPTimeSource if err := ctx.Service(&timeSource); err != nil { return nil, err @@ -513,3 +585,30 @@ func whisperRateLimiter(whisperConfig *params.WhisperConfig, clusterConfig *para }, ) } + +func wakuRateLimiter(wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) *waku.PeerRateLimiter { + enodes := append( + parseNodes(clusterCfg.StaticNodes), + parseNodes(clusterCfg.TrustedMailServers)..., + ) + var ( + ips []string + peerIDs []enode.ID + ) + for _, item := range enodes { + ips = append(ips, item.IP().String()) + peerIDs = append(peerIDs, item.ID()) + } + return waku.NewPeerRateLimiter( + &waku.PeerRateLimiterConfig{ + LimitPerSecIP: wakuCfg.RateLimitIP, + LimitPerSecPeerID: wakuCfg.RateLimitPeerID, + WhitelistedIPs: ips, + WhitelistedPeerIDs: peerIDs, + }, + &whisper.MetricsRateLimiterHandler{}, + &whisper.DropPeerRateLimiterHandler{ + Tolerance: wakuCfg.RateLimitTolerance, + }, + ) +} diff --git a/node/node_api_test.go b/node/node_api_test.go index 04c5e9a8c..6f809b668 100644 --- a/node/node_api_test.go +++ b/node/node_api_test.go @@ -13,6 +13,7 @@ import ( func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) { config := params.NodeConfig{ + EnableNTPSync: true, WhisperConfig: params.WhisperConfig{ Enabled: true, LightClient: true, @@ -35,6 +36,7 @@ func TestWhisperLightModeEnabledSetsEmptyBloomFilter(t *testing.T) { func TestWhisperLightModeEnabledSetsNilBloomFilter(t *testing.T) { config := params.NodeConfig{ + EnableNTPSync: true, WhisperConfig: params.WhisperConfig{ Enabled: true, LightClient: false, diff --git a/node/status_node_test.go b/node/status_node_test.go index d0bb1ee6e..284b0458e 100644 --- a/node/status_node_test.go +++ b/node/status_node_test.go @@ -90,6 +90,7 @@ func TestStatusNodeWithDataDir(t *testing.T) { func TestStatusNodeServiceGetters(t *testing.T) { config := params.NodeConfig{ + EnableNTPSync: true, WhisperConfig: params.WhisperConfig{ Enabled: true, }, diff --git a/params/config.go b/params/config.go index 78e541309..29f736b42 100644 --- a/params/config.go +++ b/params/config.go @@ -43,6 +43,25 @@ type LightEthConfig struct { MinTrustedFraction int } +// ---------- +// DatabaseConfig +// ---------- + +type DatabaseConfig struct { + PGConfig PGConfig +} + +// ---------- +// PGConfig +// ---------- + +type PGConfig struct { + // Enabled whether we should use a Postgres instance + Enabled bool + // The URI of the server + URI string +} + // ---------- // WhisperConfig // ---------- @@ -81,9 +100,6 @@ type WhisperConfig struct { // TTL time to live for messages, in seconds TTL int - // EnableNTPSync enables NTP synchronizations - EnableNTPSync bool - // MaxMessageSize is a maximum size of a devp2p packet handled by the Whisper protocol, // not only the size of envelopes sent in that packet. MaxMessageSize uint32 @@ -108,23 +124,71 @@ type WhisperConfig struct { RateLimitTolerance int64 } -type DatabaseConfig struct { - PGConfig PGConfig -} - -type PGConfig struct { - // Enabled whether we should use a Postgres instance - Enabled bool - // The URI of the server - URI string -} - // String dumps config object as nicely indented JSON func (c *WhisperConfig) String() string { data, _ := json.MarshalIndent(c, "", " ") // nolint: gas return string(data) } +// ---------- +// WakuConfig +// ---------- + +// WakuConfig provides a configuration for Waku service. +type WakuConfig struct { + // Enabled set to true enables Waku subprotocol. + Enabled bool + + // LightClient should be true if the node should start with an empty bloom filter and not forward messages from other nodes + LightClient bool + + // EnableMailServer is mode when node is capable of delivering expired messages on demand + EnableMailServer bool + + // DataDir is the file system folder Whisper should use for any data storage needs. + // For instance, MailServer will use this directory to store its data. + DataDir string + + // MinimumPoW minimum PoW for Whisper messages + MinimumPoW float64 + + // MailServerPassword for symmetric encryption of whisper message history requests. + // (if no account file selected, then this password is used for symmetric encryption). + MailServerPassword string + + // MailServerRateLimit minimum time between queries to mail server per peer. + MailServerRateLimit int + + // MailServerDataRetention is a number of days data should be stored by MailServer. + MailServerDataRetention int + + // TTL time to live for messages, in seconds + TTL int + + // MaxMessageSize is a maximum size of a devp2p packet handled by the Whisper protocol, + // not only the size of envelopes sent in that packet. + MaxMessageSize uint32 + + // DatabaseConfig is configuration for which data store we use. + DatabaseConfig DatabaseConfig + + // EnableRateLimiter set to true enables IP and peer ID rate limiting. + EnableRateLimiter bool + + // RateLimitIP sets the limit on the number of messages per second + // from a given IP. + RateLimitIP int64 + + // RateLimitPeerID sets the limit on the number of messages per second + // from a given peer ID. + RateLimitPeerID int64 + + // RateLimitTolerance is a number of how many a limit must be exceeded + // in order to drop a peer. + // If equal to 0, the peers are never dropped. + RateLimitTolerance int64 +} + // IncentivisationConfig holds incentivisation-related configuration type IncentivisationConfig struct { // Enabled flag specifies whether protocol is enabled @@ -343,6 +407,9 @@ type NodeConfig struct { // EnableStatusService should be true to enable methods under status namespace. EnableStatusService bool + // EnableNTPSync enables NTP synchronizations + EnableNTPSync bool + // UpstreamConfig extra config for providing upstream infura server. UpstreamConfig UpstreamRPCConfig `json:"UpstreamConfig"` @@ -355,6 +422,9 @@ type NodeConfig struct { // WhisperConfig extra configuration for SHH WhisperConfig WhisperConfig `json:"WhisperConfig," validate:"structonly"` + // WakuConfig provides a configuration for Waku subprotocol. + WakuConfig WakuConfig `json:"WakuConfig" validate:"structonly"` + // IncentivisationConfig extra configuration for incentivisation service IncentivisationConfig IncentivisationConfig `json:"IncentivisationConfig," validate:"structonly"` @@ -505,8 +575,8 @@ func NewNodeConfigWithDefaults(dataDir string, networkID uint64, opts ...Option) c.LogCompressRotated = true c.LogMaxBackups = 3 c.LogToStderr = true + c.EnableNTPSync = true c.WhisperConfig.Enabled = true - c.WhisperConfig.EnableNTPSync = true for _, opt := range opts { if err := opt(c); err != nil { @@ -591,6 +661,7 @@ func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) { LogFile: "", LogLevel: "ERROR", NoDiscovery: true, + EnableNTPSync: true, UpstreamConfig: UpstreamRPCConfig{ URL: getUpstreamURL(networkID), }, @@ -691,6 +762,10 @@ func (c *NodeConfig) Validate() error { return err } + if c.WhisperConfig.Enabled && c.WakuConfig.Enabled && c.WhisperConfig.DataDir == c.WakuConfig.DataDir { + return fmt.Errorf("both Whisper and Waku are enabled and use the same data dir") + } + // Whisper's data directory must be relative to the main data directory // if EnableMailServer is true. if c.WhisperConfig.Enabled && c.WhisperConfig.EnableMailServer { diff --git a/params/config_test.go b/params/config_test.go index fd5f99f6f..01329c208 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -29,10 +29,10 @@ func TestNewNodeConfigWithDefaults(t *testing.T) { require.NoError(t, err) assert.Equal(t, "/some/data/path", c.DataDir) assert.Equal(t, "/some/data/path/keystore", c.KeyStoreDir) + assert.Equal(t, true, c.EnableNTPSync) // assert Whisper assert.Equal(t, true, c.WhisperConfig.Enabled) assert.Equal(t, "/some/data/path/wnode", c.WhisperConfig.DataDir) - assert.Equal(t, true, c.WhisperConfig.EnableNTPSync) // assert MailServer assert.Equal(t, true, c.WhisperConfig.EnableMailServer) assert.NotEmpty(t, c.WhisperConfig.MailServerPassword) diff --git a/params/defaults.go b/params/defaults.go index 811f943a4..1329bd807 100644 --- a/params/defaults.go +++ b/params/defaults.go @@ -27,6 +27,12 @@ const ( // WhisperTTL is time to live for messages, in seconds WhisperTTL = 120 + // WakuMinimumPoW amount of work for Whisper message to be added to sending queue + WakuMinimumPoW = 0.001 + + // WakuTTL is time to live for messages, in seconds + WakuTTL = 120 + // MainnetEthereumNetworkURL is URL where the upstream ethereum network is loaded to // allow us avoid syncing node. MainnetEthereumNetworkURL = "https://mainnet.infura.io/nKmXgiFgc2KqtoQ8BCGJ" diff --git a/protocol/go.sum b/protocol/go.sum index 7886435ed..a146328d3 100644 --- a/protocol/go.sum +++ b/protocol/go.sum @@ -11,12 +11,14 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -30,12 +32,16 @@ github.com/allegro/bigcache v1.2.0 h1:qDaE0QoF29wKBb3+pXFrJFy1ihe5OT9OiXhg1t85Sx github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 h1:tS7jSmwRqSxTnonTRlDD1oHo6Q9YOK4xHS9/v4L56eg= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= @@ -137,6 +143,7 @@ github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= @@ -209,6 +216,7 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= @@ -224,6 +232,7 @@ github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -241,11 +250,13 @@ github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQ github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s= @@ -268,6 +279,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -279,6 +292,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -428,6 +442,8 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opentracing/opentracing-go v0.0.0-20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -440,17 +456,20 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v0.0.0-20170902204657-a37ad3984311/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -461,12 +480,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= @@ -482,6 +503,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315 h1:H3hCXwP92pH/hSgNrCLtjxvsKJ50sq26nICbZuoR1tQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315/go.mod h1:ZbKa3zlLnhGF1dAeJtMSoNtM5LgFQnqzq8eYH3uYYkU= @@ -531,6 +553,7 @@ github.com/status-im/status-go v0.37.3/go.mod h1:9qHQ2+8NS6ivPJS5YbsI3gWkr0t6DWm github.com/status-im/status-go/extkeys v1.0.0 h1:Qyirsoi5Ye5UFfisgPtCjPb/RkBxyK+UsSiEcr2PVlM= github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU= github.com/status-im/status-go/protocol v1.0.1/go.mod h1:LpA7BsaNmj6EOdq7BwuqncewjPqIRHCletZOb2wlWrY= +github.com/status-im/status-go/waku v1.0.0/go.mod h1:1bjvQAL4cJYtxCsm6DnKdJbxcZwnvvZmxb6pmoUDtuY= github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk= github.com/status-im/whisper v1.5.2 h1:26NgiKusmPic38eQdtXnaY+iaQ/LuQ3Dh0kCGYT/Uxs= github.com/status-im/whisper v1.5.2/go.mod h1:emrOxzJme0k66QtbbQ2bdd3P8RCdLZ8sTD7SkwH1s2s= @@ -553,7 +576,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 h1:kjbwitOGH46vD01f2s3leBfrMnePQa3NSAIlW35MvY8= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9/go.mod h1:EcGP24b8DY+bWHnpfJDP7fM+o8Nmz4fYH0l2xTtNr3I= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= @@ -583,6 +609,8 @@ github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVT github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -609,6 +637,7 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -620,6 +649,7 @@ golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIo golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -647,6 +677,7 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -673,12 +704,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk= @@ -700,7 +734,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 h1:LCmXVkvpQCDj724eX6irUTPCJP5GelFHxqGSWL2D1R0= @@ -721,7 +757,9 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= @@ -733,6 +771,11 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= @@ -740,6 +783,7 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= @@ -754,5 +798,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/services/shhext/api.go b/services/shhext/api.go index 22512d19f..e8371baf3 100644 --- a/services/shhext/api.go +++ b/services/shhext/api.go @@ -737,7 +737,7 @@ func makeEnvelop( if err != nil { return nil, err } - return gethbridge.NewGethEnvelopeWrapper(envelope), nil + return gethbridge.NewWhisperEnvelope(envelope), nil } // makeMessagesRequestPayload makes a specific payload for MailServer diff --git a/services/shhext/history.go b/services/shhext/history.go index 62f055261..60ce72af5 100644 --- a/services/shhext/history.go +++ b/services/shhext/history.go @@ -344,7 +344,7 @@ func (filter BloomFilterOption) ToMessagesRequestPayload() ([]byte, error) { // Client must tell the MailServer if it supports batch responses. // This can be removed in the future. Batch: true, - Limit: 10000, + Limit: 1000, } return rlp.EncodeToBytes(payload) } diff --git a/services/shhext/history_test.go b/services/shhext/history_test.go index e7567045d..87b34a6d7 100644 --- a/services/shhext/history_test.go +++ b/services/shhext/history_test.go @@ -85,7 +85,7 @@ func TestBloomFilterToMessageRequestPayload(t *testing.T) { Upper: end, Bloom: filter, Batch: true, - Limit: 10000, + Limit: 1000, } bloomOption = BloomFilterOption{ Filter: filter, diff --git a/services/shhext/service_test.go b/services/shhext/service_test.go index b996d3329..8c354c577 100644 --- a/services/shhext/service_test.go +++ b/services/shhext/service_test.go @@ -566,7 +566,7 @@ type RequestWithTrackingHistorySuite struct { localContext Context mailSymKey string - remoteMailserver *mailserver.WMailServer + remoteMailserver *mailserver.WhisperMailServer remoteNode *enode.Node remoteWhisper *whisper.Whisper } @@ -602,8 +602,8 @@ func (s *RequestWithTrackingHistorySuite) SetupTest() { remoteSHH := whisper.New(conf) s.remoteWhisper = remoteSHH s.Require().NoError(remoteSHH.Start(nil)) - s.remoteMailserver = &mailserver.WMailServer{} - remoteSHH.RegisterServer(s.remoteMailserver) + s.remoteMailserver = &mailserver.WhisperMailServer{} + remoteSHH.RegisterMailServer(s.remoteMailserver) password := "test" tmpdir, err = ioutil.TempDir("", "tracking-history-tests-") s.Require().NoError(err) diff --git a/t/e2e/whisper/whisper_mailbox_test.go b/t/e2e/whisper/whisper_mailbox_test.go index af2bcfad0..e53f6b68f 100644 --- a/t/e2e/whisper/whisper_mailbox_test.go +++ b/t/e2e/whisper/whisper_mailbox_test.go @@ -488,10 +488,10 @@ func (s *WhisperMailboxSuite) TestSyncBetweenTwoMailServers() { publicChatSymKey, err := mailboxWhisperService.GetSymKey(symKeyID) s.Require().NoError(err) - var mailServer mailserver.WMailServer + var mailServer mailserver.WhisperMailServer err = mailServer.Init(mailboxWhisperService, &mailbox.StatusNode().Config().WhisperConfig) s.Require().NoError(err) - mailboxWhisperService.RegisterServer(&mailServer) + mailboxWhisperService.RegisterMailServer(&mailServer) // envelopes to archive envelopesCount := 5 @@ -548,7 +548,7 @@ func (s *WhisperMailboxSuite) TestSyncBetweenTwoMailServers() { "shhext_syncMessages", shhext.SyncMessagesRequest{ MailServerPeer: mailbox.StatusNode().Server().Self().URLv4(), - From: 0, + From: uint32(time.Now().Add(-time.Hour).Unix()), To: uint32(time.Now().Unix()), Limit: 1, }, @@ -567,7 +567,7 @@ func (s *WhisperMailboxSuite) TestSyncBetweenTwoMailServers() { "shhext_syncMessages", shhext.SyncMessagesRequest{ MailServerPeer: mailbox.StatusNode().Server().Self().URLv4(), - From: 0, + From: uint32(time.Now().Add(-time.Hour).Unix()), To: uint32(time.Now().Unix()), Limit: 10, Cursor: syncMessagesResponse.Cursor, diff --git a/t/utils/utils.go b/t/utils/utils.go index 73defd01d..af222a663 100644 --- a/t/utils/utils.go +++ b/t/utils/utils.go @@ -290,10 +290,10 @@ func MakeTestNodeConfigWithDataDir(name, dataDir string, networkID uint64) (*par } else { cfg.Name = name } + cfg.EnableNTPSync = true cfg.NoDiscovery = true cfg.LightEthConfig.Enabled = false cfg.WhisperConfig.Enabled = true - cfg.WhisperConfig.EnableNTPSync = false if dataDir != "" { cfg.KeyStoreDir = path.Join(dataDir, "keystore") cfg.WhisperConfig.DataDir = path.Join(dataDir, "wnode") diff --git a/vendor/github.com/elastic/gosigar/CHANGELOG.md b/vendor/github.com/elastic/gosigar/CHANGELOG.md index 9377542ab..ae848ffb1 100644 --- a/vendor/github.com/elastic/gosigar/CHANGELOG.md +++ b/vendor/github.com/elastic/gosigar/CHANGELOG.md @@ -12,6 +12,17 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Deprecated +## [0.10.5] + +### Fixed + +- Fixed uptime calculation under Windows. #126 +- Fixed compilation issue for darwin/386. #128 + +### Changed + +- Load DLLs only from Windows system directory. #132 + ## [0.10.4] ### Fixed diff --git a/vendor/github.com/elastic/gosigar/README.md b/vendor/github.com/elastic/gosigar/README.md index ecdfc1c3c..ca1854bf2 100644 --- a/vendor/github.com/elastic/gosigar/README.md +++ b/vendor/github.com/elastic/gosigar/README.md @@ -37,6 +37,7 @@ The features vary by operating system. | ProcMem | X | X | X | | X | | ProcState | X | X | X | | X | | ProcTime | X | X | X | | X | +| Rusage | X | | X | | | | Swap | X | X | | X | X | | Uptime | X | X | | X | X | diff --git a/vendor/github.com/elastic/gosigar/sigar_darwin.go b/vendor/github.com/elastic/gosigar/sigar_darwin.go index a90b998c2..4a8309521 100644 --- a/vendor/github.com/elastic/gosigar/sigar_darwin.go +++ b/vendor/github.com/elastic/gosigar/sigar_darwin.go @@ -40,18 +40,6 @@ func (self *LoadAverage) Get() error { return nil } -func (self *Uptime) Get() error { - tv := syscall.Timeval32{} - - if err := sysctlbyname("kern.boottime", &tv); err != nil { - return err - } - - self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds() - - return nil -} - func (self *Mem) Get() error { var vmstat C.vm_statistics_data_t diff --git a/vendor/github.com/elastic/gosigar/sigar_darwin_386.go b/vendor/github.com/elastic/gosigar/sigar_darwin_386.go new file mode 100644 index 000000000..92c7ff040 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sigar_darwin_386.go @@ -0,0 +1,18 @@ +package gosigar + +import ( + "syscall" + "time" +) + +func (self *Uptime) Get() error { + tv := syscall.Timeval{} + + if err := sysctlbyname("kern.boottime", &tv); err != nil { + return err + } + + self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds() + + return nil +} diff --git a/vendor/github.com/elastic/gosigar/sigar_darwin_amd64.go b/vendor/github.com/elastic/gosigar/sigar_darwin_amd64.go new file mode 100644 index 000000000..29e5b604a --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sigar_darwin_amd64.go @@ -0,0 +1,18 @@ +package gosigar + +import ( + "syscall" + "time" +) + +func (self *Uptime) Get() error { + tv := syscall.Timeval32{} + + if err := sysctlbyname("kern.boottime", &tv); err != nil { + return err + } + + self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds() + + return nil +} diff --git a/vendor/github.com/elastic/gosigar/sigar_interface.go b/vendor/github.com/elastic/gosigar/sigar_interface.go index df79ae08d..57501b969 100644 --- a/vendor/github.com/elastic/gosigar/sigar_interface.go +++ b/vendor/github.com/elastic/gosigar/sigar_interface.go @@ -4,6 +4,7 @@ import ( "time" ) +// ErrNotImplemented is returned when a particular statistic isn't implemented on the host OS. type ErrNotImplemented struct { OS string } @@ -12,6 +13,7 @@ func (e ErrNotImplemented) Error() string { return "not implemented on " + e.OS } +// IsNotImplemented returns true if the error is ErrNotImplemented func IsNotImplemented(err error) bool { switch err.(type) { case ErrNotImplemented, *ErrNotImplemented: @@ -21,6 +23,7 @@ func IsNotImplemented(err error) bool { } } +// Sigar is an interface for gathering system host stats type Sigar interface { CollectCpuStats(collectionInterval time.Duration) (<-chan Cpu, chan<- struct{}) GetLoadAverage() (LoadAverage, error) @@ -32,6 +35,7 @@ type Sigar interface { GetRusage(who int) (Rusage, error) } +// Cpu contains CPU time stats type Cpu struct { User uint64 Nice uint64 @@ -43,11 +47,13 @@ type Cpu struct { Stolen uint64 } +// Total returns total CPU time func (cpu *Cpu) Total() uint64 { return cpu.User + cpu.Nice + cpu.Sys + cpu.Idle + cpu.Wait + cpu.Irq + cpu.SoftIrq + cpu.Stolen } +// Delta returns the difference between two Cpu stat objects func (cpu Cpu) Delta(other Cpu) Cpu { return Cpu{ User: cpu.User - other.User, @@ -61,14 +67,17 @@ func (cpu Cpu) Delta(other Cpu) Cpu { } } +// LoadAverage reports standard load averages type LoadAverage struct { One, Five, Fifteen float64 } +// Uptime reports system uptime type Uptime struct { Length float64 } +// Mem contains host memory stats type Mem struct { Total uint64 Used uint64 @@ -77,12 +86,14 @@ type Mem struct { ActualUsed uint64 } +// Swap contains stats on swap space type Swap struct { Total uint64 Used uint64 Free uint64 } +// HugeTLBPages contains HugePages stats type HugeTLBPages struct { Total uint64 Free uint64 @@ -92,16 +103,19 @@ type HugeTLBPages struct { TotalAllocatedSize uint64 } +// CpuList contains a list of CPUs on the host system type CpuList struct { List []Cpu } +// FDUsage contains stats on filesystem usage type FDUsage struct { Open uint64 Unused uint64 Max uint64 } +// FileSystem contains basic information about a given mounted filesystem type FileSystem struct { DirName string DevName string @@ -111,10 +125,12 @@ type FileSystem struct { Flags uint32 } +// FileSystemList gets a list of mounted filesystems type FileSystemList struct { List []FileSystem } +// FileSystemUsage contains basic stats for the specified filesystem type FileSystemUsage struct { Total uint64 Used uint64 @@ -124,21 +140,30 @@ type FileSystemUsage struct { FreeFiles uint64 } +// ProcList contains a list of processes found on the host system type ProcList struct { List []int } +// RunState is a byte-long code used to specify the current runtime state of a process type RunState byte const ( - RunStateSleep = 'S' - RunStateRun = 'R' - RunStateStop = 'T' - RunStateZombie = 'Z' - RunStateIdle = 'D' + // RunStateSleep corresponds to a sleep state + RunStateSleep = 'S' + // RunStateRun corresponds to a running state + RunStateRun = 'R' + // RunStateStop corresponds to a stopped state + RunStateStop = 'T' + // RunStateZombie marks a zombie process + RunStateZombie = 'Z' + // RunStateIdle corresponds to an idle state + RunStateIdle = 'D' + // RunStateUnknown corresponds to a process in an unknown state RunStateUnknown = '?' ) +// ProcState contains basic metadata and process ownership info for the specified process type ProcState struct { Name string Username string @@ -151,6 +176,7 @@ type ProcState struct { Processor int } +// ProcMem contains memory statistics for a specified process type ProcMem struct { Size uint64 Resident uint64 @@ -160,6 +186,7 @@ type ProcMem struct { PageFaults uint64 } +// ProcTime contains run time statistics for a specified process type ProcTime struct { StartTime uint64 User uint64 @@ -167,26 +194,31 @@ type ProcTime struct { Total uint64 } +// ProcArgs contains a list of args for a specified process type ProcArgs struct { List []string } +// ProcEnv contains a map of environment variables for specified process type ProcEnv struct { Vars map[string]string } +// ProcExe contains basic data about a specified process type ProcExe struct { Name string Cwd string Root string } +// ProcFDUsage contains data on file limits and usage type ProcFDUsage struct { Open uint64 SoftLimit uint64 HardLimit uint64 } +// Rusage contains data on resource usage for a specified process type Rusage struct { Utime time.Duration Stime time.Duration diff --git a/vendor/github.com/elastic/gosigar/sigar_windows.go b/vendor/github.com/elastic/gosigar/sigar_windows.go index fc868daf3..d1204b80e 100644 --- a/vendor/github.com/elastic/gosigar/sigar_windows.go +++ b/vendor/github.com/elastic/gosigar/sigar_windows.go @@ -8,7 +8,6 @@ import ( "path/filepath" "runtime" "strings" - "sync" "syscall" "time" @@ -24,11 +23,6 @@ var ( // 2003 and XP where PROCESS_QUERY_LIMITED_INFORMATION is unknown. For all newer // OS versions it is set to PROCESS_QUERY_LIMITED_INFORMATION. processQueryLimitedInfoAccess = windows.PROCESS_QUERY_LIMITED_INFORMATION - - // bootTime is the time when the OS was last booted. This value may be nil - // on operating systems that do not support the WMI query used to obtain it. - bootTime *time.Time - bootTimeLock sync.Mutex ) func init() { @@ -63,19 +57,11 @@ func (self *Uptime) Get() error { if !version.IsWindowsVistaOrGreater() { return ErrNotImplemented{runtime.GOOS} } - - bootTimeLock.Lock() - defer bootTimeLock.Unlock() - if bootTime == nil { - uptime, err := windows.GetTickCount64() - if err != nil { - return errors.Wrap(err, "failed to get boot time using win32 api") - } - var boot = time.Unix(int64(uptime), 0) - bootTime = &boot + uptimeMs, err := windows.GetTickCount64() + if err != nil { + return errors.Wrap(err, "failed to get boot time using GetTickCount64 api") } - - self.Length = time.Since(*bootTime).Seconds() + self.Length = float64(time.Duration(uptimeMs)*time.Millisecond) / float64(time.Second) return nil } diff --git a/vendor/github.com/elastic/gosigar/sys/windows/doc.go b/vendor/github.com/elastic/gosigar/sys/windows/doc.go index dda57aa83..9dca12504 100644 --- a/vendor/github.com/elastic/gosigar/sys/windows/doc.go +++ b/vendor/github.com/elastic/gosigar/sys/windows/doc.go @@ -1,2 +1,8 @@ // Package windows contains various Windows system call. package windows + +// Use "go generate -v -x ." to generate the source. + +// Add -trace to enable debug prints around syscalls. +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=true -output zsyscall_windows.go syscall_windows.go +//go:generate go run fix_generated.go -input zsyscall_windows.go diff --git a/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go index 0c11fda31..371eb256b 100644 --- a/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go +++ b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go @@ -580,11 +580,6 @@ func GetTickCount64() (uptime uint64, err error) { return uptime, nil } -// Use "GOOS=windows go generate -v -x ." to generate the source. - -// Add -trace to enable debug prints around syscalls. -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zsyscall_windows.go syscall_windows.go - // Windows API calls //sys _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx //sys _GetLogicalDriveStringsW(bufferLength uint32, buffer *uint16) (length uint32, err error) = kernel32.GetLogicalDriveStringsW diff --git a/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go b/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go index cd5d9ca32..75f19c0ea 100644 --- a/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go +++ b/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go @@ -5,6 +5,8 @@ package windows import ( "syscall" "unsafe" + + "golang.org/x/sys/windows" ) var _ unsafe.Pointer @@ -35,10 +37,10 @@ func errnoErr(e syscall.Errno) error { } var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - modpsapi = syscall.NewLazyDLL("psapi.dll") - modntdll = syscall.NewLazyDLL("ntdll.dll") - modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modpsapi = windows.NewLazySystemDLL("psapi.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") diff --git a/vendor/github.com/jackpal/go-nat-pmp/.travis.yml b/vendor/github.com/jackpal/go-nat-pmp/.travis.yml index b939153f7..3f468e74b 100644 --- a/vendor/github.com/jackpal/go-nat-pmp/.travis.yml +++ b/vendor/github.com/jackpal/go-nat-pmp/.travis.yml @@ -1,7 +1,7 @@ language: go go: - - 1.6.2 + - 1.13.4 - tip allowed_failures: @@ -11,10 +11,3 @@ install: - go get -d -v ./... && go install -race -v ./... script: go test -race -v ./... - -sudo: false - -addons: - apt: - packages: - - iproute2 diff --git a/vendor/github.com/jackpal/go-nat-pmp/README.md b/vendor/github.com/jackpal/go-nat-pmp/README.md index 3ca687f0b..cc45afe56 100644 --- a/vendor/github.com/jackpal/go-nat-pmp/README.md +++ b/vendor/github.com/jackpal/go-nat-pmp/README.md @@ -6,7 +6,7 @@ IP address of a firewall. NAT-PMP is supported by Apple brand routers and open source routers like Tomato and DD-WRT. -See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 +See https://tools.ietf.org/rfc/rfc6886.txt [![Build Status](https://travis-ci.org/jackpal/go-nat-pmp.svg)](https://travis-ci.org/jackpal/go-nat-pmp) @@ -14,27 +14,53 @@ See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 Get the package --------------- + # Get the go-nat-pmp package. go get -u github.com/jackpal/go-nat-pmp - + Usage ----- +Get one more package, used by the example code: + + go get -u github.com/jackpal/gateway + + Create a directory: + + cd ~/go + mkdir -p src/hello + cd src/hello + +Create a file hello.go with these contents: + + package main + import ( + "fmt" + "github.com/jackpal/gateway" natpmp "github.com/jackpal/go-nat-pmp" ) - gatewayIP, err = gateway.DiscoverGateway() - if err != nil { - return + func main() { + gatewayIP, err := gateway.DiscoverGateway() + if err != nil { + return + } + + client := natpmp.NewClient(gatewayIP) + response, err := client.GetExternalAddress() + if err != nil { + return + } + fmt.Printf("External IP address: %v\n", response.ExternalIPAddress) } - client := natpmp.NewClient(gatewayIP) - response, err := client.GetExternalAddress() - if err != nil { - return - } - print("External IP address:", response.ExternalIPAddress) +Build the example + + go build + ./hello + + External IP address: [www xxx yyy zzz] Clients ------- diff --git a/vendor/github.com/jackpal/go-nat-pmp/natpmp.go b/vendor/github.com/jackpal/go-nat-pmp/natpmp.go index e42065306..f296c817e 100644 --- a/vendor/github.com/jackpal/go-nat-pmp/natpmp.go +++ b/vendor/github.com/jackpal/go-nat-pmp/natpmp.go @@ -3,34 +3,43 @@ package natpmp import ( "fmt" "net" + "time" ) // Implement the NAT-PMP protocol, typically supported by Apple routers and open source // routers such as DD-WRT and Tomato. // -// See http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 +// See https://tools.ietf.org/rfc/rfc6886.txt // // Usage: // // client := natpmp.NewClient(gatewayIP) // response, err := client.GetExternalAddress() -// The recommended mapping lifetime for AddPortMapping +// The recommended mapping lifetime for AddPortMapping. const RECOMMENDED_MAPPING_LIFETIME_SECONDS = 3600 // Interface used to make remote procedure calls. type caller interface { - call(msg []byte) (result []byte, err error) + call(msg []byte, timeout time.Duration) (result []byte, err error) } // Client is a NAT-PMP protocol client. type Client struct { - caller caller + caller caller + timeout time.Duration } // Create a NAT-PMP client for the NAT-PMP server at the gateway. +// Uses default timeout which is around 128 seconds. func NewClient(gateway net.IP) (nat *Client) { - return &Client{&network{gateway}} + return &Client{&network{gateway}, 0} +} + +// Create a NAT-PMP client for the NAT-PMP server at the gateway, with a timeout. +// Timeout defines the total amount of time we will keep retrying before giving up. +func NewClientWithTimeout(gateway net.IP, timeout time.Duration) (nat *Client) { + return &Client{&network{gateway}, timeout} } // Results of the NAT-PMP GetExternalAddress operation. @@ -40,6 +49,8 @@ type GetExternalAddressResult struct { } // Get the external address of the router. +// +// Note that this call can take up to 128 seconds to return. func (n *Client) GetExternalAddress() (result *GetExternalAddressResult, err error) { msg := make([]byte, 2) msg[0] = 0 // Version 0 @@ -62,7 +73,8 @@ type AddPortMappingResult struct { PortMappingLifetimeInSeconds uint32 } -// Add (or delete) a port mapping. To delete a mapping, set the requestedExternalPort and lifetime to 0 +// Add (or delete) a port mapping. To delete a mapping, set the requestedExternalPort and lifetime to 0. +// Note that this call can take up to 128 seconds to return. func (n *Client) AddPortMapping(protocol string, internalPort, requestedExternalPort int, lifetime int) (result *AddPortMappingResult, err error) { var opcode byte if protocol == "udp" { @@ -76,6 +88,7 @@ func (n *Client) AddPortMapping(protocol string, internalPort, requestedExternal msg := make([]byte, 12) msg[0] = 0 // Version 0 msg[1] = opcode + // [2:3] is reserved. writeNetworkOrderUint16(msg[4:6], uint16(internalPort)) writeNetworkOrderUint16(msg[6:8], uint16(requestedExternalPort)) writeNetworkOrderUint32(msg[8:12], uint32(lifetime)) @@ -92,7 +105,7 @@ func (n *Client) AddPortMapping(protocol string, internalPort, requestedExternal } func (n *Client) rpc(msg []byte, resultSize int) (result []byte, err error) { - result, err = n.caller.call(msg) + result, err = n.caller.call(msg, n.timeout) if err != nil { return } diff --git a/vendor/github.com/jackpal/go-nat-pmp/network.go b/vendor/github.com/jackpal/go-nat-pmp/network.go index 9def1acda..c42b4fee9 100644 --- a/vendor/github.com/jackpal/go-nat-pmp/network.go +++ b/vendor/github.com/jackpal/go-nat-pmp/network.go @@ -2,7 +2,6 @@ package natpmp import ( "fmt" - "log" "net" "time" ) @@ -16,7 +15,7 @@ type network struct { gateway net.IP } -func (n *network) call(msg []byte) (result []byte, err error) { +func (n *network) call(msg []byte, timeout time.Duration) (result []byte, err error) { var server net.UDPAddr server.IP = n.gateway server.Port = nAT_PMP_PORT @@ -29,12 +28,18 @@ func (n *network) call(msg []byte) (result []byte, err error) { // 16 bytes is the maximum result size. result = make([]byte, 16) + var finalTimeout time.Time + if timeout != 0 { + finalTimeout = time.Now().Add(timeout) + } + needNewDeadline := true var tries uint - for tries = 0; tries < nAT_TRIES; { + for tries = 0; (tries < nAT_TRIES && finalTimeout.IsZero()) || time.Now().Before(finalTimeout); { if needNewDeadline { - err = conn.SetDeadline(time.Now().Add((nAT_INITIAL_MS << tries) * time.Millisecond)) + nextDeadline := time.Now().Add((nAT_INITIAL_MS << tries) * time.Millisecond) + err = conn.SetDeadline(minTime(nextDeadline, finalTimeout)) if err != nil { return } @@ -56,7 +61,6 @@ func (n *network) call(msg []byte) (result []byte, err error) { return } if !remoteAddr.IP.Equal(n.gateway) { - log.Printf("Ignoring packet because IPs differ:", remoteAddr, n.gateway) // Ignore this packet. // Continue without increasing retransmission timeout or deadline. continue @@ -70,3 +74,16 @@ func (n *network) call(msg []byte) (result []byte, err error) { err = fmt.Errorf("Timed out trying to contact gateway") return } + +func minTime(a, b time.Time) time.Time { + if a.IsZero() { + return b + } + if b.IsZero() { + return a + } + if a.Before(b) { + return a + } + return b +} diff --git a/vendor/github.com/jackpal/go-nat-pmp/recorder.go b/vendor/github.com/jackpal/go-nat-pmp/recorder.go index e70a3c65c..845703672 100644 --- a/vendor/github.com/jackpal/go-nat-pmp/recorder.go +++ b/vendor/github.com/jackpal/go-nat-pmp/recorder.go @@ -1,5 +1,7 @@ package natpmp +import "time" + type callObserver interface { observeCall(msg []byte, result []byte, err error) } @@ -10,8 +12,8 @@ type recorder struct { observer callObserver } -func (n *recorder) call(msg []byte) (result []byte, err error) { - result, err = n.child.call(msg) +func (n *recorder) call(msg []byte, timeout time.Duration) (result []byte, err error) { + result, err = n.child.call(msg, timeout) n.observer.observeCall(msg, result, err) return } diff --git a/vendor/github.com/rs/cors/.travis.yml b/vendor/github.com/rs/cors/.travis.yml index 17e5e50d5..9a68b5676 100644 --- a/vendor/github.com/rs/cors/.travis.yml +++ b/vendor/github.com/rs/cors/.travis.yml @@ -1,7 +1,8 @@ language: go go: -- 1.9 - "1.10" +- "1.11" +- "1.12" - tip matrix: allow_failures: diff --git a/vendor/github.com/rs/cors/cors.go b/vendor/github.com/rs/cors/cors.go index d301ca724..273093463 100644 --- a/vendor/github.com/rs/cors/cors.go +++ b/vendor/github.com/rs/cors/cors.go @@ -5,8 +5,8 @@ as defined by http://www.w3.org/TR/cors/ You can configure it by passing an option struct to cors.New: c := cors.New(cors.Options{ - AllowedOrigins: []string{"foo.com"}, - AllowedMethods: []string{"GET", "POST", "DELETE"}, + AllowedOrigins: []string{"foo.com"}, + AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodDelete}, AllowCredentials: true, }) @@ -69,10 +69,15 @@ type Options struct { Debug bool } +// Logger generic interface for logger +type Logger interface { + Printf(string, ...interface{}) +} + // Cors http handler type Cors struct { // Debug logger - Log *log.Logger + Log Logger // Normalized list of plain allowed origins allowedOrigins []string // List of allowed origins containing wildcards @@ -106,7 +111,7 @@ func New(options Options) *Cors { maxAge: options.MaxAge, optionPassthrough: options.OptionsPassthrough, } - if options.Debug { + if options.Debug && c.Log == nil { c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags) } @@ -161,7 +166,7 @@ func New(options Options) *Cors { // Allowed Methods if len(options.AllowedMethods) == 0 { // Default is spec's "simple" methods - c.allowedMethods = []string{"GET", "POST", "HEAD"} + c.allowedMethods = []string{http.MethodGet, http.MethodPost, http.MethodHead} } else { c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper) } @@ -178,8 +183,15 @@ func Default() *Cors { // origins with all standard methods with any header and credentials. func AllowAll() *Cors { return New(Options{ - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"}, + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{ + http.MethodHead, + http.MethodGet, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + }, AllowedHeaders: []string{"*"}, AllowCredentials: false, }) @@ -304,10 +316,6 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { headers := w.Header() origin := r.Header.Get("Origin") - if r.Method == http.MethodOptions { - c.logf(" Actual request no headers added: method == %s", r.Method) - return - } // Always set Vary, see https://github.com/rs/cors/issues/10 headers.Add("Vary", "Origin") if origin == "" { @@ -342,7 +350,7 @@ func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { c.logf(" Actual response added headers: %v", headers) } -// convenience method. checks if debugging is turned on before printing +// convenience method. checks if a logger is set. func (c *Cors) logf(format string, a ...interface{}) { if c.Log != nil { c.Log.Printf(format, a...) diff --git a/vendor/github.com/rs/cors/utils.go b/vendor/github.com/rs/cors/utils.go index 53ad9e9db..db83ac3ea 100644 --- a/vendor/github.com/rs/cors/utils.go +++ b/vendor/github.com/rs/cors/utils.go @@ -12,7 +12,7 @@ type wildcard struct { } func (w wildcard) match(s string) bool { - return len(s) >= len(w.prefix+w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix) + return len(s) >= len(w.prefix)+len(w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix) } // convert converts a list of string using the passed converter function diff --git a/vendor/github.com/status-im/status-go/eth-node/bridge/geth/envelope.go b/vendor/github.com/status-im/status-go/eth-node/bridge/geth/envelope.go index 884760b06..64b9306bf 100644 --- a/vendor/github.com/status-im/status-go/eth-node/bridge/geth/envelope.go +++ b/vendor/github.com/status-im/status-go/eth-node/bridge/geth/envelope.go @@ -2,29 +2,102 @@ package gethbridge import ( "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/waku" "github.com/status-im/status-go/whisper/v6" ) -type gethEnvelopeWrapper struct { - envelope *whisper.Envelope +type whisperEnvelope struct { + env *whisper.Envelope } -// NewGethEnvelopeWrapper returns an object that wraps Geth's Envelope in a types interface -func NewGethEnvelopeWrapper(e *whisper.Envelope) types.Envelope { - return &gethEnvelopeWrapper{ - envelope: e, +// NewWhisperEnvelope returns an object that wraps Geth's Whisper Envelope in a types interface. +func NewWhisperEnvelope(e *whisper.Envelope) types.Envelope { + return &whisperEnvelope{env: e} +} + +func UnwrapWhisperEnvelope(e types.Envelope) (*whisper.Envelope, bool) { + if env, ok := e.(*whisperEnvelope); ok { + return env.env, true } + return nil, false } -// GetGethEnvelopeFrom retrieves the underlying whisper Envelope struct from a wrapped Envelope interface -func GetGethEnvelopeFrom(f types.Envelope) *whisper.Envelope { - return f.(*gethEnvelopeWrapper).envelope +func MustUnwrapWhisperEnvelope(e types.Envelope) *whisper.Envelope { + return e.(*whisperEnvelope).env } -func (w *gethEnvelopeWrapper) Hash() types.Hash { - return types.Hash(w.envelope.Hash()) +func (w *whisperEnvelope) Hash() types.Hash { + return types.Hash(w.env.Hash()) } -func (w *gethEnvelopeWrapper) Bloom() []byte { - return w.envelope.Bloom() +func (w *whisperEnvelope) Bloom() []byte { + return w.env.Bloom() +} + +func (w *whisperEnvelope) PoW() float64 { + return w.env.PoW() +} + +func (w *whisperEnvelope) Expiry() uint32 { + return w.env.Expiry +} + +func (w *whisperEnvelope) TTL() uint32 { + return w.env.TTL +} + +func (w *whisperEnvelope) Topic() types.TopicType { + return types.TopicType(w.env.Topic) +} + +func (w *whisperEnvelope) Size() int { + return len(w.env.Data) +} + +type wakuEnvelope struct { + env *waku.Envelope +} + +// NewWakuEnvelope returns an object that wraps Geth's Waku Envelope in a types interface. +func NewWakuEnvelope(e *waku.Envelope) types.Envelope { + return &wakuEnvelope{env: e} +} + +func UnwrapWakuEnvelope(e types.Envelope) (*waku.Envelope, bool) { + if env, ok := e.(*wakuEnvelope); ok { + return env.env, true + } + return nil, false +} + +func MustUnwrapWakuEnvelope(e types.Envelope) *waku.Envelope { + return e.(*wakuEnvelope).env +} + +func (w *wakuEnvelope) Hash() types.Hash { + return types.Hash(w.env.Hash()) +} + +func (w *wakuEnvelope) Bloom() []byte { + return w.env.Bloom() +} + +func (w *wakuEnvelope) PoW() float64 { + return w.env.PoW() +} + +func (w *wakuEnvelope) Expiry() uint32 { + return w.env.Expiry +} + +func (w *wakuEnvelope) TTL() uint32 { + return w.env.TTL +} + +func (w *wakuEnvelope) Topic() types.TopicType { + return types.TopicType(w.env.Topic) +} + +func (w *wakuEnvelope) Size() int { + return len(w.env.Data) } diff --git a/vendor/github.com/status-im/status-go/eth-node/bridge/geth/whisper.go b/vendor/github.com/status-im/status-go/eth-node/bridge/geth/whisper.go index 53e9bf005..8e64db81c 100644 --- a/vendor/github.com/status-im/status-go/eth-node/bridge/geth/whisper.go +++ b/vendor/github.com/status-im/status-go/eth-node/bridge/geth/whisper.go @@ -166,7 +166,7 @@ func (w *gethWhisperWrapper) SendMessagesRequest(peerID []byte, r types.Messages // which are not supposed to be forwarded any further. // The whisper protocol is agnostic of the format and contents of envelope. func (w *gethWhisperWrapper) RequestHistoricMessagesWithTimeout(peerID []byte, envelope types.Envelope, timeout time.Duration) error { - return w.whisper.RequestHistoricMessagesWithTimeout(peerID, GetGethEnvelopeFrom(envelope), timeout) + return w.whisper.RequestHistoricMessagesWithTimeout(peerID, MustUnwrapWhisperEnvelope(envelope), timeout) } // SyncMessages can be sent between two Mail Servers and syncs envelopes between them. diff --git a/vendor/github.com/status-im/status-go/eth-node/types/envelopes.go b/vendor/github.com/status-im/status-go/eth-node/types/envelopes.go index 997343330..7f1cb424f 100644 --- a/vendor/github.com/status-im/status-go/eth-node/types/envelopes.go +++ b/vendor/github.com/status-im/status-go/eth-node/types/envelopes.go @@ -5,6 +5,11 @@ package types type Envelope interface { Hash() Hash // Cached hash of the envelope to avoid rehashing every time. Bloom() []byte + PoW() float64 + Expiry() uint32 + TTL() uint32 + Topic() TopicType + Size() int } // EventType used to define known envelope events. diff --git a/vendor/github.com/status-im/status-go/eth-node/types/hash.go b/vendor/github.com/status-im/status-go/eth-node/types/hash.go index 2b5dec17c..5c9d7c0e8 100644 --- a/vendor/github.com/status-im/status-go/eth-node/types/hash.go +++ b/vendor/github.com/status-im/status-go/eth-node/types/hash.go @@ -50,7 +50,7 @@ func (h Hash) Bytes() []byte { return h[:] } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. -func (h *Hash) String() string { +func (h Hash) String() string { return h.Hex() } diff --git a/vendor/github.com/status-im/status-go/protocol/go.sum b/vendor/github.com/status-im/status-go/protocol/go.sum index 7886435ed..a146328d3 100644 --- a/vendor/github.com/status-im/status-go/protocol/go.sum +++ b/vendor/github.com/status-im/status-go/protocol/go.sum @@ -11,12 +11,14 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -30,12 +32,16 @@ github.com/allegro/bigcache v1.2.0 h1:qDaE0QoF29wKBb3+pXFrJFy1ihe5OT9OiXhg1t85Sx github.com/allegro/bigcache v1.2.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20181002214814-33151c4543a7/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5 h1:L0TwgZQo7Mga9im6FvKEZGIvyLE/VG/HI5loz5LpvC0= github.com/aristanetworks/goarista v0.0.0-20190219163901-728bce664cf5/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 h1:tS7jSmwRqSxTnonTRlDD1oHo6Q9YOK4xHS9/v4L56eg= github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= @@ -137,6 +143,7 @@ github.com/fjl/memsize v0.0.0-20180929194037-2a09253e352a/go.mod h1:VvhXpOYNQvB+ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= @@ -209,6 +216,7 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= @@ -224,6 +232,7 @@ github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -241,11 +250,13 @@ github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQ github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s= @@ -268,6 +279,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -279,6 +292,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -428,6 +442,8 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opentracing/opentracing-go v0.0.0-20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -440,17 +456,20 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v0.0.0-20170902204657-a37ad3984311/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -461,12 +480,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= @@ -482,6 +503,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315 h1:H3hCXwP92pH/hSgNrCLtjxvsKJ50sq26nICbZuoR1tQ= github.com/russolsen/ohyeah v0.0.0-20160324131710-f4938c005315/go.mod h1:ZbKa3zlLnhGF1dAeJtMSoNtM5LgFQnqzq8eYH3uYYkU= @@ -531,6 +553,7 @@ github.com/status-im/status-go v0.37.3/go.mod h1:9qHQ2+8NS6ivPJS5YbsI3gWkr0t6DWm github.com/status-im/status-go/extkeys v1.0.0 h1:Qyirsoi5Ye5UFfisgPtCjPb/RkBxyK+UsSiEcr2PVlM= github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU= github.com/status-im/status-go/protocol v1.0.1/go.mod h1:LpA7BsaNmj6EOdq7BwuqncewjPqIRHCletZOb2wlWrY= +github.com/status-im/status-go/waku v1.0.0/go.mod h1:1bjvQAL4cJYtxCsm6DnKdJbxcZwnvvZmxb6pmoUDtuY= github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk= github.com/status-im/whisper v1.5.2 h1:26NgiKusmPic38eQdtXnaY+iaQ/LuQ3Dh0kCGYT/Uxs= github.com/status-im/whisper v1.5.2/go.mod h1:emrOxzJme0k66QtbbQ2bdd3P8RCdLZ8sTD7SkwH1s2s= @@ -553,7 +576,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 h1:kjbwitOGH46vD01f2s3leBfrMnePQa3NSAIlW35MvY8= github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9/go.mod h1:EcGP24b8DY+bWHnpfJDP7fM+o8Nmz4fYH0l2xTtNr3I= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= @@ -583,6 +609,8 @@ github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVT github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -609,6 +637,7 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -620,6 +649,7 @@ golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIo golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -647,6 +677,7 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -673,12 +704,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk= @@ -700,7 +734,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 h1:LCmXVkvpQCDj724eX6irUTPCJP5GelFHxqGSWL2D1R0= @@ -721,7 +757,9 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= @@ -733,6 +771,11 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= @@ -740,6 +783,7 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= @@ -754,5 +798,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/status-im/status-go/waku/api.go b/vendor/github.com/status-im/status-go/waku/api.go new file mode 100644 index 000000000..73712bf7a --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/api.go @@ -0,0 +1,600 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "context" + "crypto/ecdsa" + "errors" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/rpc" +) + +// List of errors +var ( + ErrSymAsym = errors.New("specify either a symmetric or an asymmetric key") + ErrInvalidSymmetricKey = errors.New("invalid symmetric key") + ErrInvalidPublicKey = errors.New("invalid public key") + ErrInvalidSigningPubKey = errors.New("invalid signing public key") + ErrTooLowPoW = errors.New("message rejected, PoW too low") + ErrNoTopics = errors.New("missing topic(s)") +) + +// PublicWakuAPI provides the waku RPC service that can be +// use publicly without security implications. +type PublicWakuAPI struct { + w *Waku + + mu sync.Mutex + lastUsed map[string]time.Time // keeps track when a filter was polled for the last time. +} + +// NewPublicWakuAPI create a new RPC waku service. +func NewPublicWakuAPI(w *Waku) *PublicWakuAPI { + api := &PublicWakuAPI{ + w: w, + lastUsed: make(map[string]time.Time), + } + return api +} + +// Version returns the Waku sub-protocol version. +func (api *PublicWakuAPI) Version(ctx context.Context) string { + return ProtocolVersionStr +} + +// Info contains diagnostic information. +type Info struct { + Messages int `json:"messages"` // Number of floating messages. + MinPow float64 `json:"minPow"` // Minimal accepted PoW + MaxMessageSize uint32 `json:"maxMessageSize"` // Maximum accepted message size +} + +// Info returns diagnostic information about the waku node. +func (api *PublicWakuAPI) Info(ctx context.Context) Info { + return Info{ + Messages: len(api.w.msgQueue) + len(api.w.p2pMsgQueue), + MinPow: api.w.MinPow(), + MaxMessageSize: api.w.MaxMessageSize(), + } +} + +// SetMaxMessageSize sets the maximum message size that is accepted. +// Upper limit is defined by MaxMessageSize. +func (api *PublicWakuAPI) SetMaxMessageSize(ctx context.Context, size uint32) (bool, error) { + return true, api.w.SetMaxMessageSize(size) +} + +// SetMinPoW sets the minimum PoW, and notifies the peers. +func (api *PublicWakuAPI) SetMinPoW(ctx context.Context, pow float64) (bool, error) { + return true, api.w.SetMinimumPoW(pow, true) +} + +// SetBloomFilter sets the new value of bloom filter, and notifies the peers. +func (api *PublicWakuAPI) SetBloomFilter(ctx context.Context, bloom hexutil.Bytes) (bool, error) { + return true, api.w.SetBloomFilter(bloom) +} + +// MarkTrustedPeer marks a peer trusted, which will allow it to send historic (expired) messages. +// Note: This function is not adding new nodes, the node needs to exists as a peer. +func (api *PublicWakuAPI) MarkTrustedPeer(ctx context.Context, url string) (bool, error) { + n, err := enode.Parse(enode.ValidSchemes, url) + if err != nil { + return false, err + } + return true, api.w.AllowP2PMessagesFromPeer(n.ID().Bytes()) +} + +// NewKeyPair generates a new public and private key pair for message decryption and encryption. +// It returns an ID that can be used to refer to the keypair. +func (api *PublicWakuAPI) NewKeyPair(ctx context.Context) (string, error) { + return api.w.NewKeyPair() +} + +// AddPrivateKey imports the given private key. +func (api *PublicWakuAPI) AddPrivateKey(ctx context.Context, privateKey hexutil.Bytes) (string, error) { + key, err := crypto.ToECDSA(privateKey) + if err != nil { + return "", err + } + return api.w.AddKeyPair(key) +} + +// DeleteKeyPair removes the key with the given key if it exists. +func (api *PublicWakuAPI) DeleteKeyPair(ctx context.Context, key string) (bool, error) { + if ok := api.w.DeleteKeyPair(key); ok { + return true, nil + } + return false, fmt.Errorf("key pair %s not found", key) +} + +// HasKeyPair returns an indication if the node has a key pair that is associated with the given id. +func (api *PublicWakuAPI) HasKeyPair(ctx context.Context, id string) bool { + return api.w.HasKeyPair(id) +} + +// GetPublicKey returns the public key associated with the given key. The key is the hex +// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. +func (api *PublicWakuAPI) GetPublicKey(ctx context.Context, id string) (hexutil.Bytes, error) { + key, err := api.w.GetPrivateKey(id) + if err != nil { + return hexutil.Bytes{}, err + } + return crypto.FromECDSAPub(&key.PublicKey), nil +} + +// GetPrivateKey returns the private key associated with the given key. The key is the hex +// encoded representation of a key in the form specified in section 4.3.6 of ANSI X9.62. +func (api *PublicWakuAPI) GetPrivateKey(ctx context.Context, id string) (hexutil.Bytes, error) { + key, err := api.w.GetPrivateKey(id) + if err != nil { + return hexutil.Bytes{}, err + } + return crypto.FromECDSA(key), nil +} + +// NewSymKey generate a random symmetric key. +// It returns an ID that can be used to refer to the key. +// Can be used encrypting and decrypting messages where the key is known to both parties. +func (api *PublicWakuAPI) NewSymKey(ctx context.Context) (string, error) { + return api.w.GenerateSymKey() +} + +// AddSymKey import a symmetric key. +// It returns an ID that can be used to refer to the key. +// Can be used encrypting and decrypting messages where the key is known to both parties. +func (api *PublicWakuAPI) AddSymKey(ctx context.Context, key hexutil.Bytes) (string, error) { + return api.w.AddSymKeyDirect([]byte(key)) +} + +// GenerateSymKeyFromPassword derive a key from the given password, stores it, and returns its ID. +func (api *PublicWakuAPI) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) { + return api.w.AddSymKeyFromPassword(passwd) +} + +// HasSymKey returns an indication if the node has a symmetric key associated with the given key. +func (api *PublicWakuAPI) HasSymKey(ctx context.Context, id string) bool { + return api.w.HasSymKey(id) +} + +// GetSymKey returns the symmetric key associated with the given id. +func (api *PublicWakuAPI) GetSymKey(ctx context.Context, id string) (hexutil.Bytes, error) { + return api.w.GetSymKey(id) +} + +// DeleteSymKey deletes the symmetric key that is associated with the given id. +func (api *PublicWakuAPI) DeleteSymKey(ctx context.Context, id string) bool { + return api.w.DeleteSymKey(id) +} + +// MakeLightClient turns the node into light client, which does not forward +// any incoming messages, and sends only messages originated in this node. +func (api *PublicWakuAPI) MakeLightClient(ctx context.Context) bool { + api.w.SetLightClientMode(true) + return api.w.LightClientMode() +} + +// CancelLightClient cancels light client mode. +func (api *PublicWakuAPI) CancelLightClient(ctx context.Context) bool { + api.w.SetLightClientMode(false) + return !api.w.LightClientMode() +} + +//go:generate gencodec -type NewMessage -field-override newMessageOverride -out gen_newmessage_json.go + +// NewMessage represents a new waku message that is posted through the RPC. +type NewMessage struct { + SymKeyID string `json:"symKeyID"` + PublicKey []byte `json:"pubKey"` + Sig string `json:"sig"` + TTL uint32 `json:"ttl"` + Topic TopicType `json:"topic"` + Payload []byte `json:"payload"` + Padding []byte `json:"padding"` + PowTime uint32 `json:"powTime"` + PowTarget float64 `json:"powTarget"` + TargetPeer string `json:"targetPeer"` +} + +type newMessageOverride struct { + PublicKey hexutil.Bytes + Payload hexutil.Bytes + Padding hexutil.Bytes +} + +// Post posts a message on the Waku network. +// returns the hash of the message in case of success. +func (api *PublicWakuAPI) Post(ctx context.Context, req NewMessage) (hexutil.Bytes, error) { + var ( + symKeyGiven = len(req.SymKeyID) > 0 + pubKeyGiven = len(req.PublicKey) > 0 + err error + ) + + // user must specify either a symmetric or an asymmetric key + if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { + return nil, ErrSymAsym + } + + params := &MessageParams{ + TTL: req.TTL, + Payload: req.Payload, + Padding: req.Padding, + WorkTime: req.PowTime, + PoW: req.PowTarget, + Topic: req.Topic, + } + + // 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 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 nil, ErrNoTopics + } + if params.KeySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { + return nil, err + } + if !validateDataIntegrity(params.KeySym, aesKeyLength) { + return nil, ErrInvalidSymmetricKey + } + } + + // Set asymmetric key that is used to encrypt the message + if pubKeyGiven { + if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil { + return nil, ErrInvalidPublicKey + } + } + + // encrypt and sent message + msg, err := NewSentMessage(params) + if err != nil { + return nil, err + } + + var result []byte + env, err := msg.Wrap(params, api.w.CurrentTime()) + if err != nil { + return nil, err + } + + // send to specific node (skip PoW check) + if len(req.TargetPeer) > 0 { + n, err := enode.Parse(enode.ValidSchemes, req.TargetPeer) + if err != nil { + return nil, fmt.Errorf("failed to parse target peer: %s", err) + } + err = api.w.SendP2PMessages(n.ID().Bytes(), env) + if err == nil { + hash := env.Hash() + result = hash[:] + } + return result, err + } + + // ensure that the message PoW meets the node's minimum accepted PoW + if req.PowTarget < api.w.MinPow() { + return nil, ErrTooLowPoW + } + + err = api.w.Send(env) + if err == nil { + hash := env.Hash() + result = hash[:] + } + return result, err +} + +// UninstallFilter is alias for Unsubscribe +func (api *PublicWakuAPI) UninstallFilter(id string) { + api.w.Unsubscribe(id) +} + +// Unsubscribe disables and removes an existing filter. +func (api *PublicWakuAPI) 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. +type Criteria struct { + SymKeyID string `json:"symKeyID"` + PrivateKeyID string `json:"privateKeyID"` + Sig []byte `json:"sig"` + MinPow float64 `json:"minPow"` + Topics []TopicType `json:"topics"` + AllowP2P bool `json:"allowP2P"` +} + +type criteriaOverride struct { + Sig hexutil.Bytes +} + +// Messages set up a subscription that fires events when messages arrive that match +// the given set of criteria. +func (api *PublicWakuAPI) Messages(ctx context.Context, crit Criteria) (*rpc.Subscription, error) { + var ( + symKeyGiven = len(crit.SymKeyID) > 0 + pubKeyGiven = len(crit.PrivateKeyID) > 0 + err error + ) + + // ensure that the RPC connection supports subscriptions + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return nil, rpc.ErrNotificationsUnsupported + } + + // user must specify either a symmetric or an asymmetric key + if (symKeyGiven && pubKeyGiven) || (!symKeyGiven && !pubKeyGiven) { + return nil, ErrSymAsym + } + + filter := Filter{ + PoW: crit.MinPow, + Messages: NewMemoryMessageStore(), + AllowP2P: crit.AllowP2P, + } + + if len(crit.Sig) > 0 { + if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil { + return nil, ErrInvalidSigningPubKey + } + } + + for i, bt := range crit.Topics { + if len(bt) == 0 || len(bt) > 4 { + return nil, fmt.Errorf("subscribe: topic %d has wrong size: %d", i, len(bt)) + } + filter.Topics = append(filter.Topics, bt[:]) + } + + // listen for message that are encrypted with the given symmetric key + if symKeyGiven { + if len(filter.Topics) == 0 { + return nil, ErrNoTopics + } + key, err := api.w.GetSymKey(crit.SymKeyID) + if err != nil { + return nil, err + } + if !validateDataIntegrity(key, aesKeyLength) { + return nil, ErrInvalidSymmetricKey + } + filter.KeySym = key + filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym) + } + + // listen for messages that are encrypted with the given public key + if pubKeyGiven { + filter.KeyAsym, err = api.w.GetPrivateKey(crit.PrivateKeyID) + if err != nil || filter.KeyAsym == nil { + return nil, ErrInvalidPublicKey + } + } + + id, err := api.w.Subscribe(&filter) + if err != nil { + return nil, err + } + + // create subscription and start waiting for message events + rpcSub := notifier.CreateSubscription() + go func() { + // for now poll internally, refactor waku internal for channel support + ticker := time.NewTicker(250 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + if filter := api.w.GetFilter(id); filter != nil { + for _, rpcMessage := range toMessage(filter.Retrieve()) { + if err := notifier.Notify(rpcSub.ID, rpcMessage); err != nil { + log.Error("Failed to send notification", "err", err) + } + } + } + case <-rpcSub.Err(): + _ = api.w.Unsubscribe(id) + return + } + } + }() + + return rpcSub, nil +} + +//go:generate gencodec -type Message -field-override messageOverride -out gen_message_json.go + +// Message is the RPC representation of a waku message. +type Message struct { + Sig []byte `json:"sig,omitempty"` + TTL uint32 `json:"ttl"` + Timestamp uint32 `json:"timestamp"` + Topic TopicType `json:"topic"` + Payload []byte `json:"payload"` + Padding []byte `json:"padding"` + PoW float64 `json:"pow"` + Hash []byte `json:"hash"` + Dst []byte `json:"recipientPublicKey,omitempty"` + P2P bool `json:"bool,omitempty"` +} + +type messageOverride struct { + Sig hexutil.Bytes + Payload hexutil.Bytes + Padding hexutil.Bytes + Hash hexutil.Bytes + Dst hexutil.Bytes +} + +// ToWakuMessage converts an internal message into an API version. +func ToWakuMessage(message *ReceivedMessage) *Message { + msg := Message{ + Payload: message.Payload, + Padding: message.Padding, + Timestamp: message.Sent, + TTL: message.TTL, + PoW: message.PoW, + Hash: message.EnvelopeHash.Bytes(), + Topic: message.Topic, + P2P: message.P2P, + } + + if message.Dst != nil { + b := crypto.FromECDSAPub(message.Dst) + if b != nil { + msg.Dst = b + } + } + + if isMessageSigned(message.Raw[0]) { + b := crypto.FromECDSAPub(message.SigToPubKey()) + if b != nil { + msg.Sig = b + } + } + + return &msg +} + +// toMessage converts a set of messages to its RPC representation. +func toMessage(messages []*ReceivedMessage) []*Message { + msgs := make([]*Message, len(messages)) + for i, msg := range messages { + msgs[i] = ToWakuMessage(msg) + } + return msgs +} + +// GetFilterMessages returns the messages that match the filter criteria and +// are received between the last poll and now. +func (api *PublicWakuAPI) GetFilterMessages(id string) ([]*Message, error) { + api.mu.Lock() + f := api.w.GetFilter(id) + if f == nil { + api.mu.Unlock() + return nil, fmt.Errorf("filter not found") + } + api.lastUsed[id] = time.Now() + api.mu.Unlock() + + receivedMessages := f.Retrieve() + messages := make([]*Message, 0, len(receivedMessages)) + for _, msg := range receivedMessages { + messages = append(messages, ToWakuMessage(msg)) + } + + return messages, nil +} + +// DeleteMessageFilter deletes a filter. +func (api *PublicWakuAPI) DeleteMessageFilter(id string) (bool, error) { + api.mu.Lock() + defer api.mu.Unlock() + + delete(api.lastUsed, id) + return true, api.w.Unsubscribe(id) +} + +// NewMessageFilter creates a new filter that can be used to poll for +// (new) messages that satisfy the given criteria. +func (api *PublicWakuAPI) NewMessageFilter(req Criteria) (string, error) { + var ( + src *ecdsa.PublicKey + keySym []byte + keyAsym *ecdsa.PrivateKey + topics [][]byte + + symKeyGiven = len(req.SymKeyID) > 0 + asymKeyGiven = len(req.PrivateKeyID) > 0 + + err error + ) + + // user must specify either a symmetric or an asymmetric key + if (symKeyGiven && asymKeyGiven) || (!symKeyGiven && !asymKeyGiven) { + return "", ErrSymAsym + } + + if len(req.Sig) > 0 { + if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil { + return "", ErrInvalidSigningPubKey + } + } + + if symKeyGiven { + if keySym, err = api.w.GetSymKey(req.SymKeyID); err != nil { + return "", err + } + if !validateDataIntegrity(keySym, aesKeyLength) { + return "", ErrInvalidSymmetricKey + } + } + + if asymKeyGiven { + if keyAsym, err = api.w.GetPrivateKey(req.PrivateKeyID); err != nil { + return "", err + } + } + + if len(req.Topics) > 0 { + topics = make([][]byte, len(req.Topics)) + for i, topic := range req.Topics { + topics[i] = make([]byte, TopicLength) + copy(topics[i], topic[:]) + } + } + + f := &Filter{ + Src: src, + KeySym: keySym, + KeyAsym: keyAsym, + PoW: req.MinPow, + AllowP2P: req.AllowP2P, + Topics: topics, + Messages: NewMemoryMessageStore(), + } + + id, err := api.w.Subscribe(f) + if err != nil { + return "", err + } + + api.mu.Lock() + api.lastUsed[id] = time.Now() + api.mu.Unlock() + + return id, nil +} diff --git a/vendor/github.com/status-im/status-go/waku/config.go b/vendor/github.com/status-im/status-go/waku/config.go new file mode 100644 index 000000000..2a82a5ffd --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/config.go @@ -0,0 +1,35 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +// Config represents the configuration state of a waku node. +type Config struct { + MaxMessageSize uint32 `toml:",omitempty"` + MinimumAcceptedPoW float64 `toml:",omitempty"` + LightClient bool `toml:",omitempty"` // when true, it does not forward messages + FullNode bool `toml:",omitempty"` // when true, it forwards all messages + RestrictLightClientsConn bool `toml:",omitempty"` // when true, do not accept light client as peers if it is a light client itself + EnableConfirmations bool `toml:",omitempty"` // when true, sends message confirmations +} + +var DefaultConfig = Config{ + MaxMessageSize: DefaultMaxMessageSize, + MinimumAcceptedPoW: DefaultMinimumPoW, + RestrictLightClientsConn: true, +} diff --git a/vendor/github.com/status-im/status-go/waku/doc.go b/vendor/github.com/status-im/status-go/waku/doc.go new file mode 100644 index 000000000..f31ccd76e --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/doc.go @@ -0,0 +1,213 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "errors" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +// Waku protocol parameters +const ( + ProtocolVersion = uint64(0) // Protocol version number + ProtocolVersionStr = "0" // The same, as a string + ProtocolName = "waku" // Nickname of the protocol + + // Waku protocol message codes, according to https://github.com/vacp2p/specs/blob/master/waku.md + statusCode = 0 // used in the handshake + messagesCode = 1 // regular message + powRequirementCode = 2 // node's PoW requirement + bloomFilterExCode = 3 // bloom filter exchange + batchAcknowledgedCode = 11 // confirmation that batch of envelopes was received + messageResponseCode = 12 // includes confirmation for delivery and information about errors + rateLimitingCode = 20 // includes peer's rate limiting settings + p2pRequestCompleteCode = 125 // peer-to-peer message, used by Dapp protocol + p2pRequestCode = 126 // peer-to-peer message, used by Dapp protocol + p2pMessageCode = 127 // peer-to-peer message (to be consumed by the peer, but not forwarded any further) + NumberOfMessageCodes = 128 + + SizeMask = byte(3) // mask used to extract the size of payload size field from the flags + signatureFlag = byte(4) + + TopicLength = 4 // in bytes + signatureLength = crypto.SignatureLength // in bytes + aesKeyLength = 32 // in bytes + aesNonceLength = 12 // in bytes; for more info please see cipher.gcmStandardNonceSize & aesgcm.NonceSize() + keyIDSize = 32 // in bytes + BloomFilterSize = 64 // in bytes + flagsLength = 1 + + EnvelopeHeaderLength = 20 + + MaxMessageSize = uint32(10 * 1024 * 1024) // maximum accepted size of a message. + DefaultMaxMessageSize = uint32(1024 * 1024) + DefaultMinimumPoW = 0.2 + + padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol + messageQueueLimit = 1024 + + expirationCycle = time.Second + transmissionCycle = 300 * time.Millisecond + + DefaultTTL = 50 // seconds + DefaultSyncAllowance = 10 // seconds + + MaxLimitInSyncMailRequest = 1000 + + EnvelopeTimeNotSynced uint = iota + 1 + EnvelopeOtherError + + MaxLimitInMessagesRequest = 1000 +) + +// MailServer represents a mail server, capable of +// archiving the old messages for subsequent delivery +// to the peers. Any implementation must ensure that both +// functions are thread-safe. Also, they must return ASAP. +// DeliverMail should use p2pMessageCode for delivery, +// in order to bypass the expiry checks. +type MailServer interface { + Archive(env *Envelope) + DeliverMail(peerID []byte, request *Envelope) // DEPRECATED; use Deliver() + Deliver(peerID []byte, request MessagesRequest) +} + +// MessagesRequest contains details of a request of historic messages. +type MessagesRequest struct { + // ID of the request. The current implementation requires ID to be 32-byte array, + // however, it's not enforced for future implementation. + ID []byte `json:"id"` + + // From is a lower bound of time range. + From uint32 `json:"from"` + + // To is a upper bound of time range. + To uint32 `json:"to"` + + // Limit determines the number of messages sent by the mail server + // for the current paginated request. + Limit uint32 `json:"limit"` + + // Cursor is used as starting point for paginated requests. + Cursor []byte `json:"cursor"` + + // Bloom is a filter to match requested messages. + Bloom []byte `json:"bloom"` +} + +func (r MessagesRequest) Validate() error { + if len(r.ID) != common.HashLength { + return errors.New("invalid 'ID', expected a 32-byte slice") + } + + if r.From > r.To { + return errors.New("invalid 'From' value which is greater than To") + } + + if r.Limit > MaxLimitInMessagesRequest { + return fmt.Errorf("invalid 'Limit' value, expected value lower than %d", MaxLimitInMessagesRequest) + } + + if len(r.Bloom) == 0 { + return errors.New("invalid 'Bloom' provided") + } + + return nil +} + +// MessagesResponse sent as a response after processing batch of envelopes. +type MessagesResponse struct { + // Hash is a hash of all envelopes sent in the single batch. + Hash common.Hash + // Per envelope error. + Errors []EnvelopeError +} + +// EnvelopeError code and optional description of the error. +type EnvelopeError struct { + Hash common.Hash + Code uint + Description string +} + +// MultiVersionResponse allows to decode response into chosen version. +type MultiVersionResponse struct { + Version uint + Response rlp.RawValue +} + +// DecodeResponse1 decodes response into first version of the messages response. +func (m MultiVersionResponse) DecodeResponse1() (resp MessagesResponse, err error) { + return resp, rlp.DecodeBytes(m.Response, &resp) +} + +// Version1MessageResponse first version of the message response. +type Version1MessageResponse struct { + Version uint + Response MessagesResponse +} + +// NewMessagesResponse returns instance of the version messages response. +func NewMessagesResponse(batch common.Hash, errors []EnvelopeError) Version1MessageResponse { + return Version1MessageResponse{ + Version: 1, + Response: MessagesResponse{ + Hash: batch, + Errors: errors, + }, + } +} + +// ErrorToEnvelopeError converts common golang error into EnvelopeError with a code. +func ErrorToEnvelopeError(hash common.Hash, err error) EnvelopeError { + code := EnvelopeOtherError + switch err.(type) { + case TimeSyncError: + code = EnvelopeTimeNotSynced + } + return EnvelopeError{ + Hash: hash, + Code: code, + Description: err.Error(), + } +} + +// MailServerResponse is the response payload sent by the mailserver. +type MailServerResponse struct { + LastEnvelopeHash common.Hash + Cursor []byte + Error error +} + +// RateLimits contains information about rate limit settings. +// It is exchanged using rateLimitingCode packet or in the handshake. +type RateLimits struct { + IPLimits uint64 // messages per second from a single IP (default 0, no limits) + PeerIDLimits uint64 // messages per second from a single peer ID (default 0, no limits) + TopicLimits uint64 // messages per second from a single topic (default 0, no limits) +} + +func (r RateLimits) IsZero() bool { + return r == (RateLimits{}) +} diff --git a/vendor/github.com/status-im/status-go/waku/envelope.go b/vendor/github.com/status-im/status-go/waku/envelope.go new file mode 100644 index 000000000..e4972ed16 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/envelope.go @@ -0,0 +1,272 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "crypto/ecdsa" + "encoding/binary" + "fmt" + "math" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/rlp" +) + +// Envelope represents a clear-text data packet to transmit through the Waku +// network. Its contents may or may not be encrypted and signed. +type Envelope struct { + Expiry uint32 + TTL uint32 + Topic TopicType + Data []byte + Nonce uint64 + + pow float64 // Message-specific PoW as described in the Waku specification. + + // the following variables should not be accessed directly, use the corresponding function instead: Hash(), Bloom() + hash common.Hash // Cached hash of the envelope to avoid rehashing every time. + bloom []byte +} + +// size returns the size of envelope as it is sent (i.e. public fields only) +func (e *Envelope) size() int { + return EnvelopeHeaderLength + len(e.Data) +} + +// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. +func (e *Envelope) rlpWithoutNonce() []byte { + res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data}) + return res +} + +// NewEnvelope wraps a Waku message with expiration and destination data +// included into an envelope for network forwarding. +func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage, now time.Time) *Envelope { + env := Envelope{ + Expiry: uint32(now.Add(time.Second * time.Duration(ttl)).Unix()), + TTL: ttl, + Topic: topic, + Data: msg.Raw, + Nonce: 0, + } + + return &env +} + +// Seal closes the envelope by spending the requested amount of time as a proof +// of work on hashing the data. +func (e *Envelope) Seal(options *MessageParams) error { + if options.PoW == 0 { + // PoW is not required + return nil + } + + var target, bestLeadingZeros int + if options.PoW < 0 { + // target is not set - the function should run for a period + // of time specified in WorkTime param. Since we can predict + // the execution time, we can also adjust Expiry. + e.Expiry += options.WorkTime + } else { + target = e.powToFirstBit(options.PoW) + } + + rlp := e.rlpWithoutNonce() + buf := make([]byte, len(rlp)+8) + copy(buf, rlp) + asAnInt := new(big.Int) + + finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() + for nonce := uint64(0); time.Now().UnixNano() < finish; { + for i := 0; i < 1024; i++ { + binary.BigEndian.PutUint64(buf[len(rlp):], nonce) + h := crypto.Keccak256(buf) + asAnInt.SetBytes(h) + leadingZeros := 256 - asAnInt.BitLen() + if leadingZeros > bestLeadingZeros { + e.Nonce, bestLeadingZeros = nonce, leadingZeros + if target > 0 && bestLeadingZeros >= target { + return nil + } + } + nonce++ + } + } + + if target > 0 && bestLeadingZeros < target { + return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) + } + + return nil +} + +// PoW computes (if necessary) and returns the proof of work target +// of the envelope. +func (e *Envelope) PoW() float64 { + if e.pow == 0 { + e.calculatePoW(0) + } + return e.pow +} + +func (e *Envelope) calculatePoW(diff uint32) { + rlp := e.rlpWithoutNonce() + buf := make([]byte, len(rlp)+8) + copy(buf, rlp) + binary.BigEndian.PutUint64(buf[len(rlp):], e.Nonce) + powHash := new(big.Int).SetBytes(crypto.Keccak256(buf)) + leadingZeroes := 256 - powHash.BitLen() + x := math.Pow(2, float64(leadingZeroes)) + x /= float64(len(rlp)) + x /= float64(e.TTL + diff) + e.pow = x +} + +func (e *Envelope) powToFirstBit(pow float64) int { + x := pow + x *= float64(e.size()) + x *= float64(e.TTL) + bits := math.Log2(x) + bits = math.Ceil(bits) + res := int(bits) + if res < 1 { + res = 1 + } + return res +} + +// Hash returns the SHA3 hash of the envelope, calculating it if not yet done. +func (e *Envelope) Hash() common.Hash { + if (e.hash == common.Hash{}) { + encoded, _ := rlp.EncodeToBytes(e) + e.hash = crypto.Keccak256Hash(encoded) + } + return e.hash +} + +// DecodeRLP decodes an Envelope from an RLP data stream. +func (e *Envelope) DecodeRLP(s *rlp.Stream) error { + raw, err := s.Raw() + if err != nil { + return err + } + // The decoding of Envelope uses the struct fields but also needs + // to compute the hash of the whole RLP-encoded envelope. This + // type has the same structure as Envelope but is not an + // rlp.Decoder (does not implement DecodeRLP function). + // Only public members will be encoded. + type rlpenv Envelope + if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { + return err + } + e.hash = crypto.Keccak256Hash(raw) + return nil +} + +// OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. +func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { + message := &ReceivedMessage{Raw: e.Data} + err := message.decryptAsymmetric(key) + switch err { + case nil: + return message, nil + case ecies.ErrInvalidPublicKey: // addressed to somebody else + return nil, err + default: + return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) + } +} + +// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. +func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { + msg = &ReceivedMessage{Raw: e.Data} + err = msg.decryptSymmetric(key) + if err != nil { + msg = nil + } + return msg, err +} + +// Open tries to decrypt an envelope, and populates the message fields in case of success. +func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { + if watcher == nil { + return nil + } + + // The API interface forbids filters doing both symmetric and asymmetric encryption. + if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { + return nil + } + + if watcher.expectsAsymmetricEncryption() { + msg, _ = e.OpenAsymmetric(watcher.KeyAsym) + if msg != nil { + msg.Dst = &watcher.KeyAsym.PublicKey + } + } else if watcher.expectsSymmetricEncryption() { + msg, _ = e.OpenSymmetric(watcher.KeySym) + if msg != nil { + msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) + } + } + + if msg != nil { + ok := msg.ValidateAndParse() + if !ok { + return nil + } + msg.Topic = e.Topic + msg.PoW = e.PoW() + msg.TTL = e.TTL + msg.Sent = e.Expiry - e.TTL + msg.EnvelopeHash = e.Hash() + } + return msg +} + +// Bloom maps 4-bytes Topic into 64-byte bloom filter with 3 bits set (at most). +func (e *Envelope) Bloom() []byte { + if e.bloom == nil { + e.bloom = TopicToBloom(e.Topic) + } + return e.bloom +} + +// TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes) +func TopicToBloom(topic TopicType) []byte { + b := make([]byte, BloomFilterSize) + var index [3]int + for j := 0; j < 3; j++ { + index[j] = int(topic[j]) + if (topic[3] & (1 << uint(j))) != 0 { + index[j] += 256 + } + } + + for j := 0; j < 3; j++ { + byteIndex := index[j] / 8 + bitIndex := index[j] % 8 + b[byteIndex] = (1 << uint(bitIndex)) + } + return b +} diff --git a/vendor/github.com/status-im/status-go/waku/events.go b/vendor/github.com/status-im/status-go/waku/events.go new file mode 100644 index 000000000..8c22e5fb9 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/events.go @@ -0,0 +1,64 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +// 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" + // EventEnvelopeReceived is sent once envelope was received from a peer. + // EventEnvelopeReceived must be sent to the feed even if envelope was previously in the cache. + // And event, ideally, should contain information about peer that sent envelope to us. + EventEnvelopeReceived EventType = "envelope.received" + // EventBatchAcknowledged is sent when batch of envelopes was acknowleged by a peer. + EventBatchAcknowledged EventType = "batch.acknowleged" + // EventEnvelopeAvailable fires when envelop is available for filters + EventEnvelopeAvailable EventType = "envelope.available" + // EventMailServerRequestSent fires when such request is sent. + EventMailServerRequestSent EventType = "mailserver.request.sent" + // EventMailServerRequestCompleted fires after mailserver sends all the requested messages + EventMailServerRequestCompleted EventType = "mailserver.request.completed" + // EventMailServerRequestExpired fires after mailserver the request TTL ends. + // This event is independent and concurrent to EventMailServerRequestCompleted. + // Request should be considered as expired only if expiry event was received first. + EventMailServerRequestExpired EventType = "mailserver.request.expired" + // EventMailServerEnvelopeArchived fires after an envelope has been archived + EventMailServerEnvelopeArchived EventType = "mailserver.envelope.archived" + // EventMailServerSyncFinished fires when the sync of messages is finished. + EventMailServerSyncFinished EventType = "mailserver.sync.finished" +) + +// EnvelopeEvent used for envelopes events. +type EnvelopeEvent struct { + Event EventType + Topic TopicType + Hash common.Hash + Batch common.Hash + Peer enode.ID + Data interface{} +} diff --git a/vendor/github.com/status-im/status-go/waku/filter.go b/vendor/github.com/status-im/status-go/waku/filter.go new file mode 100644 index 000000000..dfe3f60e5 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/filter.go @@ -0,0 +1,296 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "crypto/ecdsa" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" +) + +// MessageStore defines interface for temporary message store. +type MessageStore interface { + Add(*ReceivedMessage) error + Pop() ([]*ReceivedMessage, error) +} + +// NewMemoryMessageStore returns pointer to an instance of the MemoryMessageStore. +func NewMemoryMessageStore() *MemoryMessageStore { + return &MemoryMessageStore{ + messages: map[common.Hash]*ReceivedMessage{}, + } +} + +// MemoryMessageStore stores massages in memory hash table. +type MemoryMessageStore struct { + mu sync.Mutex + messages map[common.Hash]*ReceivedMessage +} + +// Add adds message to store. +func (store *MemoryMessageStore) Add(msg *ReceivedMessage) error { + store.mu.Lock() + defer store.mu.Unlock() + if _, exist := store.messages[msg.EnvelopeHash]; !exist { + store.messages[msg.EnvelopeHash] = msg + } + return nil +} + +// Pop returns all avaiable messages and cleans the store. +func (store *MemoryMessageStore) Pop() ([]*ReceivedMessage, error) { + store.mu.Lock() + defer store.mu.Unlock() + all := make([]*ReceivedMessage, 0, len(store.messages)) + for hash, msg := range store.messages { + delete(store.messages, hash) + all = append(all, msg) + } + return all, nil +} + +// Filter represents a Waku message filter +type Filter struct { + Src *ecdsa.PublicKey // Sender of the message + KeyAsym *ecdsa.PrivateKey // Private Key of recipient + KeySym []byte // Key associated with the Topic + Topics [][]byte // Topics to filter messages with + PoW float64 // Proof of work as described in the Waku spec + AllowP2P bool // Indicates whether this filter is interested in direct peer-to-peer messages + SymKeyHash common.Hash // The Keccak256Hash of the symmetric key, needed for optimization + id string // unique identifier + + Messages MessageStore + mutex sync.RWMutex +} + +// Filters represents a collection of filters +type Filters struct { + watchers map[string]*Filter + + topicMatcher map[TopicType]map[*Filter]struct{} // map a topic to the filters that are interested in being notified when a message matches that topic + allTopicsMatcher map[*Filter]struct{} // list all the filters that will be notified of a new message, no matter what its topic is + + waku *Waku + mutex sync.RWMutex +} + +// NewFilters returns a newly created filter collection +func NewFilters(w *Waku) *Filters { + return &Filters{ + watchers: make(map[string]*Filter), + topicMatcher: make(map[TopicType]map[*Filter]struct{}), + allTopicsMatcher: make(map[*Filter]struct{}), + waku: w, + } +} + +// Install will add a new filter to the filter collection +func (fs *Filters) Install(watcher *Filter) (string, error) { + if watcher.KeySym != nil && watcher.KeyAsym != nil { + return "", fmt.Errorf("filters must choose between symmetric and asymmetric keys") + } + + id, err := GenerateRandomID() + if err != nil { + return "", err + } + + fs.mutex.Lock() + defer fs.mutex.Unlock() + + if fs.watchers[id] != nil { + return "", fmt.Errorf("failed to generate unique ID") + } + + if watcher.expectsSymmetricEncryption() { + watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) + } + + watcher.id = id + fs.watchers[id] = watcher + fs.addTopicMatcher(watcher) + return id, err +} + +// Uninstall will remove a filter whose id has been specified from +// the filter collection +func (fs *Filters) Uninstall(id string) bool { + fs.mutex.Lock() + defer fs.mutex.Unlock() + if fs.watchers[id] != nil { + fs.removeFromTopicMatchers(fs.watchers[id]) + delete(fs.watchers, id) + return true + } + return false +} + +// addTopicMatcher adds a filter to the topic matchers. +// If the filter's Topics array is empty, it will be tried on every topic. +// Otherwise, it will be tried on the topics specified. +func (fs *Filters) addTopicMatcher(watcher *Filter) { + if len(watcher.Topics) == 0 { + fs.allTopicsMatcher[watcher] = struct{}{} + } else { + for _, t := range watcher.Topics { + topic := BytesToTopic(t) + if fs.topicMatcher[topic] == nil { + fs.topicMatcher[topic] = make(map[*Filter]struct{}) + } + fs.topicMatcher[topic][watcher] = struct{}{} + } + } +} + +// removeFromTopicMatchers removes a filter from the topic matchers +func (fs *Filters) removeFromTopicMatchers(watcher *Filter) { + delete(fs.allTopicsMatcher, watcher) + for _, topic := range watcher.Topics { + delete(fs.topicMatcher[BytesToTopic(topic)], watcher) + } +} + +// getWatchersByTopic returns a slice containing the filters that +// match a specific topic +func (fs *Filters) getWatchersByTopic(topic TopicType) []*Filter { + res := make([]*Filter, 0, len(fs.allTopicsMatcher)) + for watcher := range fs.allTopicsMatcher { + res = append(res, watcher) + } + for watcher := range fs.topicMatcher[topic] { + res = append(res, watcher) + } + return res +} + +// Get returns a filter from the collection with a specific ID +func (fs *Filters) Get(id string) *Filter { + fs.mutex.RLock() + defer fs.mutex.RUnlock() + return fs.watchers[id] +} + +// NotifyWatchers notifies any filter that has declared interest +// for the envelope's topic. +func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { + var msg *ReceivedMessage + + fs.mutex.RLock() + defer fs.mutex.RUnlock() + + candidates := fs.getWatchersByTopic(env.Topic) + for _, watcher := range candidates { + if p2pMessage && !watcher.AllowP2P { + log.Trace(fmt.Sprintf("msg [%x], filter [%s]: p2p messages are not allowed", env.Hash(), watcher.id)) + continue + } + + var match bool + if msg != nil { + match = watcher.MatchMessage(msg) + } else { + match = watcher.MatchEnvelope(env) + if match { + msg = env.Open(watcher) + if msg == nil { + log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", watcher.id) + } + } else { + log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", watcher.id) + } + } + + if match && msg != nil { + msg.P2P = p2pMessage + log.Trace("processing message: decrypted", "hash", env.Hash().Hex()) + if watcher.Src == nil || IsPubKeyEqual(msg.Src, watcher.Src) { + watcher.Trigger(msg) + } + } + } +} + +func (f *Filter) expectsAsymmetricEncryption() bool { + return f.KeyAsym != nil +} + +func (f *Filter) expectsSymmetricEncryption() bool { + return f.KeySym != nil +} + +// Trigger adds a yet-unknown message to the filter's list of +// received messages. +func (f *Filter) Trigger(msg *ReceivedMessage) { + err := f.Messages.Add(msg) + if err != nil { + log.Error("failed to add msg into the filters store", "hash", msg.EnvelopeHash, "error", err) + } +} + +// Retrieve will return the list of all received messages associated +// to a filter. +func (f *Filter) Retrieve() []*ReceivedMessage { + msgs, err := f.Messages.Pop() + if err != nil { + log.Error("failed to retrieve messages from filter store", "error", err) + return nil + } + return msgs +} + +// MatchMessage checks if the filter matches an already decrypted +// message (i.e. a Message that has already been handled by +// MatchEnvelope when checked by a previous filter). +// Topics are not checked here, since this is done by topic matchers. +func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { + if f.PoW > 0 && msg.PoW < f.PoW { + return false + } + + if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() { + return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) + } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { + return f.SymKeyHash == msg.SymKeyHash + } + return false +} + +// MatchEnvelope checks if it's worth decrypting the message. If +// it returns `true`, client code is expected to attempt decrypting +// the message and subsequently call MatchMessage. +// Topics are not checked here, since this is done by topic matchers. +func (f *Filter) MatchEnvelope(envelope *Envelope) bool { + return f.PoW <= 0 || envelope.pow >= f.PoW +} + +// IsPubKeyEqual checks that two public keys are equal +func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool { + if !ValidatePublicKey(a) { + return false + } else if !ValidatePublicKey(b) { + return false + } + // the curve is always the same, just compare the points + return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0 +} diff --git a/vendor/github.com/status-im/status-go/waku/go.mod b/vendor/github.com/status-im/status-go/waku/go.mod new file mode 100644 index 000000000..dee45c4c4 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/go.mod @@ -0,0 +1,24 @@ +module github.com/status-im/status-go/waku + +go 1.13 + +replace github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.6 + +require ( + github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 // indirect + github.com/deckarep/golang-set v1.7.1 + github.com/elastic/gosigar v0.10.5 // indirect + github.com/ethereum/go-ethereum v1.9.5 + github.com/gorilla/websocket v1.4.1 // indirect + github.com/huin/goupnp v1.0.0 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/prometheus/client_golang v1.2.1 + github.com/prometheus/common v0.7.0 + github.com/rs/cors v1.7.0 // indirect + github.com/stretchr/testify v1.4.0 + github.com/syndtr/goleveldb v1.0.0 // indirect + github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 + go.uber.org/zap v1.13.0 + golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c + golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e +) diff --git a/vendor/github.com/status-im/status-go/waku/go.sum b/vendor/github.com/status-im/status-go/waku/go.sum new file mode 100644 index 000000000..e1e50ef6b --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/go.sum @@ -0,0 +1,304 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/azure-pipeline-go v0.0.0-20180607212504-7571e8eb0876/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-storage-blob-go v0.0.0-20180712005634-eaae161d9d5e/go.mod h1:x2mtS6O3mnMEZOJp7d7oldh8IvatBrMfReiyQ+cKgKY= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v0.0.0-20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 h1:ZdRuixFqR3mfx4FHzclG3COrRgWrYq0VhNgIoYoObcM= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/btcsuite/btcd v0.20.0-beta h1:DnZGUjFbRkpytojHWwy6nfUSA7vFrzWXDLpFNzt74ZA= +github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/dgrijalva/jwt-go v0.0.0-20170201225849-2268707a8f08/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/docker v0.0.0-20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.0.0-20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo= +github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gizak/termui v0.0.0-20170117222342-991cd3d38091/go.mod h1:PkJoWUt/zacQKysNfQtcw1RW+eK2SxkieVBtl+4ovLA= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-stack/stack v1.5.4/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/influxdata/influxdb v0.0.0-20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v0.0.0-20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v0.0.0-20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2/go.mod h1:YvbcH+3Wo6XPs9nkgTY3u19KXLauXW+J5nB7hEHuX0A= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/maruel/panicparse v0.0.0-20160720141634-ad661195ed0e/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.0-20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/toml v0.0.0-20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nsf/termbox-go v0.0.0-20170211012700-3540b76b9c77/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/olekukonko/tablewriter v0.0.0-20170128050532-febf2d34b54a/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= +github.com/opentracing/opentracing-go v0.0.0-20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/peterh/liner v0.0.0-20170902204657-a37ad3984311/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/prometheus v0.0.0-20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/status-im/extkeys v1.0.0/go.mod h1:wNx0pnvGTgyKz/S8hBNesAHKKKI9beF+BuVLIuBJuQI= +github.com/status-im/go-ethereum v1.9.5-status.5 h1:d2RJC6ltNZJM2mrAW6kDWYdzewF8+us4qYaIH5gvyaM= +github.com/status-im/go-ethereum v1.9.5-status.5/go.mod h1:g2+E89NWtyA+55p6XEl5Sdt7Mtez3V0T3+Y7mJNb+tI= +github.com/status-im/go-ethereum v1.9.5-status.6 h1:ytuTO1yBIAuTVRtRQoc2mrdyngtP+XOQ9IHIibbz7/I= +github.com/status-im/go-ethereum v1.9.5-status.6/go.mod h1:08JvQWE+IOnAFSe4UD4ACLNe2fDd9XmWMCq5Yzy9mk0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9 h1:kjbwitOGH46vD01f2s3leBfrMnePQa3NSAIlW35MvY8= +github.com/tsenart/tb v0.0.0-20181025101425-0d2499c8b6e9/go.mod h1:EcGP24b8DY+bWHnpfJDP7fM+o8Nmz4fYH0l2xTtNr3I= +github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405 h1:829vOVxxusYHC+IqBtkX5mbKtsY9fheQiQn0MZRVLfQ= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20180302121509-abf0ba0be5d5/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/status-im/status-go/waku/mailserver_response.go b/vendor/github.com/status-im/status-go/waku/mailserver_response.go new file mode 100644 index 000000000..fb1b9ad2a --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/mailserver_response.go @@ -0,0 +1,158 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "bytes" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +const ( + mailServerFailedPayloadPrefix = "ERROR=" + cursorSize = 36 +) + +func invalidResponseSizeError(size int) error { + return fmt.Errorf("unexpected payload size: %d", size) +} + +// CreateMailServerRequestCompletedPayload creates a payload representing +// a successful request to mailserver +func CreateMailServerRequestCompletedPayload(requestID, lastEnvelopeHash common.Hash, cursor []byte) []byte { + payload := make([]byte, len(requestID)) + copy(payload, requestID[:]) + payload = append(payload, lastEnvelopeHash[:]...) + payload = append(payload, cursor...) + return payload +} + +// CreateMailServerRequestFailedPayload creates a payload representing +// a failed request to a mailserver +func CreateMailServerRequestFailedPayload(requestID common.Hash, err error) []byte { + payload := []byte(mailServerFailedPayloadPrefix) + payload = append(payload, requestID[:]...) + payload = append(payload, []byte(err.Error())...) + return payload +} + +// CreateMailServerEvent returns EnvelopeEvent with correct data +// if payload corresponds to any of the know mailserver events: +// * request completed successfully +// * request failed +// If the payload is unknown/unparseable, it returns `nil` +func CreateMailServerEvent(nodeID enode.ID, payload []byte) (*EnvelopeEvent, error) { + if len(payload) < common.HashLength { + return nil, invalidResponseSizeError(len(payload)) + } + + event, err := tryCreateMailServerRequestFailedEvent(nodeID, payload) + if err != nil { + return nil, err + } else if event != nil { + return event, nil + } + + return tryCreateMailServerRequestCompletedEvent(nodeID, payload) +} + +func tryCreateMailServerRequestFailedEvent(nodeID enode.ID, payload []byte) (*EnvelopeEvent, error) { + if len(payload) < common.HashLength+len(mailServerFailedPayloadPrefix) { + return nil, nil + } + + prefix, remainder := extractPrefix(payload, len(mailServerFailedPayloadPrefix)) + + if !bytes.Equal(prefix, []byte(mailServerFailedPayloadPrefix)) { + return nil, nil + } + + var ( + requestID common.Hash + errorMsg string + ) + + requestID, remainder = extractHash(remainder) + errorMsg = string(remainder) + + event := EnvelopeEvent{ + Peer: nodeID, + Hash: requestID, + Event: EventMailServerRequestCompleted, + Data: &MailServerResponse{ + Error: errors.New(errorMsg), + }, + } + + return &event, nil + +} + +func tryCreateMailServerRequestCompletedEvent(nodeID enode.ID, payload []byte) (*EnvelopeEvent, error) { + // check if payload is + // - requestID or + // - requestID + lastEnvelopeHash or + // - requestID + lastEnvelopeHash + cursor + // requestID is the hash of the request envelope. + // lastEnvelopeHash is the last envelope sent by the mail server + // cursor is the db key, 36 bytes: 4 for the timestamp + 32 for the envelope hash. + if len(payload) > common.HashLength*2+cursorSize { + return nil, invalidResponseSizeError(len(payload)) + } + + var ( + requestID common.Hash + lastEnvelopeHash common.Hash + cursor []byte + ) + + requestID, remainder := extractHash(payload) + + if len(remainder) >= common.HashLength { + lastEnvelopeHash, remainder = extractHash(remainder) + } + + if len(remainder) >= cursorSize { + cursor = remainder + } + + event := EnvelopeEvent{ + Peer: nodeID, + Hash: requestID, + Event: EventMailServerRequestCompleted, + Data: &MailServerResponse{ + LastEnvelopeHash: lastEnvelopeHash, + Cursor: cursor, + }, + } + + return &event, nil +} + +func extractHash(payload []byte) (common.Hash, []byte) { + prefix, remainder := extractPrefix(payload, common.HashLength) + return common.BytesToHash(prefix), remainder +} + +func extractPrefix(payload []byte, size int) ([]byte, []byte) { + return payload[:size], payload[size:] +} diff --git a/vendor/github.com/status-im/status-go/waku/message.go b/vendor/github.com/status-im/status-go/waku/message.go new file mode 100644 index 000000000..b35953dea --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/message.go @@ -0,0 +1,361 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + crand "crypto/rand" + "encoding/binary" + "errors" + mrand "math/rand" + "strconv" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/log" +) + +// MessageParams specifies the exact way a message should be wrapped +// into an Envelope. +type MessageParams struct { + TTL uint32 + Src *ecdsa.PrivateKey + Dst *ecdsa.PublicKey + KeySym []byte + Topic TopicType + WorkTime uint32 + PoW float64 + Payload []byte + Padding []byte +} + +// SentMessage represents an end-user data packet to transmit through the +// Waku protocol. These are wrapped into Envelopes that need not be +// understood by intermediate nodes, just forwarded. +type sentMessage struct { + Raw []byte +} + +// ReceivedMessage represents a data packet to be received through the +// Waku protocol and successfully decrypted. +type ReceivedMessage struct { + Raw []byte + + Payload []byte + Padding []byte + Signature []byte + Salt []byte + + PoW float64 // Proof of work as described in the Waku spec + Sent uint32 // Time when the message was posted into the network + TTL uint32 // Maximum time to live allowed for the message + Src *ecdsa.PublicKey // Message recipient (identity used to decode the message) + Dst *ecdsa.PublicKey // Message recipient (identity used to decode the message) + Topic TopicType + + SymKeyHash common.Hash // The Keccak256Hash of the key + EnvelopeHash common.Hash // Message envelope hash to act as a unique id + + P2P bool // is set to true if this message was received from mail server. +} + +func isMessageSigned(flags byte) bool { + return (flags & signatureFlag) != 0 +} + +func (msg *ReceivedMessage) isSymmetricEncryption() bool { + return msg.SymKeyHash != common.Hash{} +} + +func (msg *ReceivedMessage) isAsymmetricEncryption() bool { + return msg.Dst != nil +} + +// NewSentMessage creates and initializes a non-signed, non-encrypted Waku message. +func NewSentMessage(params *MessageParams) (*sentMessage, error) { + const payloadSizeFieldMaxSize = 4 + msg := sentMessage{} + msg.Raw = make([]byte, 1, + flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit) + msg.Raw[0] = 0 // set all the flags to zero + msg.addPayloadSizeField(params.Payload) + msg.Raw = append(msg.Raw, params.Payload...) + err := msg.appendPadding(params) + return &msg, err +} + +// addPayloadSizeField appends the auxiliary field containing the size of payload +func (msg *sentMessage) addPayloadSizeField(payload []byte) { + fieldSize := getSizeOfPayloadSizeField(payload) + field := make([]byte, 4) + binary.LittleEndian.PutUint32(field, uint32(len(payload))) + field = field[:fieldSize] + msg.Raw = append(msg.Raw, field...) + msg.Raw[0] |= byte(fieldSize) +} + +// getSizeOfPayloadSizeField returns the number of bytes necessary to encode the size of payload +func getSizeOfPayloadSizeField(payload []byte) int { + s := 1 + for i := len(payload); i >= 256; i /= 256 { + s++ + } + return s +} + +// appendPadding appends the padding specified in params. +// If no padding is provided in params, then random padding is generated. +func (msg *sentMessage) appendPadding(params *MessageParams) error { + if len(params.Padding) != 0 { + // padding data was provided by the Dapp, just use it as is + msg.Raw = append(msg.Raw, params.Padding...) + return nil + } + + rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload) + if params.Src != nil { + rawSize += signatureLength + } + odd := rawSize % padSizeLimit + paddingSize := padSizeLimit - odd + pad := make([]byte, paddingSize) + _, err := crand.Read(pad) + if err != nil { + return err + } + if !validateDataIntegrity(pad, paddingSize) { + return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize)) + } + msg.Raw = append(msg.Raw, pad...) + return nil +} + +// sign calculates and sets the cryptographic signature for the message, +// also setting the sign flag. +func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error { + if isMessageSigned(msg.Raw[0]) { + // this should not happen, but no reason to panic + log.Error("failed to sign the message: already signed") + return nil + } + + msg.Raw[0] |= signatureFlag // it is important to set this flag before signing + hash := crypto.Keccak256(msg.Raw) + signature, err := crypto.Sign(hash, key) + if err != nil { + msg.Raw[0] &= (0xFF ^ signatureFlag) // clear the flag + return err + } + msg.Raw = append(msg.Raw, signature...) + return nil +} + +// encryptAsymmetric encrypts a message with a public key. +func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error { + if !ValidatePublicKey(key) { + return errors.New("invalid public key provided for asymmetric encryption") + } + encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil) + if err == nil { + msg.Raw = encrypted + } + return err +} + +// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256. +// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). +func (msg *sentMessage) encryptSymmetric(key []byte) (err error) { + if !validateDataIntegrity(key, aesKeyLength) { + return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key))) + } + block, err := aes.NewCipher(key) + if err != nil { + return err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return err + } + salt, err := generateSecureRandomData(aesNonceLength) // never use more than 2^32 random nonces with a given key + if err != nil { + return err + } + encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil) + msg.Raw = append(encrypted, salt...) + return nil +} + +// generateSecureRandomData generates random data where extra security is required. +// The purpose of this function is to prevent some bugs in software or in hardware +// from delivering not-very-random data. This is especially useful for AES nonce, +// where true randomness does not really matter, but it is very important to have +// a unique nonce for every message. +func generateSecureRandomData(length int) ([]byte, error) { + x := make([]byte, length) + y := make([]byte, length) + res := make([]byte, length) + + _, err := crand.Read(x) + if err != nil { + return nil, err + } else if !validateDataIntegrity(x, length) { + return nil, errors.New("crypto/rand failed to generate secure random data") + } + _, err = mrand.Read(y) + if err != nil { + return nil, err + } else if !validateDataIntegrity(y, length) { + return nil, errors.New("math/rand failed to generate secure random data") + } + for i := 0; i < length; i++ { + res[i] = x[i] ^ y[i] + } + if !validateDataIntegrity(res, length) { + return nil, errors.New("failed to generate secure random data") + } + return res, nil +} + +// Wrap bundles the message into an Envelope to transmit over the network. +func (msg *sentMessage) Wrap(options *MessageParams, now time.Time) (envelope *Envelope, err error) { + if options.TTL == 0 { + options.TTL = DefaultTTL + } + if options.Src != nil { + if err = msg.sign(options.Src); err != nil { + return nil, err + } + } + if options.Dst != nil { + err = msg.encryptAsymmetric(options.Dst) + } else if options.KeySym != nil { + err = msg.encryptSymmetric(options.KeySym) + } else { + err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided") + } + if err != nil { + return nil, err + } + + envelope = NewEnvelope(options.TTL, options.Topic, msg, now) + if err = envelope.Seal(options); err != nil { + return nil, err + } + return envelope, nil +} + +// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256. +// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize). +func (msg *ReceivedMessage) decryptSymmetric(key []byte) error { + // symmetric messages are expected to contain the 12-byte nonce at the end of the payload + if len(msg.Raw) < aesNonceLength { + return errors.New("missing salt or invalid payload in symmetric message") + } + salt := msg.Raw[len(msg.Raw)-aesNonceLength:] + + block, err := aes.NewCipher(key) + if err != nil { + return err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return err + } + decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil) + if err != nil { + return err + } + msg.Raw = decrypted + msg.Salt = salt + return nil +} + +// decryptAsymmetric decrypts an encrypted payload with a private key. +func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error { + decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil) + if err == nil { + msg.Raw = decrypted + } + return err +} + +// ValidateAndParse checks the message validity and extracts the fields in case of success. +func (msg *ReceivedMessage) ValidateAndParse() bool { + end := len(msg.Raw) + if end < 1 { + return false + } + + if isMessageSigned(msg.Raw[0]) { + end -= signatureLength + if end <= 1 { + return false + } + msg.Signature = msg.Raw[end : end+signatureLength] + msg.Src = msg.SigToPubKey() + if msg.Src == nil { + return false + } + } + + beg := 1 + payloadSize := 0 + sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) // number of bytes indicating the size of payload + if sizeOfPayloadSizeField != 0 { + if end < beg+sizeOfPayloadSizeField { + return false + } + payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField])) + beg += sizeOfPayloadSizeField + if beg+payloadSize > end { + return false + } + msg.Payload = msg.Raw[beg : beg+payloadSize] + } + + beg += payloadSize + msg.Padding = msg.Raw[beg:end] + return true +} + +// SigToPubKey returns the public key associated to the message's +// signature. +func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey { + defer func() { recover() }() // in case of invalid signature + + pub, err := crypto.SigToPub(msg.hash(), msg.Signature) + if err != nil { + log.Error("failed to recover public key from signature", "err", err) + return nil + } + return pub +} + +// hash calculates the SHA3 checksum of the message flags, payload size field, payload and padding. +func (msg *ReceivedMessage) hash() []byte { + if isMessageSigned(msg.Raw[0]) { + sz := len(msg.Raw) - signatureLength + return crypto.Keccak256(msg.Raw[:sz]) + } + return crypto.Keccak256(msg.Raw) +} diff --git a/vendor/github.com/status-im/status-go/waku/metrics.go b/vendor/github.com/status-im/status-go/waku/metrics.go new file mode 100644 index 000000000..f1f08e131 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/metrics.go @@ -0,0 +1,70 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + prom "github.com/prometheus/client_golang/prometheus" +) + +var ( + envelopesReceivedCounter = prom.NewCounter(prom.CounterOpts{ + Name: "waku_envelopes_received_total", + Help: "Number of envelopes received.", + }) + envelopesValidatedCounter = prom.NewCounter(prom.CounterOpts{ + Name: "waku_envelopes_validated_total", + Help: "Number of envelopes processed successfully.", + }) + envelopesRejectedCounter = prom.NewCounterVec(prom.CounterOpts{ + Name: "waku_envelopes_rejected_total", + Help: "Number of envelopes rejected.", + }, []string{"reason"}) + envelopesCacheFailedCounter = prom.NewCounterVec(prom.CounterOpts{ + Name: "waku_envelopes_cache_failures_total", + Help: "Number of envelopes which failed to be cached.", + }, []string{"type"}) + envelopesCachedCounter = prom.NewCounterVec(prom.CounterOpts{ + Name: "waku_envelopes_cached_total", + Help: "Number of envelopes cached.", + }, []string{"cache"}) + envelopesSizeMeter = prom.NewHistogram(prom.HistogramOpts{ + Name: "waku_envelopes_size_bytes", + Help: "Size of processed Waku envelopes in bytes.", + Buckets: prom.ExponentialBuckets(256, 4, 10), + }) + // rate limiter metrics + rateLimitsProcessed = prom.NewCounter(prom.CounterOpts{ + Name: "waku_rate_limits_processed_total", + Help: "Number of packets Waku rate limiter processed.", + }) + rateLimitsExceeded = prom.NewCounterVec(prom.CounterOpts{ + Name: "waku_rate_limits_exceeded_total", + Help: "Number of times the Waku rate limits were exceeded", + }, []string{"type"}) +) + +func init() { + prom.MustRegister(envelopesReceivedCounter) + prom.MustRegister(envelopesRejectedCounter) + prom.MustRegister(envelopesCacheFailedCounter) + prom.MustRegister(envelopesCachedCounter) + prom.MustRegister(envelopesSizeMeter) + prom.MustRegister(rateLimitsProcessed) + prom.MustRegister(rateLimitsExceeded) +} diff --git a/vendor/github.com/status-im/status-go/waku/peer.go b/vendor/github.com/status-im/status-go/waku/peer.go new file mode 100644 index 000000000..92506173e --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/peer.go @@ -0,0 +1,321 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "bytes" + "fmt" + "math" + "sync" + "time" + + mapset "github.com/deckarep/golang-set" + "go.uber.org/zap" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/rlp" +) + +// Peer represents a waku protocol peer connection. +type Peer struct { + host *Waku + peer *p2p.Peer + ws p2p.MsgReadWriter + logger *zap.Logger + + trusted bool + powRequirement float64 + bloomMu sync.Mutex + bloomFilter []byte + fullNode bool + confirmationsEnabled bool + rateLimitsMu sync.Mutex + rateLimits RateLimits + + known mapset.Set // Messages already known by the peer to avoid wasting bandwidth + + quit chan struct{} +} + +// newPeer creates a new waku peer object, but does not run the handshake itself. +func newPeer(host *Waku, remote *p2p.Peer, rw p2p.MsgReadWriter, logger *zap.Logger) *Peer { + if logger == nil { + logger = zap.NewNop() + } + + return &Peer{ + host: host, + peer: remote, + ws: rw, + logger: logger, + trusted: false, + powRequirement: 0.0, + known: mapset.NewSet(), + quit: make(chan struct{}), + bloomFilter: MakeFullNodeBloom(), + fullNode: true, + } +} + +// start initiates the peer updater, periodically broadcasting the waku packets +// into the network. +func (p *Peer) start() { + go p.update() + p.logger.Debug("starting peer", zap.Binary("peerID", p.ID())) +} + +// stop terminates the peer updater, stopping message forwarding to it. +func (p *Peer) stop() { + close(p.quit) + p.logger.Debug("stopping peer", zap.Binary("peerID", p.ID())) +} + +// handshake sends the protocol initiation status message to the remote peer and +// verifies the remote status too. +func (p *Peer) handshake() error { + // Send the handshake status message asynchronously + errc := make(chan error, 1) + isLightNode := p.host.LightClientMode() + isRestrictedLightNodeConnection := p.host.LightClientModeConnectionRestricted() + go func() { + pow := p.host.MinPow() + powConverted := math.Float64bits(pow) + bloom := p.host.BloomFilter() + confirmationsEnabled := p.host.ConfirmationsEnabled() + rateLimits := p.host.RateLimits() + + errc <- p2p.SendItems(p.ws, statusCode, ProtocolVersion, powConverted, bloom, isLightNode, confirmationsEnabled, rateLimits) + }() + + // Fetch the remote status packet and verify protocol match + packet, err := p.ws.ReadMsg() + if err != nil { + return err + } + if packet.Code != statusCode { + return fmt.Errorf("p [%x] sent packet %x before status packet", p.ID(), packet.Code) + } + s := rlp.NewStream(packet.Payload, uint64(packet.Size)) + _, err = s.List() + if err != nil { + return fmt.Errorf("p [%x] sent bad status message: %v", p.ID(), err) + } + peerVersion, err := s.Uint() + if err != nil { + return fmt.Errorf("p [%x] sent bad status message (unable to decode version): %v", p.ID(), err) + } + if peerVersion != ProtocolVersion { + return fmt.Errorf("p [%x]: protocol version mismatch %d != %d", p.ID(), peerVersion, ProtocolVersion) + } + + // only version is mandatory, subsequent parameters are optional + powRaw, err := s.Uint() + if err == nil { + pow := math.Float64frombits(powRaw) + if math.IsInf(pow, 0) || math.IsNaN(pow) || pow < 0.0 { + return fmt.Errorf("p [%x] sent bad status message: invalid pow", p.ID()) + } + p.powRequirement = pow + + var bloom []byte + err = s.Decode(&bloom) + if err == nil { + sz := len(bloom) + if sz != BloomFilterSize && sz != 0 { + return fmt.Errorf("p [%x] sent bad status message: wrong bloom filter size %d", p.ID(), sz) + } + p.setBloomFilter(bloom) + } + } + + isRemotePeerLightNode, _ := s.Bool() + if isRemotePeerLightNode && isLightNode && isRestrictedLightNodeConnection { + return fmt.Errorf("p [%x] is useless: two light client communication restricted", p.ID()) + } + confirmationsEnabled, err := s.Bool() + if err != nil || !confirmationsEnabled { + p.logger.Info("confirmations are disabled for peer", zap.Binary("peer", p.ID())) + } else { + p.confirmationsEnabled = confirmationsEnabled + } + + var rateLimits RateLimits + if err := s.Decode(&rateLimits); err != nil { + p.logger.Info("rate limiting is disabled for peer", zap.Binary("peer", p.ID())) + } else { + p.setRateLimits(rateLimits) + } + + if err := <-errc; err != nil { + return fmt.Errorf("p [%x] failed to send status packet: %v", p.ID(), err) + } + return nil +} + +// update executes periodic operations on the peer, including message transmission +// and expiration. +func (p *Peer) update() { + // Start the tickers for the updates + expire := time.NewTicker(expirationCycle) + transmit := time.NewTicker(transmissionCycle) + + // Loop and transmit until termination is requested + for { + select { + case <-expire.C: + p.expire() + + case <-transmit.C: + if err := p.broadcast(); err != nil { + p.logger.Debug("broadcasting failed", zap.Binary("peer", p.ID()), zap.Error(err)) + return + } + + case <-p.quit: + return + } + } +} + +// mark marks an envelope known to the peer so that it won't be sent back. +func (p *Peer) mark(envelope *Envelope) { + p.known.Add(envelope.Hash()) +} + +// marked checks if an envelope is already known to the remote peer. +func (p *Peer) marked(envelope *Envelope) bool { + return p.known.Contains(envelope.Hash()) +} + +// expire iterates over all the known envelopes in the host and removes all +// expired (unknown) ones from the known list. +func (p *Peer) expire() { + unmark := make(map[common.Hash]struct{}) + p.known.Each(func(v interface{}) bool { + if !p.host.isEnvelopeCached(v.(common.Hash)) { + unmark[v.(common.Hash)] = struct{}{} + } + return true + }) + // Dump all known but no longer cached + for hash := range unmark { + p.known.Remove(hash) + } +} + +// broadcast iterates over the collection of envelopes and transmits yet unknown +// ones over the network. +func (p *Peer) broadcast() error { + envelopes := p.host.Envelopes() + bundle := make([]*Envelope, 0, len(envelopes)) + for _, envelope := range envelopes { + if !p.marked(envelope) && envelope.PoW() >= p.powRequirement && p.bloomMatch(envelope) { + bundle = append(bundle, envelope) + } + } + + if len(bundle) == 0 { + return nil + } + + batchHash, err := sendBundle(p.ws, bundle) + if err != nil { + p.logger.Debug("failed to deliver envelopes", zap.Binary("peer", p.ID()), zap.Error(err)) + return err + } + + // mark envelopes only if they were successfully sent + for _, e := range bundle { + p.mark(e) + event := EnvelopeEvent{ + Event: EventEnvelopeSent, + Hash: e.Hash(), + Peer: p.peer.ID(), + } + if p.confirmationsEnabled { + event.Batch = batchHash + } + p.host.envelopeFeed.Send(event) + } + p.logger.Debug("broadcasted bundles successfully", zap.Binary("peer", p.ID()), zap.Int("count", len(bundle))) + return nil +} + +// ID returns a peer's id +func (p *Peer) ID() []byte { + id := p.peer.ID() + return id[:] +} + +func (p *Peer) notifyAboutPowRequirementChange(pow float64) error { + i := math.Float64bits(pow) + return p2p.Send(p.ws, powRequirementCode, i) +} + +func (p *Peer) notifyAboutBloomFilterChange(bloom []byte) error { + return p2p.Send(p.ws, bloomFilterExCode, bloom) +} + +func (p *Peer) bloomMatch(env *Envelope) bool { + p.bloomMu.Lock() + defer p.bloomMu.Unlock() + return p.fullNode || BloomFilterMatch(p.bloomFilter, env.Bloom()) +} + +func (p *Peer) setBloomFilter(bloom []byte) { + p.bloomMu.Lock() + defer p.bloomMu.Unlock() + p.bloomFilter = bloom + p.fullNode = isFullNode(bloom) + if p.fullNode && p.bloomFilter == nil { + p.bloomFilter = MakeFullNodeBloom() + } +} + +func (p *Peer) setRateLimits(r RateLimits) { + p.rateLimitsMu.Lock() + p.rateLimits = r + p.rateLimitsMu.Unlock() +} + +func MakeFullNodeBloom() []byte { + bloom := make([]byte, BloomFilterSize) + for i := 0; i < BloomFilterSize; i++ { + bloom[i] = 0xFF + } + return bloom +} + +func sendBundle(rw p2p.MsgWriter, bundle []*Envelope) (rst common.Hash, err error) { + data, err := rlp.EncodeToBytes(bundle) + if err != nil { + return + } + err = rw.WriteMsg(p2p.Msg{ + Code: messagesCode, + Size: uint32(len(data)), + Payload: bytes.NewBuffer(data), + }) + if err != nil { + return + } + return crypto.Keccak256Hash(data), nil +} diff --git a/vendor/github.com/status-im/status-go/waku/rate_limiter.go b/vendor/github.com/status-im/status-go/waku/rate_limiter.go new file mode 100644 index 000000000..2ea260f80 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/rate_limiter.go @@ -0,0 +1,236 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "bytes" + "errors" + "fmt" + "time" + + "github.com/tsenart/tb" + + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +type runLoop func(p *Peer, rw p2p.MsgReadWriter) error + +type RateLimiterHandler interface { + ExceedPeerLimit() error + ExceedIPLimit() error +} + +type MetricsRateLimiterHandler struct{} + +func (MetricsRateLimiterHandler) ExceedPeerLimit() error { + rateLimitsExceeded.WithLabelValues("peer_id").Inc() + return nil +} +func (MetricsRateLimiterHandler) ExceedIPLimit() error { + rateLimitsExceeded.WithLabelValues("ip").Inc() + return nil +} + +var ErrRateLimitExceeded = errors.New("rate limit has been exceeded") + +type DropPeerRateLimiterHandler struct { + // Tolerance is a number of how many a limit must be exceeded + // in order to drop a peer. + Tolerance int64 + + peerLimitExceeds int64 + ipLimitExceeds int64 +} + +func (h *DropPeerRateLimiterHandler) ExceedPeerLimit() error { + h.peerLimitExceeds++ + if h.Tolerance > 0 && h.peerLimitExceeds >= h.Tolerance { + return ErrRateLimitExceeded + } + return nil +} + +func (h *DropPeerRateLimiterHandler) ExceedIPLimit() error { + h.ipLimitExceeds++ + if h.Tolerance > 0 && h.ipLimitExceeds >= h.Tolerance { + return ErrRateLimitExceeded + } + return nil +} + +type PeerRateLimiterConfig struct { + LimitPerSecIP int64 + LimitPerSecPeerID int64 + WhitelistedIPs []string + WhitelistedPeerIDs []enode.ID +} + +var defaultPeerRateLimiterConfig = PeerRateLimiterConfig{ + LimitPerSecIP: 10, + LimitPerSecPeerID: 5, + WhitelistedIPs: nil, + WhitelistedPeerIDs: nil, +} + +type PeerRateLimiter struct { + peerIDThrottler *tb.Throttler + ipThrottler *tb.Throttler + + limitPerSecIP int64 + limitPerSecPeerID int64 + + whitelistedPeerIDs []enode.ID + whitelistedIPs []string + + handlers []RateLimiterHandler +} + +func NewPeerRateLimiter(cfg *PeerRateLimiterConfig, handlers ...RateLimiterHandler) *PeerRateLimiter { + if cfg == nil { + copy := defaultPeerRateLimiterConfig + cfg = © + } + + return &PeerRateLimiter{ + peerIDThrottler: tb.NewThrottler(time.Millisecond * 100), + ipThrottler: tb.NewThrottler(time.Millisecond * 100), + limitPerSecIP: cfg.LimitPerSecIP, + limitPerSecPeerID: cfg.LimitPerSecPeerID, + whitelistedPeerIDs: cfg.WhitelistedPeerIDs, + whitelistedIPs: cfg.WhitelistedIPs, + handlers: handlers, + } +} + +func (r *PeerRateLimiter) decorate(p *Peer, rw p2p.MsgReadWriter, runLoop runLoop) error { + in, out := p2p.MsgPipe() + defer in.Close() + defer out.Close() + errC := make(chan error, 1) + + // Read from the original reader and write to the message pipe. + go func() { + for { + packet, err := rw.ReadMsg() + if err != nil { + errC <- fmt.Errorf("failed to read packet: %v", err) + return + } + + rateLimitsProcessed.Inc() + + var ip string + if p != nil && p.peer != nil { + ip = p.peer.Node().IP().String() + } + if halted := r.throttleIP(ip); halted { + for _, h := range r.handlers { + if err := h.ExceedIPLimit(); err != nil { + errC <- fmt.Errorf("exceed rate limit by IP: %w", err) + return + } + } + } + + var peerID []byte + if p != nil { + peerID = p.ID() + } + if halted := r.throttlePeer(peerID); halted { + for _, h := range r.handlers { + if err := h.ExceedPeerLimit(); err != nil { + errC <- fmt.Errorf("exceeded rate limit by peer: %w", err) + return + } + } + } + + if err := in.WriteMsg(packet); err != nil { + errC <- fmt.Errorf("failed to write packet to pipe: %v", err) + return + } + } + }() + + // Read from the message pipe and write to the original writer. + go func() { + for { + packet, err := in.ReadMsg() + if err != nil { + errC <- fmt.Errorf("failed to read packet from pipe: %v", err) + return + } + if err := rw.WriteMsg(packet); err != nil { + errC <- fmt.Errorf("failed to write packet: %v", err) + return + } + } + }() + + go func() { + errC <- runLoop(p, out) + }() + + return <-errC +} + +// throttleIP throttles a number of messages incoming from a given IP. +// It allows 10 packets per second. +func (r *PeerRateLimiter) throttleIP(ip string) bool { + if r.limitPerSecIP == 0 { + return false + } + if stringSliceContains(r.whitelistedIPs, ip) { + return false + } + return r.ipThrottler.Halt(ip, 1, r.limitPerSecIP) +} + +// throttlePeer throttles a number of messages incoming from a peer. +// It allows 3 packets per second. +func (r *PeerRateLimiter) throttlePeer(peerID []byte) bool { + if r.limitPerSecIP == 0 { + return false + } + var id enode.ID + copy(id[:], peerID) + if enodeIDSliceContains(r.whitelistedPeerIDs, id) { + return false + } + return r.peerIDThrottler.Halt(id.String(), 1, r.limitPerSecPeerID) +} + +func stringSliceContains(s []string, searched string) bool { + for _, item := range s { + if item == searched { + return true + } + } + return false +} + +func enodeIDSliceContains(s []enode.ID, searched enode.ID) bool { + for _, item := range s { + if bytes.Equal(item.Bytes(), searched.Bytes()) { + return true + } + } + return false +} diff --git a/vendor/github.com/status-im/status-go/waku/topic.go b/vendor/github.com/status-im/status-go/waku/topic.go new file mode 100644 index 000000000..a9e77ff89 --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/topic.go @@ -0,0 +1,56 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// TopicType represents a cryptographically secure, probabilistic partial +// classifications of a message, determined as the first (left) 4 bytes of the +// SHA3 hash of some arbitrary data given by the original author of the message. +type TopicType [TopicLength]byte + +// BytesToTopic converts from the byte array representation of a topic +// into the TopicType type. +func BytesToTopic(b []byte) (t TopicType) { + sz := TopicLength + if x := len(b); x < TopicLength { + sz = x + } + for i := 0; i < sz; i++ { + t[i] = b[i] + } + return t +} + +// String converts a topic byte array to a string representation. +func (t *TopicType) String() string { + return hexutil.Encode(t[:]) +} + +// MarshalText returns the hex representation of t. +func (t TopicType) MarshalText() ([]byte, error) { + return hexutil.Bytes(t[:]).MarshalText() +} + +// UnmarshalText parses a hex representation to a topic. +func (t *TopicType) UnmarshalText(input []byte) error { + return hexutil.UnmarshalFixedText("Topic", input, t[:]) +} diff --git a/vendor/github.com/status-im/status-go/waku/waku.go b/vendor/github.com/status-im/status-go/waku/waku.go new file mode 100644 index 000000000..fe68e660d --- /dev/null +++ b/vendor/github.com/status-im/status-go/waku/waku.go @@ -0,0 +1,1490 @@ +// Copyright 2019 The Waku Library Authors. +// +// The Waku 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 Waku library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty off +// 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 Waku library. If not, see . +// +// This software uses the go-ethereum library, which is licensed +// under the GNU Lesser General Public Library, version 3 or any later. + +package waku + +import ( + "bytes" + "crypto/ecdsa" + "crypto/sha256" + "errors" + "fmt" + "io" + "io/ioutil" + "math" + "runtime" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "go.uber.org/zap" + + mapset "github.com/deckarep/golang-set" + "golang.org/x/crypto/pbkdf2" + + "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/p2p/enode" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" +) + +// TimeSyncError error for clock skew errors. +type TimeSyncError error + +type settings struct { + MaxMsgSize uint32 // Maximal message length allowed by the waku node + EnableConfirmations bool // Enable sending message confirmations + MinPow float64 // Minimal PoW required by the waku node + MinPowTolerance float64 // Minimal PoW tolerated by the waku node for a limited time + BloomFilter []byte // Bloom filter for topics of interest for this node + BloomFilterTolerance []byte // Bloom filter tolerated by the waku node for a limited time + LightClient bool // Light client mode enabled does not forward messages + RestrictLightClientsConn bool // Restrict connection between two light clients + SyncAllowance int // Maximum time in seconds allowed to process the waku-related messages +} + +// Waku represents a dark communication interface through the Ethereum +// network, using its very own P2P communication layer. +type Waku struct { + protocol p2p.Protocol // Protocol description and parameters + filters *Filters // Message filters installed with Subscribe function + + privateKeys map[string]*ecdsa.PrivateKey // Private key storage + symKeys map[string][]byte // Symmetric key storage + keyMu sync.RWMutex // Mutex associated with key stores + + envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node + expirations map[uint32]mapset.Set // Message expiration pool + poolMu sync.RWMutex // Mutex to sync the message and expiration pools + + peers map[*Peer]struct{} // Set of currently active peers + peerMu sync.RWMutex // Mutex to sync the active peer set + + msgQueue chan *Envelope // Message queue for normal waku messages + p2pMsgQueue chan interface{} // Message queue for peer-to-peer messages (not to be forwarded any further) and history delivery confirmations. + quit chan struct{} // Channel used for graceful exit + + settings settings // Holds configuration settings that can be dynamically changed + settingsMu sync.RWMutex // Mutex to sync the settings access + + mailServer MailServer + + rateLimiter *PeerRateLimiter + + envelopeFeed event.Feed + + timeSource func() time.Time // source of time for waku + + logger *zap.Logger +} + +// New creates a Waku client ready to communicate through the Ethereum P2P network. +func New(cfg *Config, logger *zap.Logger) *Waku { + if cfg == nil { + c := DefaultConfig + cfg = &c + } + + if logger == nil { + logger = zap.NewNop() + } + + waku := &Waku{ + privateKeys: make(map[string]*ecdsa.PrivateKey), + symKeys: make(map[string][]byte), + envelopes: make(map[common.Hash]*Envelope), + expirations: make(map[uint32]mapset.Set), + peers: make(map[*Peer]struct{}), + msgQueue: make(chan *Envelope, messageQueueLimit), + p2pMsgQueue: make(chan interface{}, messageQueueLimit), + quit: make(chan struct{}), + timeSource: time.Now, + logger: logger, + } + + waku.settings = settings{ + MaxMsgSize: cfg.MaxMessageSize, + MinPow: cfg.MinimumAcceptedPoW, + MinPowTolerance: cfg.MinimumAcceptedPoW, + EnableConfirmations: cfg.EnableConfirmations, + LightClient: cfg.LightClient, + RestrictLightClientsConn: cfg.RestrictLightClientsConn, + SyncAllowance: DefaultSyncAllowance, + } + + if cfg.FullNode { + waku.settings.BloomFilter = MakeFullNodeBloom() + waku.settings.BloomFilterTolerance = MakeFullNodeBloom() + } + + waku.filters = NewFilters(waku) + + // p2p waku sub-protocol handler + waku.protocol = p2p.Protocol{ + Name: ProtocolName, + Version: uint(ProtocolVersion), + Length: NumberOfMessageCodes, + Run: waku.HandlePeer, + NodeInfo: func() interface{} { + return map[string]interface{}{ + "version": ProtocolVersionStr, + "maxMessageSize": waku.MaxMessageSize(), + "minimumPoW": waku.MinPow(), + } + }, + } + + return waku +} + +// Version returns the waku sub-protocol version number. +func (w *Waku) Version() uint { + return w.protocol.Version +} + +// MinPow returns the PoW value required by this node. +func (w *Waku) MinPow() float64 { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.MinPow +} + +// SetMinimumPoW sets the minimal PoW required by this node +func (w *Waku) SetMinimumPoW(val float64, tolerate bool) error { + if val < 0.0 { + return fmt.Errorf("invalid PoW: %f", val) + } + + w.settingsMu.Lock() + w.settings.MinPow = val + w.settingsMu.Unlock() + + w.notifyPeersAboutPowRequirementChange(val) + + if tolerate { + go func() { + // allow some time before all the peers have processed the notification + time.Sleep(time.Duration(w.settings.SyncAllowance) * time.Second) + w.settingsMu.Lock() + w.settings.MinPowTolerance = val + w.settingsMu.Unlock() + }() + } + + return nil +} + +// MinPowTolerance returns the value of minimum PoW which is tolerated for a limited +// time after PoW was changed. If sufficient time have elapsed or no change of PoW +// have ever occurred, the return value will be the same as return value of MinPow(). +func (w *Waku) MinPowTolerance() float64 { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.MinPowTolerance +} + +// BloomFilter returns the aggregated bloom filter for all the topics of interest. +// The nodes are required to send only messages that match the advertised bloom filter. +// If a message does not match the bloom, it will tantamount to spam, and the peer will +// be disconnected. +func (w *Waku) BloomFilter() []byte { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.BloomFilter +} + +// BloomFilterTolerance returns the bloom filter which is tolerated for a limited +// time after new bloom was advertised to the peers. If sufficient time have elapsed +// or no change of bloom filter have ever occurred, the return value will be the same +// as return value of BloomFilter(). +func (w *Waku) BloomFilterTolerance() []byte { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.BloomFilterTolerance +} + +// SetBloomFilter sets the new bloom filter +func (w *Waku) SetBloomFilter(bloom []byte) error { + if len(bloom) != BloomFilterSize { + return fmt.Errorf("invalid bloom filter size: %d", len(bloom)) + } + + b := make([]byte, BloomFilterSize) + copy(b, bloom) + + w.settingsMu.Lock() + w.settings.BloomFilter = b + w.settingsMu.Unlock() + w.notifyPeersAboutBloomFilterChange(b) + + go func() { + // allow some time before all the peers have processed the notification + time.Sleep(time.Duration(w.settings.SyncAllowance) * time.Second) + w.settingsMu.Lock() + w.settings.BloomFilterTolerance = b + w.settingsMu.Unlock() + }() + + return nil +} + +// MaxMessageSize returns the maximum accepted message size. +func (w *Waku) MaxMessageSize() uint32 { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.MaxMsgSize +} + +// SetMaxMessageSize sets the maximal message size allowed by this node +func (w *Waku) SetMaxMessageSize(size uint32) error { + if size > MaxMessageSize { + return fmt.Errorf("message size too large [%d>%d]", size, MaxMessageSize) + } + w.settingsMu.Lock() + w.settings.MaxMsgSize = size + w.settingsMu.Unlock() + return nil +} + +// LightClientMode indicates is this node is light client (does not forward any messages) +func (w *Waku) LightClientMode() bool { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.LightClient +} + +// SetLightClientMode makes node light client (does not forward any messages) +func (w *Waku) SetLightClientMode(v bool) { + w.settingsMu.Lock() + w.settings.LightClient = v + w.settingsMu.Unlock() +} + +// LightClientModeConnectionRestricted indicates that connection to light client in light client mode not allowed +func (w *Waku) LightClientModeConnectionRestricted() bool { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.RestrictLightClientsConn +} + +// RateLimiting returns RateLimits information. +func (w *Waku) RateLimits() RateLimits { + if w.rateLimiter == nil { + return RateLimits{} + } + return RateLimits{ + IPLimits: uint64(w.rateLimiter.limitPerSecIP), + PeerIDLimits: uint64(w.rateLimiter.limitPerSecPeerID), + } +} + +// ConfirmationsEnabled returns true if message confirmations are enabled. +func (w *Waku) ConfirmationsEnabled() bool { + w.settingsMu.RLock() + defer w.settingsMu.RUnlock() + return w.settings.EnableConfirmations +} + +// CurrentTime returns current time. +func (w *Waku) CurrentTime() time.Time { + return w.timeSource() +} + +// SetTimeSource assigns a particular source of time to a waku object. +func (w *Waku) SetTimeSource(timesource func() time.Time) { + w.timeSource = timesource +} + +// APIs returns the RPC descriptors the Waku implementation offers +func (w *Waku) APIs() []rpc.API { + return []rpc.API{ + { + Namespace: ProtocolName, + Version: ProtocolVersionStr, + Service: NewPublicWakuAPI(w), + Public: true, + }, + } +} + +// Protocols returns the waku sub-protocols ran by this particular client. +func (w *Waku) Protocols() []p2p.Protocol { + return []p2p.Protocol{w.protocol} +} + +// RegisterMailServer registers MailServer interface. +// MailServer will process all the incoming messages with p2pRequestCode. +func (w *Waku) RegisterMailServer(server MailServer) { + w.mailServer = server +} + +// SetRateLimiter registers a rate limiter. +func (w *Waku) RegisterRateLimiter(r *PeerRateLimiter) { + w.rateLimiter = r +} + +// SubscribeEnvelopeEvents subscribes to envelopes feed. +// In order to prevent blocking waku producers events must be amply buffered. +func (w *Waku) SubscribeEnvelopeEvents(events chan<- EnvelopeEvent) event.Subscription { + return w.envelopeFeed.Subscribe(events) +} + +func (w *Waku) notifyPeersAboutPowRequirementChange(pow float64) { + arr := w.getPeers() + for _, p := range arr { + err := p.notifyAboutPowRequirementChange(pow) + if err != nil { + // allow one retry + err = p.notifyAboutPowRequirementChange(pow) + } + if err != nil { + w.logger.Warn("failed to notify peer about new pow requirement", zap.Binary("peer", p.ID()), zap.Error(err)) + } + } +} + +func (w *Waku) notifyPeersAboutBloomFilterChange(bloom []byte) { + arr := w.getPeers() + for _, p := range arr { + err := p.notifyAboutBloomFilterChange(bloom) + if err != nil { + // allow one retry + err = p.notifyAboutBloomFilterChange(bloom) + } + if err != nil { + w.logger.Warn("failed to notify peer about new pow requirement", zap.Binary("peer", p.ID()), zap.Error(err)) + } + } +} + +func (w *Waku) getPeers() []*Peer { + arr := make([]*Peer, len(w.peers)) + i := 0 + w.peerMu.Lock() + for p := range w.peers { + arr[i] = p + i++ + } + w.peerMu.Unlock() + return arr +} + +// getPeer retrieves peer by ID +func (w *Waku) getPeer(peerID []byte) (*Peer, error) { + w.peerMu.Lock() + defer w.peerMu.Unlock() + for p := range w.peers { + id := p.peer.ID() + if bytes.Equal(peerID, id[:]) { + return p, nil + } + } + return nil, fmt.Errorf("could not find peer with ID: %x", peerID) +} + +// AllowP2PMessagesFromPeer marks specific peer trusted, +// which will allow it to send historic (expired) messages. +func (w *Waku) AllowP2PMessagesFromPeer(peerID []byte) error { + p, err := w.getPeer(peerID) + if err != nil { + return err + } + p.trusted = true + return nil +} + +// RequestHistoricMessages sends a message with p2pRequestCode to a specific peer, +// which is known to implement MailServer interface, and is supposed to process this +// request and respond with a number of peer-to-peer messages (possibly expired), +// which are not supposed to be forwarded any further. +// The waku protocol is agnostic of the format and contents of envelope. +func (w *Waku) RequestHistoricMessages(peerID []byte, envelope *Envelope) error { + return w.RequestHistoricMessagesWithTimeout(peerID, envelope, 0) +} + +// RequestHistoricMessagesWithTimeout acts as RequestHistoricMessages but requires to pass a timeout. +// It sends an event EventMailServerRequestExpired after the timeout. +func (w *Waku) RequestHistoricMessagesWithTimeout(peerID []byte, envelope *Envelope, timeout time.Duration) error { + p, err := w.getPeer(peerID) + if err != nil { + return err + } + p.trusted = true + + w.envelopeFeed.Send(EnvelopeEvent{ + Peer: p.peer.ID(), + Topic: envelope.Topic, + Hash: envelope.Hash(), + Event: EventMailServerRequestSent, + }) + + err = p2p.Send(p.ws, p2pRequestCode, envelope) + if timeout != 0 { + go w.expireRequestHistoricMessages(p.peer.ID(), envelope.Hash(), timeout) + } + return err +} + +func (w *Waku) SendMessagesRequest(peerID []byte, request MessagesRequest) error { + if err := request.Validate(); err != nil { + return err + } + p, err := w.getPeer(peerID) + if err != nil { + return err + } + p.trusted = true + if err := p2p.Send(p.ws, p2pRequestCode, request); err != nil { + return err + } + w.envelopeFeed.Send(EnvelopeEvent{ + Peer: p.peer.ID(), + Hash: common.BytesToHash(request.ID), + Event: EventMailServerRequestSent, + }) + return nil +} + +func (w *Waku) expireRequestHistoricMessages(peer enode.ID, hash common.Hash, timeout time.Duration) { + timer := time.NewTimer(timeout) + defer timer.Stop() + select { + case <-w.quit: + return + case <-timer.C: + w.envelopeFeed.Send(EnvelopeEvent{ + Peer: peer, + Hash: hash, + Event: EventMailServerRequestExpired, + }) + } +} + +func (w *Waku) SendHistoricMessageResponse(peerID []byte, payload []byte) error { + size, r, err := rlp.EncodeToReader(payload) + if err != nil { + return err + } + peer, err := w.getPeer(peerID) + if err != nil { + return err + } + return peer.ws.WriteMsg(p2p.Msg{Code: p2pRequestCompleteCode, Size: uint32(size), Payload: r}) +} + +// SendP2PMessage sends a peer-to-peer message to a specific peer. +// It sends one or more envelopes in a single batch. +func (w *Waku) SendP2PMessages(peerID []byte, envelopes ...*Envelope) error { + p, err := w.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(p.ws, p2pMessageCode, envelopes) +} + +// SendP2PDirect sends a peer-to-peer message to a specific peer. +// It sends one or more envelopes in a single batch. +func (w *Waku) SendP2PDirect(peerID []byte, envelopes ...*Envelope) error { + peer, err := w.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pMessageCode, envelopes) +} + +// SendRawP2PDirect sends a peer-to-peer message to a specific peer. +// It sends one or more envelopes in a single batch. +func (w *Waku) SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error { + peer, err := w.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pMessageCode, envelopes) +} + +// NewKeyPair generates a new cryptographic identity for the client, and injects +// it into the known identities for message decryption. Returns ID of the new key pair. +func (w *Waku) NewKeyPair() (string, error) { + key, err := crypto.GenerateKey() + if err != nil || !validatePrivateKey(key) { + key, err = crypto.GenerateKey() // retry once + } + if err != nil { + return "", err + } + if !validatePrivateKey(key) { + return "", fmt.Errorf("failed to generate valid key") + } + + id, err := toDeterministicID(hexutil.Encode(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize) + if err != nil { + return "", err + } + + w.keyMu.Lock() + defer w.keyMu.Unlock() + + if w.privateKeys[id] != nil { + return "", fmt.Errorf("failed to generate unique ID") + } + w.privateKeys[id] = key + return id, nil +} + +// DeleteKeyPair deletes the specified key if it exists. +func (w *Waku) DeleteKeyPair(key string) bool { + deterministicID, err := toDeterministicID(key, 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 +} + +// AddKeyPair imports a asymmetric private key and returns it identifier. +func (w *Waku) AddKeyPair(key *ecdsa.PrivateKey) (string, error) { + id, err := makeDeterministicID(hexutil.Encode(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() + w.privateKeys[id] = key + w.keyMu.Unlock() + + return id, nil +} + +// SelectKeyPair adds cryptographic identity, and makes sure +// that it is the only private key known to the node. +func (w *Waku) SelectKeyPair(key *ecdsa.PrivateKey) error { + id, err := makeDeterministicID(common.ToHex(crypto.FromECDSAPub(&key.PublicKey)), keyIDSize) + if err != nil { + return err + } + + w.keyMu.Lock() + defer w.keyMu.Unlock() + + w.privateKeys = make(map[string]*ecdsa.PrivateKey) // reset key store + w.privateKeys[id] = key + + return nil +} + +// DeleteKeyPairs removes all cryptographic identities known to the node +func (w *Waku) DeleteKeyPairs() error { + w.keyMu.Lock() + defer w.keyMu.Unlock() + + w.privateKeys = make(map[string]*ecdsa.PrivateKey) + + return nil +} + +// HasKeyPair checks if the waku node is configured with the private key +// of the specified public pair. +func (w *Waku) HasKeyPair(id string) bool { + deterministicID, err := toDeterministicID(id, keyIDSize) + if err != nil { + return false + } + + w.keyMu.RLock() + defer w.keyMu.RUnlock() + return w.privateKeys[deterministicID] != nil +} + +// GetPrivateKey retrieves the private key of the specified identity. +func (w *Waku) 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[deterministicID] + if key == nil { + return nil, fmt.Errorf("invalid id") + } + return key, nil +} + +// GenerateSymKey generates a random symmetric key and stores it under id, +// which is then returned. Will be used in the future for session key exchange. +func (w *Waku) GenerateSymKey() (string, error) { + key, err := generateSecureRandomData(aesKeyLength) + if err != nil { + return "", err + } else if !validateDataIntegrity(key, aesKeyLength) { + return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data") + } + + id, err := GenerateRandomID() + if err != nil { + return "", fmt.Errorf("failed to generate ID: %s", err) + } + + w.keyMu.Lock() + defer w.keyMu.Unlock() + + if w.symKeys[id] != nil { + return "", fmt.Errorf("failed to generate unique ID") + } + w.symKeys[id] = key + return id, nil +} + +// AddSymKey stores the key with a given id. +func (w *Waku) 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 *Waku) AddSymKeyDirect(key []byte) (string, error) { + if len(key) != aesKeyLength { + return "", fmt.Errorf("wrong key size: %d", len(key)) + } + + id, err := GenerateRandomID() + if err != nil { + return "", fmt.Errorf("failed to generate ID: %s", err) + } + + w.keyMu.Lock() + defer w.keyMu.Unlock() + + if w.symKeys[id] != nil { + return "", fmt.Errorf("failed to generate unique ID") + } + w.symKeys[id] = key + return id, nil +} + +// AddSymKeyFromPassword generates the key from password, stores it, and returns its id. +func (w *Waku) AddSymKeyFromPassword(password string) (string, error) { + id, err := GenerateRandomID() + if err != nil { + return "", fmt.Errorf("failed to generate ID: %s", err) + } + if w.HasSymKey(id) { + return "", fmt.Errorf("failed to generate unique ID") + } + + // kdf should run no less than 0.1 seconds on an average computer, + // because it's an once in a session experience + derived := pbkdf2.Key([]byte(password), nil, 65356, aesKeyLength, sha256.New) + if err != nil { + return "", err + } + + w.keyMu.Lock() + defer w.keyMu.Unlock() + + // double check is necessary, because deriveKeyMaterial() is very slow + if w.symKeys[id] != nil { + return "", fmt.Errorf("critical error: failed to generate unique ID") + } + w.symKeys[id] = derived + return id, nil +} + +// HasSymKey returns true if there is a key associated with the given id. +// Otherwise returns false. +func (w *Waku) HasSymKey(id string) bool { + w.keyMu.RLock() + defer w.keyMu.RUnlock() + return w.symKeys[id] != nil +} + +// DeleteSymKey deletes the key associated with the name string if it exists. +func (w *Waku) DeleteSymKey(id string) bool { + w.keyMu.Lock() + defer w.keyMu.Unlock() + if w.symKeys[id] != nil { + delete(w.symKeys, id) + return true + } + return false +} + +// GetSymKey returns the symmetric key associated with the given id. +func (w *Waku) GetSymKey(id string) ([]byte, error) { + w.keyMu.RLock() + defer w.keyMu.RUnlock() + if w.symKeys[id] != nil { + return w.symKeys[id], nil + } + return nil, fmt.Errorf("non-existent key ID") +} + +// Subscribe installs a new message handler used for filtering, decrypting +// and subsequent storing of incoming messages. +func (w *Waku) Subscribe(f *Filter) (string, error) { + s, err := w.filters.Install(f) + if err == nil { + w.updateBloomFilter(f) + } + return s, err +} + +// updateBloomFilter recalculates the new value of bloom filter, +// and informs the peers if necessary. +func (w *Waku) updateBloomFilter(f *Filter) { + aggregate := make([]byte, BloomFilterSize) + for _, t := range f.Topics { + top := BytesToTopic(t) + b := TopicToBloom(top) + aggregate = addBloom(aggregate, b) + } + + if !BloomFilterMatch(w.BloomFilter(), aggregate) { + // existing bloom filter must be updated + aggregate = addBloom(w.BloomFilter(), aggregate) + w.SetBloomFilter(aggregate) + } +} + +// GetFilter returns the filter by id. +func (w *Waku) GetFilter(id string) *Filter { + return w.filters.Get(id) +} + +// Unsubscribe removes an installed message handler. +func (w *Waku) Unsubscribe(id string) error { + ok := w.filters.Uninstall(id) + if !ok { + return fmt.Errorf("Unsubscribe: Invalid ID") + } + return nil +} + +// Send injects a message into the waku send queue, to be distributed in the +// network in the coming cycles. +func (w *Waku) Send(envelope *Envelope) error { + ok, err := w.add(envelope, false) + if err == nil && !ok { + return fmt.Errorf("failed to add envelope") + } + return err +} + +// Start implements node.Service, starting the background data propagation thread +// of the Waku protocol. +func (w *Waku) Start(*p2p.Server) error { + go w.update() + + numCPU := runtime.NumCPU() + for i := 0; i < numCPU; i++ { + go w.processQueue() + } + go w.processP2P() + + return nil +} + +// Stop implements node.Service, stopping the background data propagation thread +// of the Waku protocol. +func (w *Waku) Stop() error { + close(w.quit) + return nil +} + +// HandlePeer is called by the underlying P2P layer when the waku sub-protocol +// connection is negotiated. +func (w *Waku) HandlePeer(peer *p2p.Peer, rw p2p.MsgReadWriter) error { + // Create the new peer and start tracking it + wakuPeer := newPeer(w, peer, rw, w.logger.Named("waku/peer")) + + w.peerMu.Lock() + w.peers[wakuPeer] = struct{}{} + w.peerMu.Unlock() + + defer func() { + w.peerMu.Lock() + delete(w.peers, wakuPeer) + w.peerMu.Unlock() + }() + + // Run the peer handshake and state updates + if err := wakuPeer.handshake(); err != nil { + return err + } + wakuPeer.start() + defer wakuPeer.stop() + + if w.rateLimiter != nil { + return w.rateLimiter.decorate(wakuPeer, rw, w.runMessageLoop) + } + return w.runMessageLoop(wakuPeer, rw) +} + +// sendConfirmation sends messageResponseCode and batchAcknowledgedCode messages. +func (w *Waku) sendConfirmation(rw p2p.MsgReadWriter, data []byte, envelopeErrors []EnvelopeError) (err error) { + batchHash := crypto.Keccak256Hash(data) + err = p2p.Send(rw, messageResponseCode, NewMessagesResponse(batchHash, envelopeErrors)) + err = p2p.Send(rw, batchAcknowledgedCode, batchHash) // DEPRECATED + return +} + +// runMessageLoop reads and processes inbound messages directly to merge into client-global state. +func (w *Waku) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { + logger := w.logger.Named("runMessageLoop") + peerID := p.peer.ID() + + for { + // fetch the next packet + packet, err := rw.ReadMsg() + if err != nil { + logger.Info("failed to read a message", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + + if packet.Size > w.MaxMessageSize() { + logger.Warn("oversize message received", zap.Binary("peer", peerID[:]), zap.Uint32("size", packet.Size)) + return errors.New("oversize message received") + } + + switch packet.Code { + case messagesCode: + if err := w.handleMessagesCode(p, rw, packet, logger); err != nil { + logger.Warn("failed to handle messagesCode message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case messageResponseCode: + if err := w.handleMessageResponseCode(p, packet, logger); err != nil { + logger.Warn("failed to handle messageResponseCode message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case batchAcknowledgedCode: + if err := w.handleBatchAcknowledgeCode(p, packet, logger); err != nil { + + } + case powRequirementCode: + if err := w.handlePowRequirementCode(p, packet, logger); err != nil { + logger.Warn("failed to handle powRequirementCode message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case bloomFilterExCode: + if err := w.handleBloomFilterExCode(p, packet, logger); err != nil { + logger.Warn("failed to decode bloom filter exchange message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case p2pMessageCode: + if err := w.handleP2PMessageCode(p, packet, logger); err != nil { + logger.Warn("failed to decode direct message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case p2pRequestCode: + if err := w.handleP2PRequestCode(p, packet, logger); err != nil { + logger.Warn("failed to decode p2p request message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + case p2pRequestCompleteCode: + if err := w.handleP2PRequestCompleteCode(p, packet, logger); err != nil { + logger.Warn("failed to decode p2p request complete message, peer will be disconnected", zap.Binary("peer", peerID[:]), zap.Error(err)) + return err + } + default: + // New message types might be implemented in the future versions of Waku. + // For forward compatibility, just ignore. + logger.Debug("ignored packet with message code", zap.Uint64("code", packet.Code)) + } + + _ = packet.Discard() + } +} + +func (w *Waku) handleMessagesCode(p *Peer, rw p2p.MsgReadWriter, packet p2p.Msg, logger *zap.Logger) error { + peerID := p.peer.ID() + + // decode the contained envelopes + data, err := ioutil.ReadAll(packet.Payload) + if err != nil { + envelopesRejectedCounter.WithLabelValues("failed_read").Inc() + return fmt.Errorf("failed to read packet payload: %w", err) + } + + var envelopes []*Envelope + if err := rlp.DecodeBytes(data, &envelopes); err != nil { + envelopesRejectedCounter.WithLabelValues("invalid_data").Inc() + return fmt.Errorf("invalid payload: %w", err) + } + + envelopeErrors := make([]EnvelopeError, 0) + trouble := false + for _, env := range envelopes { + cached, err := w.add(env, w.LightClientMode()) + if err != nil { + _, isTimeSyncError := err.(TimeSyncError) + if !isTimeSyncError { + trouble = true + logger.Info("invalid envelope received", zap.Binary("peer", peerID[:]), zap.Error(err)) + } + envelopeErrors = append(envelopeErrors, ErrorToEnvelopeError(env.Hash(), err)) + } else if cached { + p.mark(env) + } + + w.envelopeFeed.Send(EnvelopeEvent{ + Event: EventEnvelopeReceived, + Topic: env.Topic, + Hash: env.Hash(), + Peer: p.peer.ID(), + }) + envelopesValidatedCounter.Inc() + } + + if w.ConfirmationsEnabled() { + go w.sendConfirmation(rw, data, envelopeErrors) + } + + if trouble { + return errors.New("received invalid envelope") + } + return nil +} + +func (w *Waku) handlePowRequirementCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + s := rlp.NewStream(packet.Payload, uint64(packet.Size)) + i, err := s.Uint() + if err != nil { + envelopesRejectedCounter.WithLabelValues("invalid_pow_req").Inc() + return fmt.Errorf("invalid powRequirementCode message: %w", err) + } + f := math.Float64frombits(i) + if math.IsInf(f, 0) || math.IsNaN(f) || f < 0.0 { + envelopesRejectedCounter.WithLabelValues("invalid_pow_req").Inc() + return errors.New("invalid value in powRequirementCode message") + } + p.powRequirement = f + return nil +} + +func (w *Waku) handleBloomFilterExCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + var bloom []byte + err := packet.Decode(&bloom) + if err == nil && len(bloom) != BloomFilterSize { + err = fmt.Errorf("wrong bloom filter size %d", len(bloom)) + } + if err != nil { + envelopesRejectedCounter.WithLabelValues("invalid_bloom").Inc() + return errors.New("invalid bloom filter exchange message") + } + + p.setBloomFilter(bloom) + return nil +} + +func (w *Waku) handleP2PMessageCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + // peer-to-peer message, sent directly to peer bypassing PoW checks, etc. + // this message is not supposed to be forwarded to other peers, and + // therefore might not satisfy the PoW, expiry and other requirements. + // these messages are only accepted from the trusted peer. + if !p.trusted { + return nil + } + + var ( + envelopes []*Envelope + err error + ) + + if err = packet.Decode(&envelopes); err != nil { + return fmt.Errorf("invalid direct message payload: %w", err) + } + + for _, envelope := range envelopes { + w.postP2P(envelope) + } + return nil +} + +func (w *Waku) handleP2PRequestCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + peerID := p.peer.ID() + + // Must be processed if mail server is implemented. Otherwise ignore. + if w.mailServer == nil { + return nil + } + + // Read all data as we will try to decode it possibly twice. + data, err := ioutil.ReadAll(packet.Payload) + if err != nil { + return fmt.Errorf("invalid p2p request messages: %w", err) + } + r := bytes.NewReader(data) + packet.Payload = r + + var requestDeprecated Envelope + errDepReq := packet.Decode(&requestDeprecated) + if errDepReq == nil { + w.mailServer.DeliverMail(p.ID(), &requestDeprecated) + return nil + } else { + logger.Info("failed to decode p2p request message (deprecated)", zap.Binary("peer", peerID[:]), zap.Error(errDepReq)) + } + + // As we failed to decode the request, let's set the offset + // to the beginning and try decode it again. + if _, err := r.Seek(0, io.SeekStart); err != nil { + return fmt.Errorf("invalid p2p request message: %w", err) + } + + var request MessagesRequest + errReq := packet.Decode(&request) + if errReq == nil { + w.mailServer.Deliver(p.ID(), request) + return nil + } else { + logger.Info("failed to decode p2p request message", zap.Binary("peer", peerID[:]), zap.Error(errDepReq)) + } + + return errors.New("invalid p2p request message") +} + +func (w *Waku) handleP2PRequestCompleteCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + if !p.trusted { + return nil + } + + var payload []byte + if err := packet.Decode(&payload); err != nil { + return fmt.Errorf("invalid p2p request complete message: %w", err) + } + + event, err := CreateMailServerEvent(p.peer.ID(), payload) + if err != nil { + return fmt.Errorf("invalid p2p request complete payload: %w", err) + } + + w.postP2P(*event) + return nil +} + +func (w *Waku) handleMessageResponseCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + var resp MultiVersionResponse + if err := packet.Decode(&resp); err != nil { + envelopesRejectedCounter.WithLabelValues("failed_read").Inc() + return fmt.Errorf("invalid response message: %w", err) + } + if resp.Version != 1 { + logger.Info("received unsupported version of MultiVersionResponse for messageResponseCode packet", zap.Uint("version", resp.Version)) + return nil + } + + response, err := resp.DecodeResponse1() + if err != nil { + envelopesRejectedCounter.WithLabelValues("invalid_data").Inc() + return fmt.Errorf("failed to decode response message: %w", err) + } + + w.envelopeFeed.Send(EnvelopeEvent{ + Batch: response.Hash, + Event: EventBatchAcknowledged, + Peer: p.peer.ID(), + Data: response.Errors, + }) + + return nil +} + +func (w *Waku) handleBatchAcknowledgeCode(p *Peer, packet p2p.Msg, logger *zap.Logger) error { + var batchHash common.Hash + if err := packet.Decode(&batchHash); err != nil { + return fmt.Errorf("invalid batch ack message: %w", err) + } + w.envelopeFeed.Send(EnvelopeEvent{ + Batch: batchHash, + Event: EventBatchAcknowledged, + Peer: p.peer.ID(), + }) + return nil +} + +// add inserts a new envelope into the message pool to be distributed within the +// waku network. It also inserts the envelope into the expiration pool at the +// appropriate time-stamp. In case of error, connection should be dropped. +// param isP2P indicates whether the message is peer-to-peer (should not be forwarded). +func (w *Waku) add(envelope *Envelope, isP2P bool) (bool, error) { + now := uint32(w.timeSource().Unix()) + sent := envelope.Expiry - envelope.TTL + + envelopesReceivedCounter.Inc() + if sent > now { + if sent-DefaultSyncAllowance > now { + envelopesCacheFailedCounter.WithLabelValues("in_future").Inc() + log.Warn("envelope created in the future", "hash", envelope.Hash()) + return false, TimeSyncError(errors.New("envelope from future")) + } + // recalculate PoW, adjusted for the time difference, plus one second for latency + envelope.calculatePoW(sent - now + 1) + } + + if envelope.Expiry < now { + if envelope.Expiry+DefaultSyncAllowance*2 < now { + envelopesCacheFailedCounter.WithLabelValues("very_old").Inc() + log.Warn("very old envelope", "hash", envelope.Hash()) + return false, TimeSyncError(errors.New("very old envelope")) + } + log.Debug("expired envelope dropped", "hash", envelope.Hash().Hex()) + envelopesCacheFailedCounter.WithLabelValues("expired").Inc() + return false, nil // drop envelope without error + } + + if uint32(envelope.size()) > w.MaxMessageSize() { + envelopesCacheFailedCounter.WithLabelValues("oversized").Inc() + return false, fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash()) + } + + if envelope.PoW() < w.MinPow() { + // maybe the value was recently changed, and the peers did not adjust yet. + // in this case the previous value is retrieved by MinPowTolerance() + // for a short period of peer synchronization. + if envelope.PoW() < w.MinPowTolerance() { + envelopesCacheFailedCounter.WithLabelValues("low_pow").Inc() + return false, fmt.Errorf("envelope with low PoW received: PoW=%f, hash=[%v]", envelope.PoW(), envelope.Hash().Hex()) + } + } + + if !BloomFilterMatch(w.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. + if !BloomFilterMatch(w.BloomFilterTolerance(), envelope.Bloom()) { + envelopesCacheFailedCounter.WithLabelValues("no_bloom_match").Inc() + return false, fmt.Errorf("envelope does not match bloom filter, hash=[%v], bloom: \n%x \n%x \n%x", + envelope.Hash().Hex(), w.BloomFilter(), envelope.Bloom(), envelope.Topic) + } + } + + hash := envelope.Hash() + + w.poolMu.Lock() + _, alreadyCached := w.envelopes[hash] + if !alreadyCached { + w.envelopes[hash] = envelope + if w.expirations[envelope.Expiry] == nil { + w.expirations[envelope.Expiry] = mapset.NewThreadUnsafeSet() + } + if !w.expirations[envelope.Expiry].Contains(hash) { + w.expirations[envelope.Expiry].Add(hash) + } + } + w.poolMu.Unlock() + + if alreadyCached { + log.Trace("w envelope already cached", "hash", envelope.Hash().Hex()) + envelopesCachedCounter.WithLabelValues("hit").Inc() + } else { + log.Trace("cached w envelope", "hash", envelope.Hash().Hex()) + envelopesCachedCounter.WithLabelValues("miss").Inc() + envelopesSizeMeter.Observe(float64(envelope.size())) + w.postEvent(envelope, isP2P) // notify the local node about the new message + if w.mailServer != nil { + w.mailServer.Archive(envelope) + w.envelopeFeed.Send(EnvelopeEvent{ + Topic: envelope.Topic, + Hash: envelope.Hash(), + Event: EventMailServerEnvelopeArchived, + }) + } + } + return true, nil +} + +func (w *Waku) postP2P(event interface{}) { + w.p2pMsgQueue <- event +} + +// postEvent queues the message for further processing. +func (w *Waku) postEvent(envelope *Envelope, isP2P bool) { + if isP2P { + w.postP2P(envelope) + } else { + w.msgQueue <- envelope + } +} + +// processQueue delivers the messages to the watchers during the lifetime of the waku node. +func (w *Waku) processQueue() { + for { + select { + case <-w.quit: + return + case e := <-w.msgQueue: + w.filters.NotifyWatchers(e, false) + w.envelopeFeed.Send(EnvelopeEvent{ + Topic: e.Topic, + Hash: e.Hash(), + Event: EventEnvelopeAvailable, + }) + } + } +} + +func (w *Waku) processP2P() { + for { + select { + case <-w.quit: + return + case e := <-w.p2pMsgQueue: + switch event := e.(type) { + case *Envelope: + w.filters.NotifyWatchers(event, true) + w.envelopeFeed.Send(EnvelopeEvent{ + Topic: event.Topic, + Hash: event.Hash(), + Event: EventEnvelopeAvailable, + }) + case EnvelopeEvent: + w.envelopeFeed.Send(event) + } + } + } +} + +// update loops until the lifetime of the waku node, updating its internal +// state by expiring stale messages from the pool. +func (w *Waku) update() { + // Start a ticker to check for expirations + expire := time.NewTicker(expirationCycle) + + // Repeat updates until termination is requested + for { + select { + case <-expire.C: + w.expire() + + case <-w.quit: + return + } + } +} + +// expire iterates over all the expiration timestamps, removing all stale +// messages from the pools. +func (w *Waku) expire() { + w.poolMu.Lock() + defer w.poolMu.Unlock() + + now := uint32(w.timeSource().Unix()) + for expiry, hashSet := range w.expirations { + if expiry < now { + // Dump all expired messages and remove timestamp + hashSet.Each(func(v interface{}) bool { + delete(w.envelopes, v.(common.Hash)) + envelopesCachedCounter.WithLabelValues("clear").Inc() + w.envelopeFeed.Send(EnvelopeEvent{ + Hash: v.(common.Hash), + Event: EventEnvelopeExpired, + }) + return false + }) + w.expirations[expiry].Clear() + delete(w.expirations, expiry) + } + } +} + +// Envelopes retrieves all the messages currently pooled by the node. +func (w *Waku) Envelopes() []*Envelope { + w.poolMu.RLock() + defer w.poolMu.RUnlock() + + all := make([]*Envelope, 0, len(w.envelopes)) + for _, envelope := range w.envelopes { + all = append(all, envelope) + } + return all +} + +// GetEnvelope retrieves an envelope from the message queue by its hash. +// It returns nil if the envelope can not be found. +func (w *Waku) GetEnvelope(hash common.Hash) *Envelope { + w.poolMu.RLock() + defer w.poolMu.RUnlock() + return w.envelopes[hash] +} + +// isEnvelopeCached checks if envelope with specific hash has already been received and cached. +func (w *Waku) isEnvelopeCached(hash common.Hash) bool { + w.poolMu.Lock() + defer w.poolMu.Unlock() + + _, exist := w.envelopes[hash] + return exist +} + +// ValidatePublicKey checks the format of the given public key. +func ValidatePublicKey(k *ecdsa.PublicKey) bool { + return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0 +} + +// validatePrivateKey checks the format of the given private key. +func validatePrivateKey(k *ecdsa.PrivateKey) bool { + if k == nil || k.D == nil || k.D.Sign() == 0 { + return false + } + return ValidatePublicKey(&k.PublicKey) +} + +// validateDataIntegrity returns false if the data have the wrong or contains all zeros, +// which is the simplest and the most common bug. +func validateDataIntegrity(k []byte, expectedSize int) bool { + if len(k) != expectedSize { + return false + } + if expectedSize > 3 && containsOnlyZeros(k) { + return false + } + return true +} + +// containsOnlyZeros checks if the data contain only zeros. +func containsOnlyZeros(data []byte) bool { + for _, b := range data { + if b != 0 { + return false + } + } + return true +} + +// bytesToUintLittleEndian converts the slice to 64-bit unsigned integer. +func bytesToUintLittleEndian(b []byte) (res uint64) { + mul := uint64(1) + for i := 0; i < len(b); i++ { + res += uint64(b[i]) * mul + mul *= 256 + } + return res +} + +// BytesToUintBigEndian converts the slice to 64-bit unsigned integer. +func BytesToUintBigEndian(b []byte) (res uint64) { + for i := 0; i < len(b); i++ { + res *= 256 + res += uint64(b[i]) + } + return res +} + +// GenerateRandomID generates a random string, which is then returned to be used as a key id +func GenerateRandomID() (id string, err error) { + buf, err := generateSecureRandomData(keyIDSize) + if err != nil { + return "", err + } + if !validateDataIntegrity(buf, keyIDSize) { + return "", fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data") + } + 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 !validateDataIntegrity(buf, keyIDSize) { + 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 +} + +func isFullNode(bloom []byte) bool { + if bloom == nil { + return true + } + for _, b := range bloom { + if b != 255 { + return false + } + } + return true +} + +func BloomFilterMatch(filter, sample []byte) bool { + if filter == nil { + return true + } + + for i := 0; i < BloomFilterSize; i++ { + f := filter[i] + s := sample[i] + if (f | s) != f { + return false + } + } + + return true +} + +func addBloom(a, b []byte) []byte { + c := make([]byte, BloomFilterSize) + for i := 0; i < BloomFilterSize; i++ { + c[i] = a[i] | b[i] + } + return c +} diff --git a/vendor/github.com/status-im/status-go/whisper/v6/doc.go b/vendor/github.com/status-im/status-go/whisper/v6/doc.go index 12d39ab0b..fdee9d708 100644 --- a/vendor/github.com/status-im/status-go/whisper/v6/doc.go +++ b/vendor/github.com/status-im/status-go/whisper/v6/doc.go @@ -105,10 +105,9 @@ const ( // in order to bypass the expiry checks. type MailServer interface { Archive(env *Envelope) - // DEPRECATED - DeliverMail(whisperPeer *Peer, request *Envelope) - Deliver(whisperPeer *Peer, request MessagesRequest) - SyncMail(*Peer, SyncMailRequest) error + DeliverMail(peerID []byte, req *Envelope) // DEPRECATED; user Deliver instead + Deliver(peerID []byte, req MessagesRequest) + SyncMail(peerID []byte, req SyncMailRequest) error } // MessagesRequest contains details of a request of historic messages. diff --git a/vendor/github.com/status-im/status-go/whisper/v6/metrics.go b/vendor/github.com/status-im/status-go/whisper/v6/metrics.go index 6ffa436fc..09b3af10f 100644 --- a/vendor/github.com/status-im/status-go/whisper/v6/metrics.go +++ b/vendor/github.com/status-im/status-go/whisper/v6/metrics.go @@ -6,37 +6,37 @@ import ( var ( envelopesReceivedCounter = prom.NewCounter(prom.CounterOpts{ - Name: "waku_envelopes_received_total", + Name: "whisper_envelopes_received_total", Help: "Number of envelopes received.", }) envelopesValidatedCounter = prom.NewCounter(prom.CounterOpts{ - Name: "waku_envelopes_validated_total", + Name: "whisper_envelopes_validated_total", Help: "Number of envelopes processed successfully.", }) envelopesRejectedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_rejected_total", + Name: "whisper_envelopes_rejected_total", Help: "Number of envelopes rejected.", }, []string{"reason"}) envelopesCacheFailedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_cache_failures_total", + Name: "whisper_envelopes_cache_failures_total", Help: "Number of envelopes which failed to be cached.", }, []string{"type"}) envelopesCachedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_cached_total", + Name: "whisper_envelopes_cached_total", Help: "Number of envelopes cached.", }, []string{"cache"}) envelopesSizeMeter = prom.NewHistogram(prom.HistogramOpts{ - Name: "waku_envelopes_size_bytes", + Name: "whisper_envelopes_size_bytes", Help: "Size of processed Waku envelopes in bytes.", Buckets: prom.ExponentialBuckets(256, 4, 10), }) // rate limiter metrics rateLimitsProcessed = prom.NewCounter(prom.CounterOpts{ - Name: "waku_rate_limits_processed_total", + Name: "whisper_rate_limits_processed_total", Help: "Number of packets Waku rate limiter processed.", }) rateLimitsExceeded = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_rate_limits_exceeded_total", + Name: "whisper_rate_limits_exceeded_total", Help: "Number of times the Waku rate limits were exceeded", }, []string{"type"}) ) diff --git a/vendor/github.com/status-im/status-go/whisper/v6/whisper.go b/vendor/github.com/status-im/status-go/whisper/v6/whisper.go index cff9dcf54..693fede2d 100644 --- a/vendor/github.com/status-im/status-go/whisper/v6/whisper.go +++ b/vendor/github.com/status-im/status-go/whisper/v6/whisper.go @@ -104,7 +104,7 @@ type Whisper struct { statsMu sync.Mutex // guard stats stats Statistics // Statistics of whisper node - mailServer MailServer // MailServer interface + mailServer MailServer rateLimiter *PeerRateLimiter @@ -264,7 +264,7 @@ func (whisper *Whisper) GetCurrentTime() time.Time { // RegisterServer registers MailServer interface. // MailServer will process all the incoming messages with p2pRequestCode. -func (whisper *Whisper) RegisterServer(server MailServer) { +func (whisper *Whisper) RegisterMailServer(server MailServer) { whisper.mailServer = server } @@ -502,12 +502,15 @@ func (whisper *Whisper) expireRequestHistoricMessages(peer enode.ID, hash common } } -func (whisper *Whisper) SendHistoricMessageResponse(peer *Peer, payload []byte) error { +func (whisper *Whisper) SendHistoricMessageResponse(peerID []byte, payload []byte) error { size, r, err := rlp.EncodeToReader(payload) if err != nil { return err } - + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } return peer.ws.WriteMsg(p2p.Msg{Code: p2pRequestCompleteCode, Size: uint32(size), Payload: r}) } @@ -530,29 +533,37 @@ func (whisper *Whisper) SyncMessages(peerID []byte, req SyncMailRequest) error { } // SendSyncResponse sends a response to a Mail Server with a slice of envelopes. -func (whisper *Whisper) SendSyncResponse(p *Peer, data SyncResponse) error { - return p2p.Send(p.ws, p2pSyncResponseCode, data) +func (whisper *Whisper) SendSyncResponse(peerID []byte, data SyncResponse) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pSyncResponseCode, data) } // SendRawSyncResponse sends a response to a Mail Server with a slice of envelopes. -func (whisper *Whisper) SendRawSyncResponse(p *Peer, data RawSyncResponse) error { - return p2p.Send(p.ws, p2pSyncResponseCode, data) +func (whisper *Whisper) SendRawSyncResponse(peerID []byte, data RawSyncResponse) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pSyncResponseCode, data) } // SendP2PMessage sends a peer-to-peer message to a specific peer. func (whisper *Whisper) SendP2PMessage(peerID []byte, envelopes ...*Envelope) error { - p, err := whisper.getPeer(peerID) - if err != nil { - return err - } - return whisper.SendP2PDirect(p, envelopes...) + return whisper.SendP2PDirect(peerID, envelopes...) } // SendP2PDirect sends a peer-to-peer message to a specific peer. // If only a single envelope is given, data is sent as a single object // rather than a slice. This is important to keep this method backward compatible // as it used to send only single envelopes. -func (whisper *Whisper) SendP2PDirect(peer *Peer, envelopes ...*Envelope) error { +func (whisper *Whisper) SendP2PDirect(peerID []byte, envelopes ...*Envelope) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } if len(envelopes) == 1 { return p2p.Send(peer.ws, p2pMessageCode, envelopes[0]) } @@ -563,7 +574,11 @@ func (whisper *Whisper) SendP2PDirect(peer *Peer, envelopes ...*Envelope) error // If only a single envelope is given, data is sent as a single object // rather than a slice. This is important to keep this method backward compatible // as it used to send only single envelopes. -func (whisper *Whisper) SendRawP2PDirect(peer *Peer, envelopes ...rlp.RawValue) error { +func (whisper *Whisper) SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } if len(envelopes) == 1 { return p2p.Send(peer.ws, p2pMessageCode, envelopes[0]) } @@ -1099,13 +1114,13 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { return fmt.Errorf("sync mail request was invalid: %v", err) } - if err := whisper.mailServer.SyncMail(p, request); err != nil { + if err := whisper.mailServer.SyncMail(p.ID(), request); err != nil { log.Error( "failed to sync envelopes", "peer", p.peer.ID().String(), ) _ = whisper.SendSyncResponse( - p, + p.ID(), SyncResponse{Error: err.Error()}, ) return err @@ -1157,7 +1172,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { var requestDeprecated Envelope errDepReq := packet.Decode(&requestDeprecated) if errDepReq == nil { - whisper.mailServer.DeliverMail(p, &requestDeprecated) + whisper.mailServer.DeliverMail(p.ID(), &requestDeprecated) continue } else { log.Info("failed to decode p2p request message (deprecated)", "peer", p.peer.ID(), "err", errDepReq) @@ -1172,7 +1187,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { var request MessagesRequest errReq := packet.Decode(&request) if errReq == nil { - whisper.mailServer.Deliver(p, request) + whisper.mailServer.Deliver(p.ID(), request) continue } else { log.Info("failed to decode p2p request message", "peer", p.peer.ID(), "err", errReq) diff --git a/vendor/modules.txt b/vendor/modules.txt index 6f4a00773..e2244a46d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -3,7 +3,7 @@ github.com/BurntSushi/toml # github.com/allegro/bigcache v1.2.0 github.com/allegro/bigcache github.com/allegro/bigcache/queue -# github.com/aristanetworks/goarista v0.0.0-20190502180301-283422fc1708 +# github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 github.com/aristanetworks/goarista/monotime # github.com/beevik/ntp v0.2.0 github.com/beevik/ntp @@ -28,7 +28,7 @@ github.com/davecgh/go-spew/spew github.com/deckarep/golang-set # github.com/edsrzf/mmap-go v1.0.0 github.com/edsrzf/mmap-go -# github.com/elastic/gosigar v0.10.4 +# github.com/elastic/gosigar v0.10.5 github.com/elastic/gosigar github.com/elastic/gosigar/sys/windows # github.com/ethereum/go-ethereum v1.9.5 => github.com/status-im/go-ethereum v1.9.5-status.7 @@ -167,7 +167,7 @@ github.com/ipfs/go-log/tracer/wire github.com/ipfs/go-log/writer # github.com/jackpal/gateway v1.0.5 github.com/jackpal/gateway -# github.com/jackpal/go-nat-pmp v1.0.1 +# github.com/jackpal/go-nat-pmp v1.0.2 github.com/jackpal/go-nat-pmp # github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 github.com/jbenet/go-temp-err-catcher @@ -343,7 +343,7 @@ github.com/prometheus/procfs/internal/util github.com/prometheus/tsdb/fileutil # github.com/rjeczalik/notify v0.9.2 github.com/rjeczalik/notify -# github.com/rs/cors v1.6.0 +# github.com/rs/cors v1.7.0 github.com/rs/cors # github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a github.com/russolsen/transit @@ -397,6 +397,8 @@ github.com/status-im/status-go/protocol/transport/whisper github.com/status-im/status-go/protocol/transport/whisper/migrations github.com/status-im/status-go/protocol/v1 github.com/status-im/status-go/protocol/zaputil +# github.com/status-im/status-go/waku v1.0.0 => ./waku +github.com/status-im/status-go/waku # github.com/status-im/status-go/whisper/v6 v6.0.1 => ./whisper github.com/status-im/status-go/whisper/v6 # github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501 @@ -487,7 +489,7 @@ go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit go.uber.org/zap/zapcore -# golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba +# golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c golang.org/x/crypto/blake2s golang.org/x/crypto/curve25519 golang.org/x/crypto/ed25519 diff --git a/waku/api.go b/waku/api.go index ef49fe1ce..73712bf7a 100644 --- a/waku/api.go +++ b/waku/api.go @@ -26,10 +26,9 @@ import ( "sync" "time" - "github.com/prometheus/common/log" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) diff --git a/waku/doc.go b/waku/doc.go index 03dfd8e5c..f31ccd76e 100644 --- a/waku/doc.go +++ b/waku/doc.go @@ -89,8 +89,8 @@ const ( // in order to bypass the expiry checks. type MailServer interface { Archive(env *Envelope) - DeliverMail(wakuPeer *Peer, request *Envelope) // DEPRECATED - Deliver(wakuPeer *Peer, request MessagesRequest) + DeliverMail(peerID []byte, request *Envelope) // DEPRECATED; use Deliver() + Deliver(peerID []byte, request MessagesRequest) } // MessagesRequest contains details of a request of historic messages. diff --git a/waku/message.go b/waku/message.go index 91848b4a6..b35953dea 100644 --- a/waku/message.go +++ b/waku/message.go @@ -29,11 +29,10 @@ import ( "strconv" "time" - "github.com/prometheus/common/log" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/ethereum/go-ethereum/log" ) // MessageParams specifies the exact way a message should be wrapped diff --git a/waku/waku.go b/waku/waku.go index 98ad566ed..fe68e660d 100644 --- a/waku/waku.go +++ b/waku/waku.go @@ -87,7 +87,7 @@ type Waku struct { settings settings // Holds configuration settings that can be dynamically changed settingsMu sync.RWMutex // Mutex to sync the settings access - mailServer MailServer // MailServer interface + mailServer MailServer rateLimiter *PeerRateLimiter @@ -480,11 +480,15 @@ func (w *Waku) expireRequestHistoricMessages(peer enode.ID, hash common.Hash, ti } } -func (w *Waku) SendHistoricMessageResponse(peer *Peer, payload []byte) error { +func (w *Waku) SendHistoricMessageResponse(peerID []byte, payload []byte) error { size, r, err := rlp.EncodeToReader(payload) if err != nil { return err } + peer, err := w.getPeer(peerID) + if err != nil { + return err + } return peer.ws.WriteMsg(p2p.Msg{Code: p2pRequestCompleteCode, Size: uint32(size), Payload: r}) } @@ -500,13 +504,21 @@ func (w *Waku) SendP2PMessages(peerID []byte, envelopes ...*Envelope) error { // SendP2PDirect sends a peer-to-peer message to a specific peer. // It sends one or more envelopes in a single batch. -func (w *Waku) SendP2PDirect(peer *Peer, envelopes ...*Envelope) error { +func (w *Waku) SendP2PDirect(peerID []byte, envelopes ...*Envelope) error { + peer, err := w.getPeer(peerID) + if err != nil { + return err + } return p2p.Send(peer.ws, p2pMessageCode, envelopes) } // SendRawP2PDirect sends a peer-to-peer message to a specific peer. // It sends one or more envelopes in a single batch. -func (w *Waku) SendRawP2PDirect(peer *Peer, envelopes ...rlp.RawValue) error { +func (w *Waku) SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error { + peer, err := w.getPeer(peerID) + if err != nil { + return err + } return p2p.Send(peer.ws, p2pMessageCode, envelopes) } @@ -1050,7 +1062,7 @@ func (w *Waku) handleP2PRequestCode(p *Peer, packet p2p.Msg, logger *zap.Logger) var requestDeprecated Envelope errDepReq := packet.Decode(&requestDeprecated) if errDepReq == nil { - w.mailServer.DeliverMail(p, &requestDeprecated) + w.mailServer.DeliverMail(p.ID(), &requestDeprecated) return nil } else { logger.Info("failed to decode p2p request message (deprecated)", zap.Binary("peer", peerID[:]), zap.Error(errDepReq)) @@ -1065,7 +1077,7 @@ func (w *Waku) handleP2PRequestCode(p *Peer, packet p2p.Msg, logger *zap.Logger) var request MessagesRequest errReq := packet.Decode(&request) if errReq == nil { - w.mailServer.Deliver(p, request) + w.mailServer.Deliver(p.ID(), request) return nil } else { logger.Info("failed to decode p2p request message", zap.Binary("peer", peerID[:]), zap.Error(errDepReq)) diff --git a/whisper/doc.go b/whisper/doc.go index 12d39ab0b..fdee9d708 100644 --- a/whisper/doc.go +++ b/whisper/doc.go @@ -105,10 +105,9 @@ const ( // in order to bypass the expiry checks. type MailServer interface { Archive(env *Envelope) - // DEPRECATED - DeliverMail(whisperPeer *Peer, request *Envelope) - Deliver(whisperPeer *Peer, request MessagesRequest) - SyncMail(*Peer, SyncMailRequest) error + DeliverMail(peerID []byte, req *Envelope) // DEPRECATED; user Deliver instead + Deliver(peerID []byte, req MessagesRequest) + SyncMail(peerID []byte, req SyncMailRequest) error } // MessagesRequest contains details of a request of historic messages. diff --git a/whisper/metrics.go b/whisper/metrics.go index 6ffa436fc..09b3af10f 100644 --- a/whisper/metrics.go +++ b/whisper/metrics.go @@ -6,37 +6,37 @@ import ( var ( envelopesReceivedCounter = prom.NewCounter(prom.CounterOpts{ - Name: "waku_envelopes_received_total", + Name: "whisper_envelopes_received_total", Help: "Number of envelopes received.", }) envelopesValidatedCounter = prom.NewCounter(prom.CounterOpts{ - Name: "waku_envelopes_validated_total", + Name: "whisper_envelopes_validated_total", Help: "Number of envelopes processed successfully.", }) envelopesRejectedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_rejected_total", + Name: "whisper_envelopes_rejected_total", Help: "Number of envelopes rejected.", }, []string{"reason"}) envelopesCacheFailedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_cache_failures_total", + Name: "whisper_envelopes_cache_failures_total", Help: "Number of envelopes which failed to be cached.", }, []string{"type"}) envelopesCachedCounter = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_envelopes_cached_total", + Name: "whisper_envelopes_cached_total", Help: "Number of envelopes cached.", }, []string{"cache"}) envelopesSizeMeter = prom.NewHistogram(prom.HistogramOpts{ - Name: "waku_envelopes_size_bytes", + Name: "whisper_envelopes_size_bytes", Help: "Size of processed Waku envelopes in bytes.", Buckets: prom.ExponentialBuckets(256, 4, 10), }) // rate limiter metrics rateLimitsProcessed = prom.NewCounter(prom.CounterOpts{ - Name: "waku_rate_limits_processed_total", + Name: "whisper_rate_limits_processed_total", Help: "Number of packets Waku rate limiter processed.", }) rateLimitsExceeded = prom.NewCounterVec(prom.CounterOpts{ - Name: "waku_rate_limits_exceeded_total", + Name: "whisper_rate_limits_exceeded_total", Help: "Number of times the Waku rate limits were exceeded", }, []string{"type"}) ) diff --git a/whisper/whisper.go b/whisper/whisper.go index cff9dcf54..693fede2d 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -104,7 +104,7 @@ type Whisper struct { statsMu sync.Mutex // guard stats stats Statistics // Statistics of whisper node - mailServer MailServer // MailServer interface + mailServer MailServer rateLimiter *PeerRateLimiter @@ -264,7 +264,7 @@ func (whisper *Whisper) GetCurrentTime() time.Time { // RegisterServer registers MailServer interface. // MailServer will process all the incoming messages with p2pRequestCode. -func (whisper *Whisper) RegisterServer(server MailServer) { +func (whisper *Whisper) RegisterMailServer(server MailServer) { whisper.mailServer = server } @@ -502,12 +502,15 @@ func (whisper *Whisper) expireRequestHistoricMessages(peer enode.ID, hash common } } -func (whisper *Whisper) SendHistoricMessageResponse(peer *Peer, payload []byte) error { +func (whisper *Whisper) SendHistoricMessageResponse(peerID []byte, payload []byte) error { size, r, err := rlp.EncodeToReader(payload) if err != nil { return err } - + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } return peer.ws.WriteMsg(p2p.Msg{Code: p2pRequestCompleteCode, Size: uint32(size), Payload: r}) } @@ -530,29 +533,37 @@ func (whisper *Whisper) SyncMessages(peerID []byte, req SyncMailRequest) error { } // SendSyncResponse sends a response to a Mail Server with a slice of envelopes. -func (whisper *Whisper) SendSyncResponse(p *Peer, data SyncResponse) error { - return p2p.Send(p.ws, p2pSyncResponseCode, data) +func (whisper *Whisper) SendSyncResponse(peerID []byte, data SyncResponse) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pSyncResponseCode, data) } // SendRawSyncResponse sends a response to a Mail Server with a slice of envelopes. -func (whisper *Whisper) SendRawSyncResponse(p *Peer, data RawSyncResponse) error { - return p2p.Send(p.ws, p2pSyncResponseCode, data) +func (whisper *Whisper) SendRawSyncResponse(peerID []byte, data RawSyncResponse) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } + return p2p.Send(peer.ws, p2pSyncResponseCode, data) } // SendP2PMessage sends a peer-to-peer message to a specific peer. func (whisper *Whisper) SendP2PMessage(peerID []byte, envelopes ...*Envelope) error { - p, err := whisper.getPeer(peerID) - if err != nil { - return err - } - return whisper.SendP2PDirect(p, envelopes...) + return whisper.SendP2PDirect(peerID, envelopes...) } // SendP2PDirect sends a peer-to-peer message to a specific peer. // If only a single envelope is given, data is sent as a single object // rather than a slice. This is important to keep this method backward compatible // as it used to send only single envelopes. -func (whisper *Whisper) SendP2PDirect(peer *Peer, envelopes ...*Envelope) error { +func (whisper *Whisper) SendP2PDirect(peerID []byte, envelopes ...*Envelope) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } if len(envelopes) == 1 { return p2p.Send(peer.ws, p2pMessageCode, envelopes[0]) } @@ -563,7 +574,11 @@ func (whisper *Whisper) SendP2PDirect(peer *Peer, envelopes ...*Envelope) error // If only a single envelope is given, data is sent as a single object // rather than a slice. This is important to keep this method backward compatible // as it used to send only single envelopes. -func (whisper *Whisper) SendRawP2PDirect(peer *Peer, envelopes ...rlp.RawValue) error { +func (whisper *Whisper) SendRawP2PDirect(peerID []byte, envelopes ...rlp.RawValue) error { + peer, err := whisper.getPeer(peerID) + if err != nil { + return err + } if len(envelopes) == 1 { return p2p.Send(peer.ws, p2pMessageCode, envelopes[0]) } @@ -1099,13 +1114,13 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { return fmt.Errorf("sync mail request was invalid: %v", err) } - if err := whisper.mailServer.SyncMail(p, request); err != nil { + if err := whisper.mailServer.SyncMail(p.ID(), request); err != nil { log.Error( "failed to sync envelopes", "peer", p.peer.ID().String(), ) _ = whisper.SendSyncResponse( - p, + p.ID(), SyncResponse{Error: err.Error()}, ) return err @@ -1157,7 +1172,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { var requestDeprecated Envelope errDepReq := packet.Decode(&requestDeprecated) if errDepReq == nil { - whisper.mailServer.DeliverMail(p, &requestDeprecated) + whisper.mailServer.DeliverMail(p.ID(), &requestDeprecated) continue } else { log.Info("failed to decode p2p request message (deprecated)", "peer", p.peer.ID(), "err", errDepReq) @@ -1172,7 +1187,7 @@ func (whisper *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { var request MessagesRequest errReq := packet.Decode(&request) if errReq == nil { - whisper.mailServer.Deliver(p, request) + whisper.mailServer.Deliver(p.ID(), request) continue } else { log.Info("failed to decode p2p request message", "peer", p.peer.ID(), "err", errReq)