diff --git a/rskj-core/src/main/java/co/rsk/db/ContractDetailsImpl.java b/rskj-core/src/main/java/co/rsk/db/ContractDetailsImpl.java index d19daba7420..984df137770 100644 --- a/rskj-core/src/main/java/co/rsk/db/ContractDetailsImpl.java +++ b/rskj-core/src/main/java/co/rsk/db/ContractDetailsImpl.java @@ -384,6 +384,12 @@ public boolean isNullObject() { return (code==null || code.length==0) && keys.isEmpty(); } + @Override + public void mergeStore(ContractDetails storeContractDetails) { + ((ContractDetailsImpl) storeContractDetails).getTrie().copyTo(((TrieImpl)this.trie).getStore()); + checkExternalStorage(); + } + public Trie getTrie() { return this.trie; } @@ -401,7 +407,7 @@ private void removeKey(byte[] key) { } private void checkExternalStorage() { - this.externalStorage = (keys.size() > memoryStorageLimit) || this.externalStorage; + this.externalStorage = true; } private String getDataSourceName() { diff --git a/rskj-core/src/main/java/co/rsk/db/RepositoryImpl.java b/rskj-core/src/main/java/co/rsk/db/RepositoryImpl.java index b8a1cdaa93a..e72e7396aac 100644 --- a/rskj-core/src/main/java/co/rsk/db/RepositoryImpl.java +++ b/rskj-core/src/main/java/co/rsk/db/RepositoryImpl.java @@ -97,7 +97,7 @@ public synchronized AccountState createAccount(RskAddress addr) { null, trieStoreFactory, memoryStorageLimit - )); + ), null); return accountState; } @@ -181,7 +181,7 @@ public synchronized void saveCode(RskAddress addr, byte[] code) { details.setCode(code); accountState.setCodeHash(Keccak256Helper.keccak256(code)); - updateContractDetails(addr, details); + updateContractDetails(addr, details, null); updateAccountState(addr, accountState); } @@ -217,7 +217,7 @@ public synchronized void addStorageRow(RskAddress addr, DataWord key, DataWord v details.put(key, value); - updateContractDetails(addr, details); + updateContractDetails(addr, details, null); } @Override @@ -231,7 +231,7 @@ public synchronized void addStorageBytes(RskAddress addr, DataWord key, byte[] v details.putBytes(key, value); - updateContractDetails(addr, details); + updateContractDetails(addr, details, null); } @Override @@ -366,8 +366,9 @@ public synchronized void updateBatch(Map stateCache, } contractDetails = contractDetailsCache.getOriginalContractDetails(); + ContractDetails storeContractDetails = detailsDataStore.get(addr); - updateContractDetails(addr, contractDetails); + updateContractDetails(addr, contractDetails, storeContractDetails); if (!Arrays.equals(accountState.getCodeHash(), EMPTY_TRIE_HASH)) { accountState.setStateRoot(contractDetails.getStorageHash()); @@ -423,7 +424,12 @@ public synchronized DetailsDataStore getDetailsDataStore() { } @Override - public synchronized void updateContractDetails(RskAddress addr, final ContractDetails contractDetails) { + public synchronized void updateContractDetails(RskAddress addr, + final ContractDetails contractDetails, + final ContractDetails storeContractDetails) { + if (storeContractDetails != null) { + contractDetails.mergeStore(storeContractDetails); + } detailsDataStore.update(addr, contractDetails); } diff --git a/rskj-core/src/main/java/org/ethereum/core/Repository.java b/rskj-core/src/main/java/org/ethereum/core/Repository.java index c3601bde911..14ef9555c29 100644 --- a/rskj-core/src/main/java/org/ethereum/core/Repository.java +++ b/rskj-core/src/main/java/org/ethereum/core/Repository.java @@ -199,7 +199,10 @@ void loadAccount(RskAddress addr, DetailsDataStore getDetailsDataStore(); - void updateContractDetails(RskAddress addr, final ContractDetails contractDetails); + void updateContractDetails( + RskAddress addr, + final ContractDetails contractDetails, + ContractDetails storeContractDetails); void updateAccountState(RskAddress addr, AccountState accountState); diff --git a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java index 8d80e9f99bb..553c1ca63ae 100644 --- a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java +++ b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java @@ -130,7 +130,8 @@ public BlockChainImpl loadBlockchain() { accountState.setNonce(initialAddressState.getAccountState().getNonce()); if (initialAddressState.getContractDetails()!=null) { - repository.updateContractDetails(addr, initialAddressState.getContractDetails()); + repository.updateContractDetails(addr, initialAddressState.getContractDetails(), + null); accountState.setStateRoot(initialAddressState.getAccountState().getStateRoot()); accountState.setCodeHash(initialAddressState.getAccountState().getCodeHash()); } diff --git a/rskj-core/src/main/java/org/ethereum/db/ContractDetails.java b/rskj-core/src/main/java/org/ethereum/db/ContractDetails.java index e4edaf785bc..bcc406f7a34 100644 --- a/rskj-core/src/main/java/org/ethereum/db/ContractDetails.java +++ b/rskj-core/src/main/java/org/ethereum/db/ContractDetails.java @@ -78,4 +78,6 @@ public interface ContractDetails { ContractDetails getSnapshotTo(byte[] hash); boolean isNullObject(); + + void mergeStore(ContractDetails storeContractDetails); } diff --git a/rskj-core/src/main/java/org/ethereum/db/ContractDetailsCacheImpl.java b/rskj-core/src/main/java/org/ethereum/db/ContractDetailsCacheImpl.java index 4b1b4db37fc..bb5f0b65338 100644 --- a/rskj-core/src/main/java/org/ethereum/db/ContractDetailsCacheImpl.java +++ b/rskj-core/src/main/java/org/ethereum/db/ContractDetailsCacheImpl.java @@ -305,6 +305,11 @@ public boolean isNullObject() { return origContract.isNullObject() && (MapUtils.isEmpty(storage)); } + @Override + public void mergeStore(ContractDetails storeContractDetails) { + throw new UnsupportedOperationException("No merge option during cache state"); + } + public ContractDetails getOriginalContractDetails() { return this.origContract; } diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java b/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java index 01770e8ab6c..2b41aed30a9 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/Storage.java @@ -245,7 +245,10 @@ public DetailsDataStore getDetailsDataStore() { } @Override - public void updateContractDetails(RskAddress addr, ContractDetails contractDetails) { + public void updateContractDetails( + RskAddress addr, + ContractDetails contractDetails, + ContractDetails storeContractDetails) { throw new UnsupportedOperationException(); } diff --git a/rskj-core/src/test/java/co/rsk/core/NetworkStateExporterTest.java b/rskj-core/src/test/java/co/rsk/core/NetworkStateExporterTest.java index db7eeda1858..402a2df4c81 100644 --- a/rskj-core/src/test/java/co/rsk/core/NetworkStateExporterTest.java +++ b/rskj-core/src/test/java/co/rsk/core/NetworkStateExporterTest.java @@ -135,7 +135,7 @@ public void testContracts() throws Exception { contractDetails.setCode(new byte[] {1, 2, 3, 4}); contractDetails.put(DataWord.ZERO, DataWord.ONE); contractDetails.putBytes(DataWord.ONE, new byte[] {5, 6, 7, 8}); - repository.updateContractDetails(addr1, contractDetails); + repository.updateContractDetails(addr1, contractDetails, null); AccountState accountState = repository.getAccountState(addr1); accountState.setStateRoot(contractDetails.getStorageHash()); repository.updateAccountState(addr1, accountState);