Skip to content
This repository was archived by the owner on Feb 20, 2025. It is now read-only.

Commit dc281f3

Browse files
authored
Merge pull request #390 from Fantom-foundation/feature/fuzzing
Add fuzzing for aida-stochastic
2 parents daa2932 + 7b7d4bc commit dc281f3

File tree

2 files changed

+157
-20
lines changed

2 files changed

+157
-20
lines changed

stochastic/fuzzing_test.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package stochastic
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
"log"
7+
"math/rand"
8+
"os"
9+
"testing"
10+
11+
"github.com/Fantom-foundation/Aida/utils"
12+
)
13+
14+
// fuzzSource is a random generator source from a fuzzing source.
15+
type fuzzSource struct {
16+
buf *bytes.Reader // read buffer for fuzz string
17+
}
18+
19+
// newFuzzSource creates a new fuzzing source for random number generation.
20+
func newFuzzSource(str []byte) *fuzzSource {
21+
return &fuzzSource{buf: bytes.NewReader(str)}
22+
}
23+
24+
// Int63() retrieves next random number from the fuzzing string.
25+
// If the fuzzing string is depleted, Int63() returns zero.
26+
func (s *fuzzSource) Int63() int64 {
27+
var result int64
28+
if s.buf.Len() >= 8 {
29+
if err := binary.Read(s.buf, binary.LittleEndian, &result); err != nil {
30+
panic("Reading from fuzzing string failed.")
31+
}
32+
if result < 0 {
33+
result = -result
34+
}
35+
}
36+
return result
37+
}
38+
39+
// Seed is not used for the fuzzing string
40+
func (s *fuzzSource) Seed(_ int64) {
41+
}
42+
43+
// End returns true iff the end of fuzz string is reached.
44+
func (s *fuzzSource) End() bool {
45+
return s.buf.Len() < 8
46+
}
47+
48+
// FuzzStochastic produces a seed corpus of random strings of various sizes
49+
func FuzzStochastic(f *testing.F) {
50+
51+
// create corpus
52+
testcases := []int{8 * 512, 8 * 1024}
53+
rand.Seed(1)
54+
for _, n := range testcases {
55+
randomStr := make([]byte, n)
56+
if _, err := rand.Read(randomStr); err != nil {
57+
log.Fatalf("error producing a random byte slice. Error: %v", err)
58+
}
59+
f.Add(randomStr)
60+
}
61+
62+
f.Fuzz(func(f *testing.T, fuzzingStr []byte) {
63+
64+
// generate configuration
65+
cfg := utils.Config{
66+
ContractNumber: 1000,
67+
KeysNumber: 1000,
68+
ValuesNumber: 1000,
69+
SnapshotDepth: 100,
70+
BlockLength: 3,
71+
SyncPeriodLength: 10,
72+
OperationFrequency: 2,
73+
74+
ShadowImpl: "geth",
75+
StateDbTempDir: "/tmp/",
76+
DbImpl: "carmen",
77+
DbVariant: "go-file",
78+
}
79+
80+
// create a directory for the store to place all its files, and
81+
// instantiate the state DB under testing.
82+
db, stateDirectory, _, err := utils.PrepareStateDB(&cfg)
83+
if err != nil {
84+
f.Errorf("failed opening StateDB. Error: %v", err)
85+
}
86+
defer os.RemoveAll(stateDirectory)
87+
88+
// generate uniform events
89+
events := GenerateUniformRegistry(&cfg).NewEventRegistryJSON()
90+
91+
// generate uniform matrix
92+
e := NewEstimationModelJSON(&events)
93+
94+
// construct random generator from fuzzing string
95+
fSrc := newFuzzSource(fuzzingStr)
96+
rg := rand.New(fSrc)
97+
98+
// create a stochastic state
99+
ss := createState(&cfg, &e, db, rg)
100+
101+
// get stochastic matrix
102+
operations, A, state := getStochasticMatrix(&e)
103+
104+
// generate operations/random parameters from fuzzing string
105+
for !fSrc.End() {
106+
107+
// decode opcode
108+
op, addrCl, keyCl, valueCl := DecodeOpcode(operations[state])
109+
110+
// execute operation with its argument classes
111+
ss.execute(op, addrCl, keyCl, valueCl)
112+
113+
// check for errors
114+
if err := ss.db.Error(); err != nil {
115+
f.Errorf("failed fuzzing. Error: %v", err)
116+
}
117+
118+
// transit to next state in Markovian process
119+
state = nextState(rg, A, state)
120+
}
121+
})
122+
}

stochastic/replay.go

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,8 @@ func find[T comparable](a []T, x T) int {
5252
return -1
5353
}
5454

55-
// RunStochasticReplay runs the stochastic simulation for StateDB operations.
56-
// It requires the simulation model and simulation length. The trace-debug flag
57-
// enables/disables the printing of StateDB operations and their arguments on
58-
// the screen.
59-
func RunStochasticReplay(db state.StateDB, e *EstimationModelJSON, nBlocks int, cfg *utils.Config) error {
60-
var (
61-
opFrequency [NumOps]uint64 // operation frequency
62-
numOps uint64 // total number of operations
63-
)
64-
65-
// random generator
66-
rg := rand.New(rand.NewSource(cfg.RandomSeed))
67-
log.Printf("using random seed %d", cfg.RandomSeed)
68-
69-
// retrieve operations and stochastic matrix from simulation object
70-
operations := e.Operations
71-
A := e.StochasticMatrix
72-
55+
// createState creates a stochastic state and primes the StateDB
56+
func createState(cfg *utils.Config, e *EstimationModelJSON, db state.StateDB, rg *rand.Rand) *stochasticState {
7357
// produce random access generators for contract addresses,
7458
// storage-keys, and storage addresses.
7559
// (NB: Contracts need an indirect access wrapper because
@@ -99,11 +83,42 @@ func RunStochasticReplay(db state.StateDB, e *EstimationModelJSON, nBlocks int,
9983
// create accounts in StateDB
10084
ss.prime()
10185

102-
// set initial state to BeginSyncPeriod
86+
return &ss
87+
}
88+
89+
// getStochasticMatrix returns the stochastic matrix with its operations and the initial state
90+
func getStochasticMatrix(e *EstimationModelJSON) ([]string, [][]float64, int) {
91+
operations := e.Operations
92+
A := e.StochasticMatrix
93+
// and set initial state to BeginSyncPeriod
10394
state := find(operations, OpMnemo(BeginSyncPeriodID))
10495
if state == -1 {
105-
return fmt.Errorf("BeginSyncPeriod cannot be observed in stochastic matrix/recording failed.")
96+
panic("BeginSyncPeriod cannot be observed in stochastic matrix/recording failed.")
10697
}
98+
return operations, A, state
99+
}
100+
101+
// retrieve operations and stochastic matrix from simulation object
102+
103+
// RunStochasticReplay runs the stochastic simulation for StateDB operations.
104+
// It requires the simulation model and simulation length. The trace-debug flag
105+
// enables/disables the printing of StateDB operations and their arguments on
106+
// the screen.
107+
func RunStochasticReplay(db state.StateDB, e *EstimationModelJSON, nBlocks int, cfg *utils.Config) error {
108+
var (
109+
opFrequency [NumOps]uint64 // operation frequency
110+
numOps uint64 // total number of operations
111+
)
112+
113+
// random generator
114+
rg := rand.New(rand.NewSource(cfg.RandomSeed))
115+
log.Printf("using random seed %d", cfg.RandomSeed)
116+
117+
// create a stochastic state
118+
ss := createState(cfg, e, db, rg)
119+
120+
// get stochastic matrix
121+
operations, A, state := getStochasticMatrix(e)
107122

108123
// progress message setup
109124
var (

0 commit comments

Comments
 (0)