-
Notifications
You must be signed in to change notification settings - Fork 267
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
Adding transient storage maps with TLOAD/TSTORE implementation #2801
Adding transient storage maps with TLOAD/TSTORE implementation #2801
Conversation
6142056
to
7149f88
Compare
d6dc804
to
8892bf3
Compare
743e9e8
to
3ce63a0
Compare
01c2a45
to
81cef20
Compare
|
||
@Override | ||
public void clearTransientStorage() { | ||
this.transientTrie = new MutableTrieImpl(new TrieStoreImpl(new HashMapDB()), new Trie()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how often does clearTransientStorage
gets called in our app? If it’s pretty frequent, I wonder if constantly reinitializing transientTrie is the best approach performance-wise. Maybe we could find a way to clear entries without creating a new instance? let me know what you think!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically after every transaction execution. The thing is that this class it's initialized everytime a transaction starts anyway. Because this is used for the Storage during the transaction execution that might be rolled back and used by the storage. This clear will be called at end of a transaction. And it's extremely important that this data it's cleared. So, we would basically create a new MutableTrieStore anyway.
b887917
to
9d4530d
Compare
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Manifest Files |
9d4530d
to
7038543
Compare
@Nullable | ||
@Override | ||
public DataWord getTransientStorageValue(RskAddress addr, DataWord key) { | ||
byte[] triekey = trieKeyMapper.getAccountStorageKey(addr, key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method below public byte[] getTransientStorageBytes(RskAddress addr, DataWord key)
could be used here before wrap the result into the DataWord as they have the same logic to retrieve the value from the transient trie.
private TransientStorageRepositoryCreator() { | ||
} | ||
|
||
public static Repository createNewTransientStorage() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where this method would be used? Why is needed? Are we going to need TransientStorage "alone"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used anymore, should have been deleted and I forgot it here during some rebases. Good catch,
} | ||
|
||
program.stackPush(val); | ||
// key could be returned to the pool, but transientStorageLoad semantics should be checked | ||
// to make sure storageLoad always gets a copy, not a reference. | ||
program.step(); | ||
} | ||
|
||
protected void doTSTORE(){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor comment, It would be useful (for the reviewers) to add a //TODO for the speding gas logic and static call checks etc
if (!activations.isActive(RSKIP446)) { | ||
throw Program.ExceptionHelper.invalidOpCode(program); | ||
} | ||
doTLOAD(); | ||
break; | ||
case OpCodes.OP_TSTORE: doTSTORE(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should go after the activation rule check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should. good catch!
} | ||
|
||
@Test | ||
void testTransientStorageOpcodesExecutionFailsWithRSKIPDeactivated() throws FileNotFoundException, DslProcessorException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the code the OP code call is done before the activation check, is the test working anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is working, because it fails for the other one that was fine. We can have a split test with a contract that does only TLOAD and other only TSTORE to catch these two situations, I will do.
// to make sure storageLoad always gets a copy, not a reference. | ||
program.step(); | ||
} | ||
|
||
protected void doTSTORE(){ | ||
|
||
DataWord address = program.stackPop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About the naming of this variable, shouldn't it be "key" instead of address?
import java.util.HashSet; | ||
import java.util.Iterator; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
public class MutableRepository implements Repository { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't fully understand why the transient storage is implemented into the standard storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the standard mutable storage, it's also mutable and if a transaction is not rolled back it can be reverted. As you can see, in the lifecycle of the transaction, every time it starts we create a new instance of this MutableRepository. With that, we will have the snapshot storage that can be reverted or commited in the final storage at the end but we also will have this transient storage.
The transient storage it's also mutable and the lifecycle of it it's the same for the regular mutable storage. That's why it's implemented here, for the sake of simplicity and to be managed in the same way. It will get advantage of the whole lifecycle of the mutable storage that we already have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, it is interesting point of view.
@@ -27,7 +27,7 @@ | |||
|
|||
import java.math.BigInteger; | |||
|
|||
public interface Repository extends RepositorySnapshot { | |||
public interface Repository extends RepositorySnapshot, TransientRepository { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a repository is both standard repo and transient repo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's explained a bit in the other comment here, if still not clear, let me know and I will try to explain more. Maybe we can have a call to discuss.
|
||
void addTransientStorageRow(RskAddress addr, DataWord key, DataWord value); | ||
|
||
void addTransientStorageBytes(RskAddress addr, DataWord key, byte[] value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it needed these two methods? it seems that addTransientStorageBytes is only called from addTransientStorageRow
and addTransientStorageRow it is only being used once in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After follow your suggestion, is being used twice now. Let's keep it. :)
ffa96a3
to
bfd6026
Compare
Quality Gate failedFailed conditions See analysis details on SonarCloud Catch issues before they fail your Quality Gate with our IDE extension SonarLint |
55b6728
to
e9494b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work.
My only concern is about the implementation of both transient and standard storage in the same classes. I think it could have some disadvantages. I would like to talk about it in a call but I think it is not a blocker to not continue with it.
- Adding scratch from the DSL tests and contracts for tests - The tests are still failing, I am investigating to find the root cause - Adding more logic to the map structures - Finishing test validation for basic scenarios of TLOAD/TSTORE - Now we need to add more scenarios to validate that the memory isn't shared and erased in the end of the transaction.
- In order to get advantage from the whole flow of tracking, rollback and commits already present in the MutableRepository. We refactored a bit the logic of transient storage, now it's simpler. - The task isn't done yet, more tests needs to be added to validate that this is working properly.
e9494b0
to
8bba650
Compare
f244dc2
into
fmacleal/addition_transient_storage_opcodes
* Adding the structure for transient storage opcodes - Finishing test validation for basic scenarios of TLOAD/TSTORE * Refactor from code to get advantage from the MutableRepository - In order to get advantage from the whole flow of tracking, rollback and commits already present in the MutableRepository. We refactored a bit the logic of transient storage, now it's simpler. * Adding more tests defined on the EIP-1153 spec * Adding tests for the different create contexts EIP1153 * Addressing comments from review * Adding more scenarios of test with dynamic execution context
This PR adds the basic implementation of the TLOAD/TSTORE opcodes with some DSL contracts tests. Still work in progress and more validations need to be added.
Description
Motivation and Context
How Has This Been Tested?
Types of changes
Checklist: