diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index f9f9f981c..fa78ee15a 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -17,6 +17,8 @@ package logger import ( + "sort" + "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" types2 "github.com/ledgerwatch/erigon-lib/types" @@ -94,6 +96,10 @@ func (al accessList) equal(other accessList) bool { return true } +func (al accessList) Equal(other accessList) bool { + return al.equal(other) +} + // accesslist converts the accesslist to a types2.AccessList. func (al accessList) accessList() types2.AccessList { acl := make(types2.AccessList, 0, len(al)) @@ -107,6 +113,25 @@ func (al accessList) accessList() types2.AccessList { return acl } +// accesslist converts the accesslist to a types2.AccessList. +func (al accessList) accessListSorted() types2.AccessList { + acl := make(types2.AccessList, 0, len(al)) + for addr, slots := range al { + storageKeys := make([]libcommon.Hash, 0, len(slots)) + for slot := range slots { + storageKeys = append(storageKeys, slot) + } + sort.Slice(storageKeys, func(i, j int) bool { + return storageKeys[i].String() < storageKeys[j].String() + }) + acl = append(acl, types2.AccessTuple{ + Address: addr, + StorageKeys: storageKeys, + }) + } + return acl +} + // AccessListTracer is a tracer that accumulates touched accounts and storage // slots into an internal set. type AccessListTracer struct { @@ -227,6 +252,11 @@ func (a *AccessListTracer) AccessList() types2.AccessList { return a.list.accessList() } +// AccessList returns the current accesslist maintained by the tracer. +func (a *AccessListTracer) AccessListSorted() types2.AccessList { + return a.list.accessListSorted() +} + // CreatedContracts returns the set of all addresses of contracts created during tx execution. func (a *AccessListTracer) CreatedContracts() map[libcommon.Address]struct{} { return a.createdContracts diff --git a/eth/tracers/logger/access_list_tracer_test.go b/eth/tracers/logger/access_list_tracer_test.go new file mode 100644 index 000000000..02f719689 --- /dev/null +++ b/eth/tracers/logger/access_list_tracer_test.go @@ -0,0 +1,40 @@ +package logger + +import ( + "testing" + + "github.com/ledgerwatch/erigon-lib/common" + types2 "github.com/ledgerwatch/erigon-lib/types" + "github.com/stretchr/testify/require" +) + +var ( + addr = common.BytesToAddress([]byte{0x01, 0x71}) + + slot1 = common.BytesToHash([]byte{0x01}) + slot2 = common.BytesToHash([]byte{0x02}) + slot3 = common.BytesToHash([]byte{0x03}) + slot4 = common.BytesToHash([]byte{0x04}) + + ordered = types2.AccessList{{ + Address: addr, + StorageKeys: []common.Hash{ + slot1, + slot2, + slot3, + slot4, + }, + }} +) + +func TestTracer_AccessList_Order(t *testing.T) { + al := newAccessList() + al.addAddress(addr) + al.addSlot(addr, slot1) + al.addSlot(addr, slot4) + al.addSlot(addr, slot3) + al.addSlot(addr, slot2) + require.NotEqual(t, ordered, al.accessList()) + require.Equal(t, ordered, al.accessListSorted()) + require.True(t, al.Equal(al)) +}