package state import ( "context" "encoding/binary" "testing" "github.com/ledgerwatch/log/v3" "github.com/stretchr/testify/require" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/mdbx" ) func testDbAndAggregator(t *testing.T, prefixLen int, aggStep uint64) (string, kv.RwDB, *Aggregator) { t.Helper() path := t.TempDir() logger := log.New() db := mdbx.NewMDBX(logger).Path(path).WithTableCfg(func(defaultBuckets kv.TableCfg) kv.TableCfg { return kv.ChaindataTablesCfg }).MustOpen() agg, err := NewAggregator(path, aggStep) require.NoError(t, err) return path, db, agg } func TestAggregator_Merge(t *testing.T) { _, db, agg := testDbAndAggregator(t, 0, 100) defer db.Close() defer agg.Close() tx, err := db.BeginRw(context.Background()) require.NoError(t, err) defer func() { if tx != nil { tx.Rollback() } }() agg.SetTx(tx) txs := uint64(10000) // keys are encodings of numbers 1..31 // each key changes value on every txNum which is multiple of the key var maxWrite, otherMaxWrite uint64 for txNum := uint64(1); txNum <= txs; txNum++ { agg.SetTxNum(txNum) var v [8]byte binary.BigEndian.PutUint64(v[:], txNum) var err error if txNum%135 == 0 { err = agg.UpdateCommitmentData([]byte("otherroothash"), v[:]) otherMaxWrite = txNum } else { err = agg.UpdateCommitmentData([]byte("roothash"), v[:]) maxWrite = txNum } require.NoError(t, err) require.NoError(t, agg.FinishTx()) if txNum%100 == 0 { err = tx.Commit() require.NoError(t, err) tx, err = db.BeginRw(context.Background()) require.NoError(t, err) agg.SetTx(tx) } } err = tx.Commit() require.NoError(t, err) tx = nil // Check the history roTx, err := db.BeginRo(context.Background()) require.NoError(t, err) defer roTx.Rollback() dc := agg.MakeContext() v, err := dc.ReadCommitment([]byte("roothash"), roTx) require.NoError(t, err) require.EqualValues(t, maxWrite, binary.BigEndian.Uint64(v[:])) v, err = dc.ReadCommitment([]byte("otherroothash"), roTx) require.NoError(t, err) require.EqualValues(t, otherMaxWrite, binary.BigEndian.Uint64(v[:])) } func TestAggregator_RestartOnFiles(t *testing.T) { aggStep := uint64(100) path, db, agg := testDbAndAggregator(t, 0, aggStep) defer db.Close() tx, err := db.BeginRw(context.Background()) require.NoError(t, err) defer func() { if tx != nil { tx.Rollback() } if agg != nil { agg.Close() } }() agg.SetTx(tx) comit := func(txn uint64) error { err = tx.Commit() require.NoError(t, err) tx, err = db.BeginRw(context.Background()) require.NoError(t, err) agg.SetTx(tx) return nil } agg.SetCommitFn(comit) txs := uint64(1026) // keys are encodings of numbers 1..31 // each key changes value on every txNum which is multiple of the key var maxWrite, otherMaxWrite uint64 for txNum := uint64(1); txNum <= txs; txNum++ { agg.SetTxNum(txNum) var v [8]byte binary.BigEndian.PutUint64(v[:], txNum) var err error if txNum%135 == 0 { err = agg.UpdateCommitmentData([]byte("otherroothash"), v[:]) otherMaxWrite = txNum } else { err = agg.UpdateCommitmentData([]byte("roothash"), v[:]) maxWrite = txNum } agg.ComputeCommitment(true, false) require.NoError(t, err) require.NoError(t, agg.FinishTx()) if txNum+1%100 == 0 { comit(txNum) } } err = tx.Commit() require.NoError(t, err) tx = nil agg.Close() agg = nil anotherAgg, err := NewAggregator(path, aggStep) require.NoError(t, err) defer anotherAgg.Close() rwTx, err := db.BeginRw(context.Background()) require.NoError(t, err) defer func() { if rwTx != nil { rwTx.Rollback() } }() anotherAgg.SetTx(rwTx) startTx := anotherAgg.EndTxNumMinimax() sstartTx, err := anotherAgg.SeekCommitment(startTx) require.NoError(t, err) _ = sstartTx rwTx.Rollback() rwTx = nil // Check the history roTx, err := db.BeginRo(context.Background()) require.NoError(t, err) defer roTx.Rollback() dc := anotherAgg.MakeContext() v, err := dc.ReadCommitment([]byte("roothash"), roTx) require.NoError(t, err) require.EqualValues(t, maxWrite, binary.BigEndian.Uint64(v[:])) v, err = dc.ReadCommitment([]byte("otherroothash"), roTx) require.NoError(t, err) require.EqualValues(t, otherMaxWrite, binary.BigEndian.Uint64(v[:])) }