Skip to content

Commit

Permalink
blobpool: add test for changing shelf size
Browse files Browse the repository at this point in the history
  • Loading branch information
lightclient committed Jan 10, 2025
1 parent aee56ab commit 23ba4bf
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 22 deletions.
138 changes: 136 additions & 2 deletions core/txpool/blobpool/blobpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ var (
const testMaxBlobsPerBlock = 6

func init() {
for i := 0; i < 10; i++ {
for i := 0; i < 24; i++ {
testBlob := &kzg4844.Blob{byte(i)}
testBlobs = append(testBlobs, testBlob)

Expand Down Expand Up @@ -196,10 +196,43 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
}

// makeMultiBlobTx is a utility method to construct a ramdom blob tx with
// certain number of blobs in its sidecar.
func makeMultiBlobTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64, blobCount int, key *ecdsa.PrivateKey) *types.Transaction {
var (
blobs []kzg4844.Blob
blobHashes []common.Hash
commitments []kzg4844.Commitment
proofs []kzg4844.Proof
)
for i := 0; i < blobCount; i++ {
blobs = append(blobs, *testBlobs[i])
commitments = append(commitments, testBlobCommits[i])
proofs = append(proofs, testBlobProofs[i])
blobHashes = append(blobHashes, testBlobVHashes[i])
}
blobtx := &types.BlobTx{
ChainID: uint256.MustFromBig(params.MainnetChainConfig.ChainID),
Nonce: nonce,
GasTipCap: uint256.NewInt(gasTipCap),
GasFeeCap: uint256.NewInt(gasFeeCap),
Gas: 21000,
BlobFeeCap: uint256.NewInt(blobFeeCap),
BlobHashes: blobHashes,
Value: uint256.NewInt(100),
Sidecar: &types.BlobTxSidecar{
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
},
}
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
}

// makeUnsignedTx is a utility method to construct a random blob transaction
// without signing it.
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rand.Intn(len(testBlobs)))
return makeUnsignedTxWithTestBlob(nonce, gasTipCap, gasFeeCap, blobFeeCap, rnd.Intn(len(testBlobs)))
}

// makeUnsignedTx is a utility method to construct a random blob transaction
Expand Down Expand Up @@ -994,6 +1027,107 @@ func TestOpenCap(t *testing.T) {
}
}

// TestChangingSlotterSize attempts to mimic a scenario where the max blob count
// of the pool is increased. This would happen during a client release where a
// new fork is added with a max blob count higher than the previous fork. We
// want to make sure transactions a persisted between those runs.
func TestChangingSlotterSize(t *testing.T) {
//log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))

// Create a temporary folder for the persistent backend
storage, _ := os.MkdirTemp("", "blobpool-")
defer os.RemoveAll(storage)

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(6), nil)

// Create transactions from a few accounts.
var (
key1, _ = crypto.GenerateKey()
key2, _ = crypto.GenerateKey()
key3, _ = crypto.GenerateKey()

addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey)

tx1 = makeMultiBlobTx(0, 1, 1000, 100, 6, key1)
tx2 = makeMultiBlobTx(0, 1, 800, 70, 6, key2)
tx3 = makeMultiBlobTx(0, 1, 800, 110, 24, key3)

blob1, _ = rlp.EncodeToBytes(tx1)
blob2, _ = rlp.EncodeToBytes(tx2)
)

// Write the two safely sized txs to store. note: although the store is
// configured for a blob count of 6, it can also support around ~1mb of call
// data - all this to say that we aren't using the the absolute largest shelf
// available.
store.Put(blob1)
store.Put(blob2)
store.Close()

// Mimic a blobpool with max blob count of 6 upgrading to a max blob count of 24.
for _, maxBlobs := range []uint64{6, 24} {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)

// Make custom chain config where the max blob count changes based on the loop variable.
cancunTime := uint64(0)
config := &params.ChainConfig{
ChainID: big.NewInt(1),
LondonBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
CancunTime: &cancunTime,
BlobScheduleConfig: &params.BlobScheduleConfig{
Cancun: &params.BlobConfig{
Target: maxBlobs / 2,
Max: maxBlobs,
},
},
}
chain := &testBlockChain{
config: config,
basefee: uint256.NewInt(1050),
blobfee: uint256.NewInt(105),
statedb: statedb,
}
pool := New(Config{Datadir: storage}, chain)
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
t.Fatalf("failed to create blob pool: %v", err)
}

// Try to add the big blob tx. In the initial iteration it should overflow
// the pool. On the subsequent iteration it should be accepted.
errs := pool.Add([]*types.Transaction{tx3}, false, true)
if _, ok := pool.index[addr3]; ok && maxBlobs == 6 {
t.Errorf("expected insert of oversized blob tx to fail: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
} else if !ok && maxBlobs == 10 {
t.Errorf("expected insert of oversized blob tx to succeed: blobs=24, maxBlobs=%d, err=%v", maxBlobs, errs[0])
}

// Verify the regular two txs are always available.
if got := pool.Get(tx1.Hash()); got == nil {
t.Errorf("expected tx %s from %s in pool", tx1.Hash(), addr1)
}
if got := pool.Get(tx2.Hash()); got == nil {
t.Errorf("expected tx %s from %s in pool", tx2.Hash(), addr2)
}

// Verify all the calculated pool internals. Interestingly, this is **not**
// a duplication of the above checks, this actually validates the verifier
// using the above already hard coded checks.
//
// Do not remove this, nor alter the above to be generic.
verifyPoolInternals(t, pool)

pool.Close()
}
}

// Tests that adding transaction will correctly store it in the persistent store
// and update all the indices.
//
Expand Down
34 changes: 17 additions & 17 deletions core/txpool/blobpool/evictheap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/holiman/uint256"
)

var rand = mrand.New(mrand.NewSource(1))
var rnd = mrand.New(mrand.NewSource(1))

// verifyHeapInternals verifies that all accounts present in the index are also
// present in the heap and internals are consistent across various indices.
Expand Down Expand Up @@ -193,12 +193,12 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) {
index := make(map[common.Address][]*blobTxMeta)
for i := 0; i < int(blobs); i++ {
var addr common.Address
rand.Read(addr[:])
rnd.Read(addr[:])

var (
execTip = uint256.NewInt(rand.Uint64())
execFee = uint256.NewInt(rand.Uint64())
blobFee = uint256.NewInt(rand.Uint64())
execTip = uint256.NewInt(rnd.Uint64())
execFee = uint256.NewInt(rnd.Uint64())
blobFee = uint256.NewInt(rnd.Uint64())

basefeeJumps = dynamicFeeJumps(execFee)
blobfeeJumps = dynamicFeeJumps(blobFee)
Expand All @@ -218,13 +218,13 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) {
}}
}
// Create a price heap and reinit it over and over
heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
heap := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index)

basefees := make([]*uint256.Int, b.N)
blobfees := make([]*uint256.Int, b.N)
for i := 0; i < b.N; i++ {
basefees[i] = uint256.NewInt(rand.Uint64())
blobfees[i] = uint256.NewInt(rand.Uint64())
basefees[i] = uint256.NewInt(rnd.Uint64())
blobfees[i] = uint256.NewInt(rnd.Uint64())
}
b.ResetTimer()
b.ReportAllocs()
Expand Down Expand Up @@ -269,12 +269,12 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
index := make(map[common.Address][]*blobTxMeta)
for i := 0; i < int(blobs); i++ {
var addr common.Address
rand.Read(addr[:])
rnd.Read(addr[:])

var (
execTip = uint256.NewInt(rand.Uint64())
execFee = uint256.NewInt(rand.Uint64())
blobFee = uint256.NewInt(rand.Uint64())
execTip = uint256.NewInt(rnd.Uint64())
execFee = uint256.NewInt(rnd.Uint64())
blobFee = uint256.NewInt(rnd.Uint64())

basefeeJumps = dynamicFeeJumps(execFee)
blobfeeJumps = dynamicFeeJumps(blobFee)
Expand All @@ -294,18 +294,18 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
}}
}
// Create a price heap and overflow it over and over
evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
evict := newPriceHeap(uint256.NewInt(rnd.Uint64()), uint256.NewInt(rnd.Uint64()), index)
var (
addrs = make([]common.Address, b.N)
metas = make([]*blobTxMeta, b.N)
)
for i := 0; i < b.N; i++ {
rand.Read(addrs[i][:])
rnd.Read(addrs[i][:])

var (
execTip = uint256.NewInt(rand.Uint64())
execFee = uint256.NewInt(rand.Uint64())
blobFee = uint256.NewInt(rand.Uint64())
execTip = uint256.NewInt(rnd.Uint64())
execFee = uint256.NewInt(rnd.Uint64())
blobFee = uint256.NewInt(rnd.Uint64())

basefeeJumps = dynamicFeeJumps(execFee)
blobfeeJumps = dynamicFeeJumps(blobFee)
Expand Down
6 changes: 3 additions & 3 deletions core/txpool/blobpool/priority_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestPriorityCalculation(t *testing.T) {
func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
fees := make([]*uint256.Int, b.N)
for i := 0; i < b.N; i++ {
fees[i] = uint256.NewInt(rand.Uint64())
fees[i] = uint256.NewInt(rnd.Uint64())
}
b.ResetTimer()
b.ReportAllocs()
Expand All @@ -76,8 +76,8 @@ func BenchmarkPriorityCalculation(b *testing.B) {
txBasefeeJumps := make([]float64, b.N)
txBlobfeeJumps := make([]float64, b.N)
for i := 0; i < b.N; i++ {
txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64()))
txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rand.Uint64()))
txBasefeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64()))
txBlobfeeJumps[i] = dynamicFeeJumps(uint256.NewInt(rnd.Uint64()))
}
b.ResetTimer()
b.ReportAllocs()
Expand Down

0 comments on commit 23ba4bf

Please sign in to comment.