-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b58b43e
commit 89802f0
Showing
23 changed files
with
2,853 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package evm | ||
|
||
import ( | ||
"github.com/BlocSoc-iitr/selene/common" | ||
) | ||
|
||
type JournaledState struct { | ||
State EvmState | ||
TransientStorage TransientStorage | ||
Logs []Log[LogData] | ||
Depth uint | ||
Journal [][]JournalEntry | ||
Spec SpecId | ||
WarmPreloadedAddresses map[Address]struct{} | ||
} | ||
|
||
func NewJournalState(spec SpecId, warmPreloadedAddresses map[Address]struct{}) JournaledState { | ||
return JournaledState{ | ||
State: nil, | ||
TransientStorage: nil, | ||
Logs: []Log[LogData]{}, | ||
Depth: 0, | ||
Journal: [][]JournalEntry{}, | ||
Spec: spec, | ||
WarmPreloadedAddresses: warmPreloadedAddresses, | ||
} | ||
} | ||
|
||
type JournalCheckpoint struct { | ||
Log_i uint | ||
Journal_i uint | ||
} | ||
|
||
func (j *JournaledState) setSpecId(spec SpecId) { | ||
j.Spec = spec | ||
} | ||
|
||
type TransientStorage map[Key]U256 | ||
type EvmState map[common.Address]Account | ||
type Key struct { | ||
Account common.Address | ||
Slot U256 | ||
} | ||
type Log[T any] struct { | ||
// The address which emitted this log. | ||
Address Address `json:"address"` | ||
// The log data. | ||
Data T `json:"data"` | ||
} | ||
|
||
type LogData struct { | ||
// The indexed topic list. | ||
Topics []B256 `json:"topics"` | ||
// The plain data. | ||
Data Bytes `json:"data"` | ||
} | ||
|
||
func (l *Log[LogData]) UnmarshalJSON(data []byte) error { | ||
return unmarshalJSON(data, l) | ||
} | ||
|
||
func (l *LogData) UnmarshalJSON(data []byte) error { | ||
return unmarshalJSON(data, l) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package evm | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"math/big" | ||
) | ||
|
||
type JournalEntryType uint8 | ||
|
||
const ( | ||
AccountWarmedType JournalEntryType = iota | ||
AccountDestroyedType | ||
AccountTouchedType | ||
BalanceTransferType | ||
NonceChangeType | ||
AccountCreatedType | ||
StorageChangedType | ||
StorageWarmedType | ||
TransientStorageChangeType | ||
CodeChangeType | ||
) | ||
|
||
// JournalEntry represents a journal entry with various fields. | ||
type JournalEntry struct { | ||
Type JournalEntryType `json:"type"` | ||
Address Address `json:"address"` | ||
Target Address `json:"target,omitempty"` // Used for AccountDestroyed | ||
WasDestroyed bool `json:"was_destroyed,omitempty"` // Used for AccountDestroyed | ||
HadBalance U256 `json:"had_balance,omitempty"` // Used for AccountDestroyed | ||
Balance U256 `json:"balance,omitempty"` // Used for BalanceTransfer | ||
From Address `json:"from,omitempty"` // Used for BalanceTransfer | ||
To Address `json:"to,omitempty"` // Used for BalanceTransfer | ||
Key U256 `json:"key,omitempty"` // Used for Storage operations | ||
HadValue U256 `json:"had_value,omitempty"` // Used for Storage operations | ||
} | ||
|
||
// MarshalJSON implements the json.Marshaler interface for JournalEntry. | ||
func (j JournalEntry) MarshalJSON() ([]byte, error) { | ||
type Alias JournalEntry // Create an alias to avoid recursion | ||
|
||
// Helper function to convert U256 to hex string | ||
u256ToHex := func(u U256) string { | ||
return fmt.Sprintf("0x%s", (*big.Int)(u).Text(16)) | ||
} | ||
|
||
return json.Marshal(&struct { | ||
Address string `json:"address"` | ||
Target string `json:"target,omitempty"` | ||
From string `json:"from,omitempty"` | ||
To string `json:"to,omitempty"` | ||
Key string `json:"key,omitempty"` | ||
HadBalance string `json:"had_balance,omitempty"` | ||
Balance string `json:"balance,omitempty"` | ||
HadValue string `json:"had_value,omitempty"` | ||
*Alias | ||
}{ | ||
Address: "0x" + fmt.Sprintf("%x", j.Address.Addr[:]), // Convert to hex string | ||
Target: "0x" + fmt.Sprintf("%x", j.Target.Addr[:]), // Convert to hex string | ||
From: "0x" + fmt.Sprintf("%x", j.From.Addr[:]), // Convert to hex string | ||
To: "0x" + fmt.Sprintf("%x", j.To.Addr[:]), // Convert to hex string | ||
Key: u256ToHex(j.Key), // Convert U256 to hex string | ||
HadBalance: u256ToHex(j.HadBalance), // Convert U256 to hex string | ||
Balance: u256ToHex(j.Balance), // Convert U256 to hex string | ||
HadValue: u256ToHex(j.HadValue), // Convert U256 to hex string | ||
Alias: (*Alias)(&j), // Embed the original struct | ||
}) | ||
} | ||
|
||
func NewAccountWarmedEntry(address Address) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: AccountWarmedType, | ||
Address: address, | ||
} | ||
} | ||
|
||
// NewAccountDestroyedEntry creates a new journal entry for destroying an account | ||
func NewAccountDestroyedEntry(address, target Address, wasDestroyed bool, hadBalance U256) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: AccountDestroyedType, | ||
Address: address, | ||
Target: target, | ||
WasDestroyed: wasDestroyed, | ||
HadBalance: new(big.Int).Set(hadBalance), //to avoid mutating the original value (had balance not written directly) | ||
} | ||
} | ||
|
||
// NewAccountTouchedEntry creates a new journal entry for touching an account | ||
func NewAccountTouchedEntry(address Address) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: AccountTouchedType, | ||
Address: address, | ||
} | ||
} | ||
|
||
// NewBalanceTransferEntry creates a new journal entry for balance transfer | ||
func NewBalanceTransferEntry(from, to Address, balance U256) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: BalanceTransferType, | ||
From: from, | ||
To: to, | ||
Balance: new(big.Int).Set(balance), | ||
} | ||
} | ||
|
||
// NewNonceChangeEntry creates a new journal entry for nonce change | ||
func NewNonceChangeEntry(address Address) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: NonceChangeType, | ||
Address: address, | ||
} | ||
} | ||
|
||
// NewAccountCreatedEntry creates a new journal entry for account creation | ||
func NewAccountCreatedEntry(address Address) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: AccountCreatedType, | ||
Address: address, | ||
} | ||
} | ||
|
||
// NewStorageChangedEntry creates a new journal entry for storage change | ||
func NewStorageChangedEntry(address Address, key, hadValue U256) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: StorageChangedType, | ||
Address: address, | ||
Key: new(big.Int).Set(key), | ||
HadValue: new(big.Int).Set(hadValue), | ||
} | ||
} | ||
|
||
// NewStorageWarmedEntry creates a new journal entry for storage warming | ||
func NewStorageWarmedEntry(address Address, key U256) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: StorageWarmedType, | ||
Address: address, | ||
Key: new(big.Int).Set(key), | ||
} | ||
} | ||
|
||
// NewTransientStorageChangeEntry creates a new journal entry for transient storage change | ||
func NewTransientStorageChangeEntry(address Address, key, hadValue U256) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: TransientStorageChangeType, | ||
Address: address, | ||
Key: new(big.Int).Set(key), | ||
HadValue: new(big.Int).Set(hadValue), | ||
} | ||
} | ||
|
||
// NewCodeChangeEntry creates a new journal entry for code change | ||
func NewCodeChangeEntry(address Address) *JournalEntry { | ||
return &JournalEntry{ | ||
Type: CodeChangeType, | ||
Address: address, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
package evm | ||
|
||
import ( | ||
"encoding/hex" | ||
"encoding/json" | ||
"math/big" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// HexToAddress converts a hex string to an Address type | ||
func HexToAddress(hexStr string) Address { | ||
var addr Address | ||
bytes, err := hex.DecodeString(hexStr[2:]) // Remove '0x' prefix | ||
if err == nil && len(bytes) == 20 { | ||
var bytesNew [20]byte | ||
copy(bytesNew[:], bytes) | ||
addr = Address{ | ||
Addr: bytesNew, | ||
} | ||
} | ||
return addr | ||
} | ||
|
||
// Helper function to create U256 values | ||
func newU256(value int64) *big.Int { | ||
return big.NewInt(value) | ||
} | ||
|
||
func TestNewAccountWarmedEntry(t *testing.T) { | ||
address := Address{} | ||
entry := NewAccountWarmedEntry(address) | ||
|
||
assert.Equal(t, AccountWarmedType, entry.Type, "Type should be AccountWarmedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
} | ||
|
||
func TestNewAccountDestroyedEntry(t *testing.T) { | ||
address := HexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
target := HexToAddress("0x5678567856785678567856785678567856785678") | ||
hadBalance := newU256(100) | ||
entry := NewAccountDestroyedEntry(address, target, true, hadBalance) | ||
|
||
assert.Equal(t, AccountDestroyedType, entry.Type, "Type should be AccountDestroyedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
assert.Equal(t, target, entry.Target, "Target should match") | ||
assert.True(t, entry.WasDestroyed, "WasDestroyed should be true") | ||
assert.Equal(t, hadBalance, entry.HadBalance, "HadBalance should match") | ||
} | ||
|
||
func TestNewAccountTouchedEntry(t *testing.T) { | ||
address := HexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
entry := NewAccountTouchedEntry(address) | ||
|
||
assert.Equal(t, AccountTouchedType, entry.Type, "Type should be AccountTouchedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
} | ||
|
||
func TestNewBalanceTransferEntry(t *testing.T) { | ||
from := HexToAddress("0x1111111111111111111111111111111111111111") | ||
to := HexToAddress("0x2222222222222222222222222222222222222222") | ||
balance := newU256(50) | ||
entry := NewBalanceTransferEntry(from, to, balance) | ||
|
||
assert.Equal(t, BalanceTransferType, entry.Type, "Type should be BalanceTransferType") | ||
assert.Equal(t, from, entry.From, "From address should match") | ||
assert.Equal(t, to, entry.To, "To address should match") | ||
assert.Equal(t, balance, entry.Balance, "Balance should match") | ||
} | ||
|
||
func TestNewNonceChangeEntry(t *testing.T) { | ||
address := HexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
entry := NewNonceChangeEntry(address) | ||
|
||
assert.Equal(t, NonceChangeType, entry.Type, "Type should be NonceChangeType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
} | ||
|
||
func TestNewAccountCreatedEntry(t *testing.T) { | ||
address := HexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
entry := NewAccountCreatedEntry(address) | ||
|
||
assert.Equal(t, AccountCreatedType, entry.Type, "Type should be AccountCreatedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
} | ||
|
||
func TestNewStorageChangedEntry(t *testing.T) { | ||
address := HexToAddress("0x3333333333333333333333333333333333333333") | ||
key := newU256(1) | ||
hadValue := newU256(10) | ||
entry := NewStorageChangedEntry(address, key, hadValue) | ||
|
||
assert.Equal(t, StorageChangedType, entry.Type, "Type should be StorageChangedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
assert.Equal(t, key, entry.Key, "Key should match") | ||
assert.Equal(t, hadValue, entry.HadValue, "HadValue should match") | ||
} | ||
|
||
func TestNewStorageWarmedEntry(t *testing.T) { | ||
address := HexToAddress("0x3333333333333333333333333333333333333333") | ||
key := newU256(1) | ||
entry := NewStorageWarmedEntry(address, key) | ||
|
||
assert.Equal(t, StorageWarmedType, entry.Type, "Type should be StorageWarmedType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
assert.Equal(t, key, entry.Key, "Key should match") | ||
} | ||
|
||
func TestNewTransientStorageChangeEntry(t *testing.T) { | ||
address := HexToAddress("0x4444444444444444444444444444444444444444") | ||
key := newU256(5) | ||
hadValue := newU256(20) | ||
entry := NewTransientStorageChangeEntry(address, key, hadValue) | ||
|
||
assert.Equal(t, TransientStorageChangeType, entry.Type, "Type should be TransientStorageChangeType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
assert.Equal(t, key, entry.Key, "Key should match") | ||
assert.Equal(t, hadValue, entry.HadValue, "HadValue should match") | ||
} | ||
|
||
func TestNewCodeChangeEntry(t *testing.T) { | ||
address := HexToAddress("0x1234567890abcdef1234567890abcdef12345678") | ||
entry := NewCodeChangeEntry(address) | ||
|
||
assert.Equal(t, CodeChangeType, entry.Type, "Type should be CodeChangeType") | ||
assert.Equal(t, address, entry.Address, "Address should match") | ||
} | ||
|
||
func TestJournalEntryMarshalJSON(t *testing.T) { | ||
// Create an example JournalEntry object | ||
entry := JournalEntry{ | ||
Type: 1, | ||
Address: Address{Addr: [20]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}}, | ||
Target: Address{Addr: [20]byte{0x56, 0x78, 0x56, 0x78, 0x56, 0x78, 0x56, 0x78}}, | ||
WasDestroyed: true, | ||
HadBalance: big.NewInt(100), | ||
Balance: big.NewInt(200), | ||
From: Address{Addr: [20]byte{0x00, 0x00, 0x00, 0x00}}, | ||
To: Address{Addr: [20]byte{0x00, 0x00, 0x00, 0x00}}, | ||
Key: big.NewInt(300), | ||
HadValue: big.NewInt(400), | ||
} | ||
|
||
// Marshal the entry to JSON | ||
actualJSON, err := json.Marshal(entry) | ||
if err != nil { | ||
t.Fatalf("Failed to marshal JournalEntry to JSON: %v", err) | ||
} | ||
|
||
// Define the expected JSON output with hex strings | ||
expectedJSON := `{"address":"0x1234567890abcdef000000000000000000000000","target":"0x5678567856785678000000000000000000000000","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","key":"0x12c","had_balance":"0x64","balance":"0xc8","had_value":"0x190","type":1,"was_destroyed":true}` | ||
|
||
// Compare actual JSON with expected JSON | ||
if string(actualJSON) != expectedJSON { | ||
t.Errorf("Expected JSON does not match actual JSON.\nExpected: %s\nActual: %s", expectedJSON, actualJSON) | ||
} | ||
} | ||
|
||
// Helper function to compare two JSON objects | ||
func compareJSON(a, b map[string]interface{}) bool { | ||
return reflect.DeepEqual(a, b) | ||
} |
Oops, something went wrong.