Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/core state logs #10

Merged
merged 2 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions core/state/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ledgerwatch/erigon/firehose"
"github.com/ledgerwatch/erigon/turbo/stages"
"github.com/ledgerwatch/erigon/turbo/trie"

Expand Down Expand Up @@ -846,25 +847,25 @@ func TestReproduceCrash(t *testing.T) {
tsw := state.NewPlainStateWriter(tx, nil, 1)
intraBlockState := state.New(state.NewPlainState(tx, 1, nil))
// Start the 1st transaction
intraBlockState.CreateAccount(contract, true)
intraBlockState.CreateAccount(contract, true, firehose.NoOpContext)
if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
// Start the 2nd transaction
intraBlockState.SetState(contract, &storageKey1, *value1)
intraBlockState.SetState(contract, &storageKey1, *value1, firehose.NoOpContext)
if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
// Start the 3rd transaction
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000))
intraBlockState.SetState(contract, &storageKey2, *value2)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000), false, firehose.NoOpContext, "test")
intraBlockState.SetState(contract, &storageKey2, *value2, firehose.NoOpContext)
if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
// Start the 4th transaction - clearing both storage cells
intraBlockState.SubBalance(contract, uint256.NewInt(1000000000))
intraBlockState.SetState(contract, &storageKey1, *value0)
intraBlockState.SetState(contract, &storageKey2, *value0)
intraBlockState.SubBalance(contract, uint256.NewInt(1000000000), firehose.NoOpContext, "test")
intraBlockState.SetState(contract, &storageKey1, *value0, firehose.NoOpContext)
intraBlockState.SetState(contract, &storageKey2, *value0, firehose.NoOpContext)
if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
Expand Down Expand Up @@ -1235,12 +1236,12 @@ func TestChangeAccountCodeBetweenBlocks(t *testing.T) {
r, tsw := state.NewPlainStateReader(tx), state.NewPlainStateWriter(tx, nil, 0)
intraBlockState := state.New(r)
// Start the 1st transaction
intraBlockState.CreateAccount(contract, true)
intraBlockState.CreateAccount(contract, true, firehose.NoOpContext)

oldCode := []byte{0x01, 0x02, 0x03, 0x04}

intraBlockState.SetCode(contract, oldCode)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000))
intraBlockState.SetCode(contract, oldCode, firehose.NoOpContext)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000), false, firehose.NoOpContext, "test")
if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
Expand All @@ -1252,7 +1253,7 @@ func TestChangeAccountCodeBetweenBlocks(t *testing.T) {
assert.Equal(t, oldCode, trieCode, "new code should be received")

newCode := []byte{0x04, 0x04, 0x04, 0x04}
intraBlockState.SetCode(contract, newCode)
intraBlockState.SetCode(contract, newCode, firehose.NoOpContext)

if err := intraBlockState.FinalizeTx(&chain.Rules{}, tsw); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
Expand All @@ -1273,12 +1274,12 @@ func TestCacheCodeSizeSeparately(t *testing.T) {
r, w := state.NewPlainState(tx, 0, nil), state.NewPlainStateWriter(tx, nil, 0)
intraBlockState := state.New(r)
// Start the 1st transaction
intraBlockState.CreateAccount(contract, true)
intraBlockState.CreateAccount(contract, true, firehose.NoOpContext)

code := []byte{0x01, 0x02, 0x03, 0x04}

intraBlockState.SetCode(contract, code)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000))
intraBlockState.SetCode(contract, code, firehose.NoOpContext)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000), false, firehose.NoOpContext, "test")
if err := intraBlockState.FinalizeTx(&chain.Rules{}, w); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
Expand Down Expand Up @@ -1306,12 +1307,12 @@ func TestCacheCodeSizeInTrie(t *testing.T) {
r, w := state.NewPlainState(tx, 0, nil), state.NewPlainStateWriter(tx, nil, 0)
intraBlockState := state.New(r)
// Start the 1st transaction
intraBlockState.CreateAccount(contract, true)
intraBlockState.CreateAccount(contract, true, firehose.NoOpContext)

code := []byte{0x01, 0x02, 0x03, 0x04}

intraBlockState.SetCode(contract, code)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000))
intraBlockState.SetCode(contract, code, firehose.NoOpContext)
intraBlockState.AddBalance(contract, uint256.NewInt(1000000000), false, firehose.NoOpContext, "test")
if err := intraBlockState.FinalizeTx(&chain.Rules{}, w); err != nil {
t.Errorf("error finalising 1st tx: %v", err)
}
Expand Down
84 changes: 53 additions & 31 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/types/accounts"
"github.com/ledgerwatch/erigon/crypto"
"github.com/ledgerwatch/erigon/firehose"
"github.com/ledgerwatch/erigon/turbo/trie"
)

