You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.
this challenge explores the fact that if a state variable is declared private, it's only hidden from other contracts (i.e., it's private within the contract's scope).
in other words, a private variable's value is still recorded in the blockchain and is open to anyone who understands how the memory is organized.
remember that public and private are visibility modifiers, while pure and view are state modifiers.
a great explanation about solidity function visibility can be found on solidity by example.
before we start, it's worth talking about the four ways the EVM stores data, depending on their context:
firstly, there is the key-value stack, where you can POP, PUSH , DUP1, or POP data.
basically, the EVM is a stack machine, as it does not operate on registers but on a virtual stack with a size limit 1024.
stack items (both keys and values) have a size of 32-bytes (or 256-bit), so the EVM is a 256-bit word machine (facilitating, for instance, keccak256 hash scheme and elliptic-curve computations).
secondly, there is the byte-array memory (RAM), used to store data during execution (such as passing arguments to internal functions).
opcodes are MSTORE, MLOAD, or MSTORE8.
third, there is the calldata (which can be accessed through msg.data), a read-only byte-addressable space for the data parameter of a transaction or call.
unlike the stack, this data is accessed by specifying the exact byte offset and the number of bytes to read.
opcdes are CALLDATACOPY, which copies a number of bytes of the transaction to memory, CALLDATASIZE, and CALLDATALOAD.
lastly, there is disk storage, a persistent read-write word-addressable space, where each contract stores persistent information (and where state variables live), and is represented by a mapping of 2^{256} slots of 32 bytes each.
the opcode SSTORE is used to store data and SLOAD to load.
contractVault {
boolpublic locked;
bytes32private password;
constructor(bytes32_password) {
locked =true;
password = _password;
}
function unlock(bytes32_password) public {
if (password == _password) {
locked =false;
}
}
}
discussion
the first thing we see in the contract is the two state variables set as private.
finally, we look at the only function in the contract: it "unlocks" locked when given the correct password:
function unlock(bytes32_password) public {
if (password == _password) {
locked =false;
}
}
there are many ways to solve this exercise, but the theory is the same: each smart contract has its own storage reflecting the state of the contract, which is divided into 32-byte slots.
a first approach is simply to call the well-known APIweb3.eth.getStorageAt(contractAddress, slotNumber), as we know the contract address and that password is on slot number 1: