@@ -38,6 +38,13 @@ void Buffer::begin_block(uint64_t block_number) {
38
38
39
39
void Buffer::update_account (const evmc::address& address, std::optional<Account> initial,
40
40
std::optional<Account> current) {
41
+ // Skip update if both initial and final state are non-existent (i.e. contract creation+destruction within the same block)
42
+ if (!initial && !current) {
43
+ // Only to perfectly match Erigon state batch size (Erigon does count any account w/ old=new=empty value).
44
+ batch_state_size_ += kAddressLength ;
45
+ return ;
46
+ }
47
+
41
48
const bool equal{current == initial};
42
49
const bool account_deleted{!current.has_value ()};
43
50
@@ -83,10 +90,12 @@ void Buffer::update_account(const evmc::address& address, std::optional<Account>
83
90
84
91
void Buffer::update_account_code (const evmc::address& address, uint64_t incarnation, const evmc::bytes32& code_hash,
85
92
ByteView code) {
86
- // Don't overwrite already existing code so that views of it
87
- // that were previously returned by read_code() are still valid.
88
- if (hash_to_code_. try_emplace (code_hash, code). second ) {
93
+ // Don't overwrite existing code so that views of it that were previously returned by read_code are still valid
94
+ const auto [inserted_or_existing_it, inserted] = hash_to_code_. try_emplace (code_hash, code);
95
+ if (inserted ) {
89
96
batch_state_size_ += kHashLength + code.length ();
97
+ } else {
98
+ batch_state_size_ += code.length () - inserted_or_existing_it->second .length ();
90
99
}
91
100
92
101
if (storage_prefix_to_code_hash_.insert_or_assign (storage_prefix (address, incarnation), code_hash).second ) {
@@ -109,8 +118,14 @@ void Buffer::update_storage(const evmc::address& address, uint64_t incarnation,
109
118
}
110
119
}
111
120
112
- if (storage_[address][incarnation].insert_or_assign (location, current).second ) {
113
- batch_state_size_ += kPlainStoragePrefixLength + kHashLength + kHashLength ;
121
+ // Iterator in insert_or_assign return value "is pointing at the element that was inserted or updated"
122
+ // so we cannot use it to determine the old value size: we need to use initial instead
123
+ const auto [_, inserted] = storage_[address][incarnation].insert_or_assign (location, current);
124
+ ByteView current_val{zeroless_view (current.bytes )};
125
+ if (inserted) {
126
+ batch_state_size_ += kPlainStoragePrefixLength + kHashLength + current_val.length ();
127
+ } else {
128
+ batch_state_size_ += current_val.length () - zeroless_view (initial.bytes ).length ();
114
129
}
115
130
}
116
131
@@ -335,9 +350,17 @@ void Buffer::write_state_to_db() {
335
350
if (auto it{storage_.find (address)}; it != storage_.end ()) {
336
351
for (const auto & [incarnation, contract_storage] : it->second ) {
337
352
Bytes prefix{storage_prefix (address, incarnation)};
338
- for (const auto & [location, value] : contract_storage) {
339
- upsert_storage_value (*state_table, prefix, location.bytes , value.bytes );
340
- written_size += prefix.length () + kLocationLength + kHashLength ;
353
+ // Extract sorted set of storage locations to insert ordered data into the DB
354
+ absl::btree_set<evmc::bytes32> storage_locations;
355
+ for (auto & storage_entry : contract_storage) {
356
+ storage_locations.insert (storage_entry.first );
357
+ }
358
+ for (const auto & location : storage_locations) {
359
+ if (auto storage_it{contract_storage.find (location)}; storage_it != contract_storage.end ()) {
360
+ const auto & value{storage_it->second };
361
+ upsert_storage_value (*state_table, prefix, location.bytes , value.bytes );
362
+ written_size += prefix.length () + kLocationLength + zeroless_view (value.bytes ).size ();
363
+ }
341
364
}
342
365
}
343
366
storage_.erase (it);
@@ -439,7 +462,7 @@ void Buffer::insert_block(const Block& block, const evmc::bytes32& hash) {
439
462
uint64_t block_number{block.header .number };
440
463
Bytes key{block_key (block_number, hash.bytes )};
441
464
headers_[key] = block.header ;
442
- bodies_[key] = block;
465
+ bodies_[key] = block; // NOLINT(cppcoreguidelines-slicing)
443
466
444
467
if (block_number == 0 ) {
445
468
difficulty_[key] = 0 ;
0 commit comments