Expand Down Expand Up @@ -144,12 +145,17 @@ func (sdb *IntraBlockState) Reset() {
//sdb.balanceInc = make(map[libcommon.Address]*BalanceIncrease)
}

func (sdb *IntraBlockState) AddLog(log2 *types.Log) {
func (sdb *IntraBlockState) AddLog(log2 *types.Log, firehoseContext *firehose.Context) {
sdb.journal.append(addLogChange{txhash: sdb.thash})
log2.TxHash = sdb.thash
log2.BlockHash = sdb.bhash
log2.TxIndex = uint(sdb.txIndex)
log2.Index = sdb.logSize

if firehoseContext.Enabled() {
firehoseContext.RecordLog(log2)
}

sdb.logs[sdb.thash] = append(sdb.logs[sdb.thash], log2)
sdb.logSize++
}
Expand Down Expand Up @@ -303,7 +309,7 @@ func (sdb *IntraBlockState) HasSelfdestructed(addr libcommon.Address) bool {

// AddBalance adds amount to the account associated with addr.
// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.Int) {
func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.Int, isPrecompiledAddr bool, firehoseContext *firehose.Context, reason firehose.BalanceChangeReason) {
if sdb.trace {
fmt.Printf("AddBalance %x, %d\n", addr, amount)
}
Expand All @@ -327,68 +333,68 @@ func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.I
return
}

stateObject := sdb.GetOrNewStateObject(addr)
stateObject.AddBalance(amount)
stateObject := sdb.GetOrNewStateObject(addr, isPrecompiledAddr, firehoseContext)
stateObject.AddBalance(amount, firehoseContext, reason)
}

// SubBalance subtracts amount from the account associated with addr.
// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) SubBalance(addr libcommon.Address, amount *uint256.Int) {
func (sdb *IntraBlockState) SubBalance(addr libcommon.Address, amount *uint256.Int, firehoseContext *firehose.Context, reason firehose.BalanceChangeReason) {
if sdb.trace {
fmt.Printf("SubBalance %x, %d\n", addr, amount)
}

stateObject := sdb.GetOrNewStateObject(addr)
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SubBalance(amount)
stateObject.SubBalance(amount, firehoseContext, reason)
}
}

// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) SetBalance(addr libcommon.Address, amount *uint256.Int) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetBalance(addr libcommon.Address, amount *uint256.Int, firehoseContext *firehose.Context, reason firehose.BalanceChangeReason) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SetBalance(amount)
stateObject.SetBalance(amount, firehoseContext, reason)
}
}

// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) SetNonce(addr libcommon.Address, nonce uint64) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetNonce(addr libcommon.Address, nonce uint64, firehoseContext *firehose.Context) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SetNonce(nonce)
stateObject.SetNonce(nonce, firehoseContext)
}
}

// DESCRIBED: docs/programmers_guide/guide.md#code-hash
// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) SetCode(addr libcommon.Address, code []byte) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetCode(addr libcommon.Address, code []byte, firehoseContext *firehose.Context) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SetCode(crypto.Keccak256Hash(code), code)
stateObject.SetCode(crypto.Keccak256Hash(code), code, firehoseContext)
}
}

// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) SetState(addr libcommon.Address, key *libcommon.Hash, value uint256.Int) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetState(addr libcommon.Address, key *libcommon.Hash, value uint256.Int, firehoseContext *firehose.Context) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SetState(key, value)
stateObject.SetState(key, value, firehoseContext)
}
}

