aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Ballet <gballet@gmail.com>2019-03-26 17:23:59 +0800
committerFelix Lange <fjl@users.noreply.github.com>2019-03-26 17:23:59 +0800
commitdf717abc999add34c5725ab86dce1fcee968ca10 (patch)
treed2cfa23532526f66f3f4c148756e7eef866ecdf3
parentb8b4fb004c89d0d59276216ca73583f3ef608bba (diff)
downloadgo-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar.gz
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar.bz2
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar.lz
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar.xz
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.tar.zst
go-tangerine-df717abc999add34c5725ab86dce1fcee968ca10.zip
whisper/whisperv6: fix PoW calculations to match the spec (#19330)
This PR fixes two issues in the PoW calculation of a Whisper envelope, compared to the spec (see PoW Requirements): - The pow is supposed to take the leading number of zeroes (i.e. most significant zeroes) and what it did was to take the number of trailing zeroes (i.e. least significant zeroes). It has been fixed to match what the spec and Parity does. - The spec expects to use the size of the RLP encoded envelope, and it took something else, as described in #18070.
-rw-r--r--whisper/whisperv6/envelope.go24
-rw-r--r--whisper/whisperv6/envelope_test.go27
2 files changed, 39 insertions, 12 deletions
diff --git a/whisper/whisperv6/envelope.go b/whisper/whisperv6/envelope.go
index c42d1fa8a..5d9d35081 100644
--- a/whisper/whisperv6/envelope.go
+++ b/whisper/whisperv6/envelope.go
@@ -27,7 +27,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/rlp"
@@ -82,7 +81,7 @@ func (e *Envelope) Seal(options *MessageParams) error {
return nil
}
- var target, bestBit int
+ 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
@@ -101,10 +100,10 @@ func (e *Envelope) Seal(options *MessageParams) error {
for i := 0; i < 1024; i++ {
binary.BigEndian.PutUint64(buf[56:], nonce)
d := new(big.Int).SetBytes(crypto.Keccak256(buf))
- firstBit := math.FirstBitSet(d)
- if firstBit > bestBit {
- e.Nonce, bestBit = nonce, firstBit
- if target > 0 && bestBit >= target {
+ leadingZeros := 256 - d.BitLen()
+ if leadingZeros > bestLeadingZeros {
+ e.Nonce, bestLeadingZeros = nonce, leadingZeros
+ if target > 0 && bestLeadingZeros >= target {
return nil
}
}
@@ -112,7 +111,7 @@ func (e *Envelope) Seal(options *MessageParams) error {
}
}
- if target > 0 && bestBit < target {
+ if target > 0 && bestLeadingZeros < target {
return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime)
}
@@ -130,13 +129,14 @@ func (e *Envelope) PoW() float64 {
func (e *Envelope) calculatePoW(diff uint32) {
buf := make([]byte, 64)
- h := crypto.Keccak256(e.rlpWithoutNonce())
+ rlp := e.rlpWithoutNonce()
+ h := crypto.Keccak256(rlp)
copy(buf[:32], h)
binary.BigEndian.PutUint64(buf[56:], e.Nonce)
- d := new(big.Int).SetBytes(crypto.Keccak256(buf))
- firstBit := math.FirstBitSet(d)
- x := gmath.Pow(2, float64(firstBit))
- x /= float64(e.size())
+ powHash := new(big.Int).SetBytes(crypto.Keccak256(buf))
+ leadingZeroes := 256 - powHash.BitLen()
+ x := gmath.Pow(2, float64(leadingZeroes))
+ x /= float64(len(rlp))
x /= float64(e.TTL + diff)
e.pow = x
}
diff --git a/whisper/whisperv6/envelope_test.go b/whisper/whisperv6/envelope_test.go
index 410b250a3..d6e38e683 100644
--- a/whisper/whisperv6/envelope_test.go
+++ b/whisper/whisperv6/envelope_test.go
@@ -25,6 +25,33 @@ import (
"github.com/ethereum/go-ethereum/crypto"
)
+func TestPoWCalculationsWithNoLeadingZeros(t *testing.T) {
+ e := Envelope{
+ TTL: 1,
+ Data: []byte{0xde, 0xad, 0xbe, 0xef},
+ Nonce: 100000,
+ }
+
+ e.calculatePoW(0)
+
+ if e.pow != 0.07692307692307693 {
+ t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow)
+ }
+}
+
+func TestPoWCalculationsWith8LeadingZeros(t *testing.T) {
+ e := Envelope{
+ TTL: 1,
+ Data: []byte{0xde, 0xad, 0xbe, 0xef},
+ Nonce: 48159,
+ }
+ e.calculatePoW(0)
+
+ if e.pow != 40329.846153846156 {
+ t.Fatalf("invalid PoW calculation. Expected 0.07692307692307693, got %v", e.pow)
+ }
+}
+
func TestEnvelopeOpenAcceptsOnlyOneKeyTypeInFilter(t *testing.T) {
symKey := make([]byte, aesKeyLength)
mrand.Read(symKey)