diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccount.java index 6eea664e048..7ca6ef2b693 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccount.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccount.java @@ -82,6 +82,7 @@ public BonsaiAccount( toCopy.nonce, toCopy.balance, toCopy.codeHash, + toCopy.code, mutable); this.storageRoot = toCopy.storageRoot; updatedStorage.putAll(toCopy.updatedStorage); @@ -96,6 +97,7 @@ public BonsaiAccount( tracked.getNonce(), tracked.getBalance(), tracked.getCodeHash(), + tracked.getCode(), true); this.storageRoot = Hash.EMPTY_TRIE_HASH; updatedStorage.putAll(tracked.getUpdatedStorage()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedAccount.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedAccount.java index 044deb45a01..9b0a54fa468 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedAccount.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedAccount.java @@ -42,6 +42,22 @@ public abstract class DiffBasedAccount implements MutableAccount, AccountValue { protected final Map updatedStorage = new HashMap<>(); + /** + * Constructs a new DiffBasedAccount instance without the account's code. This constructor is used + * when the account's code is not required or will not be read from the database. It initializes + * the account with its context, address, address hash, nonce, balance, code hash, and mutability + * status. + * + * @param context The DiffBasedWorldView context in which this account exists. + * @param address The Ethereum address of this account. + * @param addressHash The hash of the account's address. + * @param nonce The nonce of the account, representing the number of transactions sent from this + * account. + * @param balance The balance of the account in Wei. + * @param codeHash The hash of the account's code. + * @param mutable A boolean indicating if the account is mutable. If false, the account is + * considered immutable. + */ public DiffBasedAccount( final DiffBasedWorldView context, final Address address, @@ -60,32 +76,40 @@ public DiffBasedAccount( this.immutable = !mutable; } + /** + * Constructs a new DiffBasedAccount instance with the account's code. This constructor is used + * when all account information, including its code, are available. It initializes the account + * with its context, address, address hash, nonce, balance, code hash, the actual code, and + * mutability status. + * + * @param context The DiffBasedWorldView context in which this account exists. + * @param address The Ethereum address of this account. + * @param addressHash The hash of the account's address. + * @param nonce The nonce of the account, representing the number of transactions sent from this + * account. + * @param balance The balance of the account in Wei. + * @param codeHash The hash of the account's code. + * @param code The actual bytecode of the account's smart contract. This is provided when the code + * is known and needs to be associated with the account. + * @param mutable A boolean indicating if the account is mutable. If false, the account is + * considered immutable. + */ public DiffBasedAccount( final DiffBasedWorldView context, final Address address, - final AccountValue stateTrieAccount, + final Hash addressHash, + final long nonce, + final Wei balance, + final Hash codeHash, + final Bytes code, final boolean mutable) { - this( - context, - address, - address.addressHash(), - stateTrieAccount.getNonce(), - stateTrieAccount.getBalance(), - stateTrieAccount.getCodeHash(), - mutable); - } - - public DiffBasedAccount( - final DiffBasedAccount toCopy, final DiffBasedWorldView context, final boolean mutable) { this.context = context; - this.address = toCopy.address; - this.addressHash = toCopy.addressHash; - this.nonce = toCopy.nonce; - this.balance = toCopy.balance; - this.codeHash = toCopy.codeHash; - this.code = toCopy.code; - updatedStorage.putAll(toCopy.updatedStorage); - + this.address = address; + this.addressHash = addressHash; + this.nonce = nonce; + this.balance = balance; + this.codeHash = codeHash; + this.code = code; this.immutable = !mutable; } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccountTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccountTest.java new file mode 100644 index 00000000000..60396b9789f --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccountTest.java @@ -0,0 +1,74 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.trie.diffbased.bonsai; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.units.bigints.UInt256; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +public class BonsaiAccountTest { + + @Mock BonsaiWorldState bonsaiWorldState; + + @Test + void shouldCopyTrackedBonsaiAccountCorrectly() { + final BonsaiAccount trackedAccount = + new BonsaiAccount( + bonsaiWorldState, + Address.ZERO, + Hash.hash(Address.ZERO), + 0, + Wei.ONE, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY, + true); + trackedAccount.setCode(Bytes.of(1)); + final UpdateTrackingAccount bonsaiAccountUpdateTrackingAccount = + new UpdateTrackingAccount<>(trackedAccount); + bonsaiAccountUpdateTrackingAccount.setStorageValue(UInt256.ONE, UInt256.ONE); + + final BonsaiAccount expectedAccount = new BonsaiAccount(trackedAccount, bonsaiWorldState, true); + expectedAccount.setStorageValue(UInt256.ONE, UInt256.ONE); + assertThat(new BonsaiAccount(bonsaiWorldState, bonsaiAccountUpdateTrackingAccount)) + .isEqualToComparingFieldByField(expectedAccount); + } + + @Test + void shouldCopyBonsaiAccountCorrectly() { + final BonsaiAccount account = + new BonsaiAccount( + bonsaiWorldState, + Address.ZERO, + Hash.hash(Address.ZERO), + 0, + Wei.ONE, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY, + true); + account.setCode(Bytes.of(1)); + account.setStorageValue(UInt256.ONE, UInt256.ONE); + assertThat(new BonsaiAccount(account, bonsaiWorldState, true)) + .isEqualToComparingFieldByField(account); + } +}