// SetStorage replaces the entire storage for the specified account with given
// storage. This function should only be used for debugging.
func (sdb *IntraBlockState) SetStorage(addr libcommon.Address, storage Storage) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetStorage(addr libcommon.Address, storage Storage, firehoseContext *firehose.Context) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.SetStorage(storage)
}
}

// SetIncarnation sets incarnation for account if account exists
func (sdb *IntraBlockState) SetIncarnation(addr libcommon.Address, incarnation uint64) {
stateObject := sdb.GetOrNewStateObject(addr)
func (sdb *IntraBlockState) SetIncarnation(addr libcommon.Address, incarnation uint64, firehoseContext *firehose.Context) {
stateObject := sdb.GetOrNewStateObject(addr, false, firehoseContext)
if stateObject != nil {
stateObject.setIncarnation(incarnation)
}
Expand All @@ -407,7 +413,7 @@ func (sdb *IntraBlockState) GetIncarnation(addr libcommon.Address) uint64 {
//
// The account's state object is still available until the state is committed,
// getStateObject will return a non-nil account after Suicide.
func (sdb *IntraBlockState) Selfdestruct(addr libcommon.Address) bool {
func (sdb *IntraBlockState) Selfdestruct(addr libcommon.Address, firehoseContext *firehose.Context) bool {
stateObject := sdb.getStateObject(addr)
if stateObject == nil || stateObject.deleted {
return false
Expand All @@ -417,6 +423,11 @@ func (sdb *IntraBlockState) Selfdestruct(addr libcommon.Address) bool {
prev: stateObject.selfdestructed,
prevbalance: *stateObject.Balance(),
})

if firehoseContext.Enabled() {
firehoseContext.RecordSuicide(stateObject.address, stateObject.selfdestructed, stateObject.Balance())
}

stateObject.markSelfdestructed()
stateObject.created = false
stateObject.data.Balance.Clear()
Expand All @@ -433,7 +444,10 @@ func (sdb *IntraBlockState) getStateObject(addr libcommon.Address) (stateObject
// Load the object from the database.
if _, ok := sdb.nilAccounts[addr]; ok {
if bi, ok := sdb.balanceInc[addr]; ok && !bi.transferred {
return sdb.createObject(addr, nil)
// CS TODO: check if we need to provide actual firehose context
// this means that the account is being created through this logic
// and we need to capture this
return sdb.createObject(addr, nil, false, firehose.NoOpContext)
}
return nil
}
Expand All @@ -445,7 +459,10 @@ func (sdb *IntraBlockState) getStateObject(addr libcommon.Address) (stateObject
if account == nil {
sdb.nilAccounts[addr] = struct{}{}
if bi, ok := sdb.balanceInc[addr]; ok && !bi.transferred {
return sdb.createObject(addr, nil)
// CS TODO: check if we need to provide actual firehose context
// this means that the account is being created through this logic
// and we need to capture this
return sdb.createObject(addr, nil, false, firehose.NoOpContext)
}
return nil
}
Expand All @@ -466,17 +483,17 @@ func (sdb *IntraBlockState) setStateObject(addr libcommon.Address, object *state
}

// Retrieve a state object or create a new state object if nil.
func (sdb *IntraBlockState) GetOrNewStateObject(addr libcommon.Address) *stateObject {
func (sdb *IntraBlockState) GetOrNewStateObject(addr libcommon.Address, isPrecompiledAddr bool, firehoseContext *firehose.Context) *stateObject {
stateObject := sdb.getStateObject(addr)
if stateObject == nil || stateObject.deleted {
stateObject = sdb.createObject(addr, stateObject /* previous */)
stateObject = sdb.createObject(addr, stateObject /* previous */, isPrecompiledAddr, firehoseContext)
}
return stateObject
}

// createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten.
func (sdb *IntraBlockState) createObject(addr libcommon.Address, previous *stateObject) (newobj *stateObject) {
func (sdb *IntraBlockState) createObject(addr libcommon.Address, previous *stateObject, isPrecompiledAddr bool, firehoseContext *firehose.Context) (newobj *stateObject) {
account := new(accounts.Account)
var original *accounts.Account
if previous == nil {
Expand All @@ -492,6 +509,11 @@ func (sdb *IntraBlockState) createObject(addr libcommon.Address, previous *state
} else {
sdb.journal.append(resetObjectChange{account: &addr, prev: previous})
}

if firehoseContext.Enabled() && !isPrecompiledAddr {
firehoseContext.RecordNewAccount(addr)
}

sdb.setStateObject(addr, newobj)
return newobj
}
Expand All @@ -506,7 +528,7 @@ func (sdb *IntraBlockState) createObject(addr libcommon.Address, previous *state
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
//
// Carrying over the balance ensures that Ether doesn't disappear.
func (sdb *IntraBlockState) CreateAccount(addr libcommon.Address, contractCreation bool) {
func (sdb *IntraBlockState) CreateAccount(addr libcommon.Address, contractCreation bool, firehoseContext *firehose.Context) {
var prevInc uint64
previous := sdb.getStateObject(addr)
if contractCreation {
Expand All @@ -523,7 +545,7 @@ func (sdb *IntraBlockState) CreateAccount(addr libcommon.Address, contractCreati
}
}

newObj := sdb.createObject(addr, previous)
newObj := sdb.createObject(addr, previous, false, firehoseContext)
if previous != nil {
newObj.data.Balance.Set(&previous.data.Balance)
newObj.data.Initialised = true
Expand Down
16 changes: 8 additions & 8 deletions core/state/intra_block_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,21 @@ func newTestAction(addr libcommon.Address, r *rand.Rand) testAction {
{
name: "SetBalance",
fn: func(a testAction, s *IntraBlockState) {
s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])))
s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])), firehose.NoOpContext, "test")
},
args: make([]int64, 1),
},
{
name: "AddBalance",
fn: func(a testAction, s *IntraBlockState) {
s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])))
s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])), false, firehose.NoOpContext, "test")
},
args: make([]int64, 1),
},
{
name: "SetNonce",
fn: func(a testAction, s *IntraBlockState) {
s.SetNonce(addr, uint64(a.args[0]))
s.SetNonce(addr, uint64(a.args[0]), firehose.NoOpContext)
},
args: make([]int64, 1),
},
Expand All @@ -104,7 +104,7 @@ func newTestAction(addr libcommon.Address, r *rand.Rand) testAction {
var key libcommon.Hash
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
val := uint256.NewInt(uint64(a.args[1]))
s.SetState(addr, &key, *val)
s.SetState(addr, &key, *val, firehose.NoOpContext)
},
args: make([]int64, 2),
},
Expand All @@ -114,20 +114,20 @@ func newTestAction(addr libcommon.Address, r *rand.Rand) testAction {
code := make([]byte, 16)
binary.BigEndian.PutUint64(code, uint64(a.args[0]))
binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
s.SetCode(addr, code)
s.SetCode(addr, code, firehose.NoOpContext)
},
args: make([]int64, 2),
},
{
name: "CreateAccount",
fn: func(a testAction, s *IntraBlockState) {
s.CreateAccount(addr, true)
s.CreateAccount(addr, true, firehose.NoOpContext)
},
},
{
name: "Selfdestruct",
fn: func(a testAction, s *IntraBlockState) {
s.Selfdestruct(addr)
s.Selfdestruct(addr, firehose.NoOpContext)
},
},
{
Expand All @@ -143,7 +143,7 @@ func newTestAction(addr libcommon.Address, r *rand.Rand) testAction {
fn: func(a testAction, s *IntraBlockState) {
data := make([]byte, 2)
binary.BigEndian.PutUint16(data, uint16(a.args[0]))
s.AddLog(&types.Log{Address: addr, Data: data})
s.AddLog(&types.Log{Address: addr, Data: data}, firehose.NoOpContext)
},
args: make([]int64, 1),
},
Expand Down
Loading