help fuzzer

This commit is contained in:
alex.sharov 2021-08-05 18:38:37 +07:00
parent aef904971c
commit 730cd96e9b

View File

@ -4,7 +4,9 @@
package txpool package txpool
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt"
"testing" "testing"
"github.com/google/btree" "github.com/google/btree"
@ -83,7 +85,7 @@ func FuzzTwoQueue(f *testing.F) {
} }
func u64Slice(in []byte) ([]uint64, bool) { func u64Slice(in []byte) ([]uint64, bool) {
if len(in)%8 != 0 { if len(in) < 8 {
return nil, false return nil, false
} }
res := make([]uint64, len(in)/8) res := make([]uint64, len(in)/8)
@ -93,7 +95,7 @@ func u64Slice(in []byte) ([]uint64, bool) {
return res, true return res, true
} }
func u256Slice(in []byte) ([]uint256.Int, bool) { func u256Slice(in []byte) ([]uint256.Int, bool) {
if len(in)%32 != 0 { if len(in) < 32 {
return nil, false return nil, false
} }
res := make([]uint256.Int, len(in)/32) res := make([]uint256.Int, len(in)/32)
@ -103,32 +105,26 @@ func u256Slice(in []byte) ([]uint256.Int, bool) {
return res, true return res, true
} }
func poolsFromFuzzBytes(rawTxNonce, rawValues, rawTips, rawSender, rawSenderNonce, rawSenderBalance []byte) (sendersInfo map[uint64]*senderInfo, senderIDs map[string]uint64, txs TxSlots, ok bool) { func parseSenders(rawSenders []byte) (senders Addresses, nonces []uint64, balances []uint256.Int) {
if len(rawTxNonce) < 8 || len(rawValues) < 32 || len(rawTips) < 8 || len(rawSender) < 20 || len(rawSenderNonce) < 8 || len(rawSenderBalance) < 32 { for i := 0; i < len(rawSenders)-(20+8+32-1); i += 20 + 8 + 32 {
return nil, nil, txs, false senders = append(senders, rawSenders[i:i+20]...)
} nonce := binary.BigEndian.Uint64(rawSenders[i+20:])
if len(rawTxNonce) != len(rawTips) { if nonce == 0 {
return nil, nil, txs, false nonce = 1
}
if len(rawTxNonce)*32/8 != len(rawValues) {
return nil, nil, txs, false
}
if len(rawSenderNonce)*20/8 != len(rawSender) {
return nil, nil, txs, false
}
if len(rawSenderNonce)*32/8 != len(rawSenderBalance) {
return nil, nil, txs, false
}
senderNonce, ok := u64Slice(rawSenderNonce)
if !ok {
return nil, nil, txs, false
}
for i := 0; i < len(senderNonce); i++ {
if senderNonce[i] == 0 {
return nil, nil, txs, false
} }
nonces = append(nonces, nonce)
balance := uint256.NewInt(0)
balance.SetBytes(rawSenders[i+20+8 : i+20+8+32])
balances = append(balances, *balance)
} }
return
}
func poolsFromFuzzBytes(rawTxNonce, rawValues, rawTips, rawSender []byte) (sendersInfo map[uint64]*senderInfo, senderIDs map[string]uint64, txs TxSlots, ok bool) {
if len(rawTxNonce) < 8 || len(rawValues) < 32 || len(rawTips) < 8 || len(rawSender) < 20+8+32 {
return nil, nil, txs, false
}
senders, senderNonce, senderBalance := parseSenders(rawSender)
txNonce, ok := u64Slice(rawTxNonce) txNonce, ok := u64Slice(rawTxNonce)
if !ok { if !ok {
return nil, nil, txs, false return nil, nil, txs, false
@ -141,27 +137,21 @@ func poolsFromFuzzBytes(rawTxNonce, rawValues, rawTips, rawSender, rawSenderNonc
if !ok { if !ok {
return nil, nil, txs, false return nil, nil, txs, false
} }
senderBalance, ok := u256Slice(rawSenderBalance)
if !ok {
return nil, nil, txs, false
}
sendersInfo = map[uint64]*senderInfo{} sendersInfo = map[uint64]*senderInfo{}
senderIDs = map[string]uint64{} senderIDs = map[string]uint64{}
for i := 0; i < len(senderNonce); i++ { for i := 0; i < len(senderNonce); i++ {
senderID := uint64(i + 1) //non-zero expected senderID := uint64(i + 1) //non-zero expected
sendersInfo[senderID] = newSenderInfo(senderNonce[i], senderBalance[i]) sendersInfo[senderID] = newSenderInfo(senderNonce[i], senderBalance[i%len(senderBalance)])
senderIDs[string(rawSender[i*20:(i+1)*20])] = senderID senderIDs[string(senders.At(i%senders.Len()))] = senderID
} }
sendersAmount := len(sendersInfo)
for i := range txNonce { for i := range txNonce {
txs.txs = append(txs.txs, &TxSlot{ txs.txs = append(txs.txs, &TxSlot{
nonce: txNonce[i], nonce: txNonce[i],
value: values[i], value: values[i%len(values)],
tip: tips[i], tip: tips[i%len(tips)],
}) })
senderN := i % sendersAmount txs.senders = append(txs.senders, senders.At(i%senders.Len())...)
txs.senders = append(txs.senders, rawSender[senderN*20:(senderN+1)*20]...)
txs.isLocal = append(txs.isLocal, false) txs.isLocal = append(txs.isLocal, false)
} }
@ -197,25 +187,26 @@ func splitDataset(in TxSlots) (TxSlots, TxSlots, TxSlots, TxSlots) {
return p1, p2, p3, p4 return p1, p2, p3, p4
} }
func FuzzOnNewBlocks6(f *testing.F) { func FuzzOnNewBlocks7(f *testing.F) {
var u64 = [8 * 4]byte{1} var u64 = [8 * 4]byte{1}
var u256 = [32 * 4]byte{1} var sender = [20 + 8 + 32]byte{1}
f.Add(u64[:], u64[:], u64[:], u64[:], u256[:], u256[:], 123, 456) f.Add(u64[:], u64[:], u64[:], sender[:], 123, 456)
f.Add(u64[:], u64[:], u64[:], u64[:], u256[:], u256[:], 78, 100) f.Add(u64[:], u64[:], u64[:], sender[:], 78, 100)
f.Add(u64[:], u64[:], u64[:], u64[:], u256[:], u256[:], 100_000, 101_000) f.Add(u64[:], u64[:], u64[:], sender[:], 100_000, 101_000)
f.Fuzz(func(t *testing.T, txNonce, values, tips, sender, senderNonce, senderBalance []byte, protocolBaseFee, blockBaseFee uint64) { f.Fuzz(func(t *testing.T, txNonce, values, tips, sender []byte, protocolBaseFee, blockBaseFee uint64) {
t.Parallel() t.Parallel()
if protocolBaseFee == 0 || blockBaseFee == 0 { if protocolBaseFee == 0 || blockBaseFee == 0 {
t.Skip() t.Skip()
} }
if len(txNonce)%(8*4) != 0 || len(txNonce) != len(tips) { if len(sender) < 20+8+32 {
t.Skip() t.Skip()
} }
senders, senderIDs, txs, ok := poolsFromFuzzBytes(txNonce, values, tips, sender, senderNonce, senderBalance) senders, senderIDs, txs, ok := poolsFromFuzzBytes(txNonce, values, tips, sender)
if !ok { if !ok {
t.Skip() t.Skip()
} }
assert := assert.New(t) assert := assert.New(t)
err := txs.Valid() err := txs.Valid()
assert.NoError(err) assert.NoError(err)
@ -226,6 +217,9 @@ func FuzzOnNewBlocks6(f *testing.F) {
pool.senderIDs = senderIDs pool.senderIDs = senderIDs
check := func(unwindTxs, minedTxs TxSlots) { check := func(unwindTxs, minedTxs TxSlots) {
pending, baseFee, queued := pool.pending, pool.baseFee, pool.queued pending, baseFee, queued := pool.pending, pool.baseFee, pool.queued
if pending.Len() > 0 || baseFee.Len() > 0 || queued.Len() > 0 {
fmt.Printf("len: %d,%d,%d\n", pending.Len(), baseFee.Len(), queued.Len())
}
best, worst := pending.Best(), pending.Worst() best, worst := pending.Best(), pending.Worst()
assert.LessOrEqual(pending.Len(), PendingSubPoolLimit) assert.LessOrEqual(pending.Len(), PendingSubPoolLimit)
@ -333,39 +327,54 @@ func FuzzOnNewBlocks6(f *testing.F) {
} }
} }
checkNotify := func(unwindTxs, minedTxs TxSlots) {
select {
case newHashes := <-ch:
//assert.Equal(len(unwindTxs.txs), newHashes.Len())
assert.Greater(len(newHashes), 0)
for i := 0; i < newHashes.Len(); i++ {
foundInUnwind := false
foundInMined := false
newHash := newHashes.At(i)
for j := range unwindTxs.txs {
if bytes.Equal(unwindTxs.txs[j].idHash[:], newHash) {
foundInUnwind = true
break
}
}
for j := range minedTxs.txs {
if bytes.Equal(unwindTxs.txs[j].idHash[:], newHash) {
foundInMined = true
break
}
}
assert.True(foundInUnwind)
assert.False(foundInMined)
}
default:
//TODO: no notifications - means pools must be empty (unchanged)
}
}
// go to first fork // go to first fork
unwindTxs, minedTxs1, p2pReceived, minedTxs2 := splitDataset(txs) unwindTxs, minedTxs1, p2pReceived, minedTxs2 := splitDataset(txs)
err = pool.OnNewBlock(unwindTxs, minedTxs1, protocolBaseFee, blockBaseFee) err = pool.OnNewBlock(unwindTxs, minedTxs1, protocolBaseFee, blockBaseFee)
assert.NoError(err) assert.NoError(err)
check(unwindTxs, minedTxs1) check(unwindTxs, minedTxs1)
select { checkNotify(unwindTxs, minedTxs1)
case newHashes := <-ch:
assert.Greater(len(newHashes), 0)
//TODO: all notified hashes must be in given list
default:
//TODO: no notifications - means pools must be empty (unchanged)
}
//assert.Equal(len(unwindTxs.txs), newHashes.Len())
// unwind everything and switch to new fork (need unwind mined now) // unwind everything and switch to new fork (need unwind mined now)
err = pool.OnNewBlock(minedTxs1, minedTxs2, protocolBaseFee, blockBaseFee) err = pool.OnNewBlock(minedTxs1, minedTxs2, protocolBaseFee, blockBaseFee)
assert.NoError(err) assert.NoError(err)
check(minedTxs1, minedTxs2) check(minedTxs1, minedTxs2)
select { checkNotify(minedTxs1, minedTxs2)
case newHashes := <-ch:
assert.Greater(len(newHashes), 0)
default:
}
// add some remote txs from p2p // add some remote txs from p2p
err = pool.OnNewTxs(p2pReceived) err = pool.OnNewTxs(p2pReceived)
assert.NoError(err) assert.NoError(err)
check(TxSlots{}, p2pReceived) check(p2pReceived, TxSlots{})
select { checkNotify(p2pReceived, TxSlots{})
case newHashes := <-ch:
assert.Greater(len(newHashes), 0)
default:
}
}) })
} }