Skip to content

Commit

Permalink
more support of transient objects: work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Mar 25, 2024
1 parent ba8e5e7 commit 1f83e79
Show file tree
Hide file tree
Showing 9 changed files with 451 additions and 272 deletions.
42 changes: 26 additions & 16 deletions contracts/example.sol
Expand Up @@ -4,7 +4,7 @@ pragma solidity >0.8.25;
contract Test {
struct MyStruct {
uint256 v;
// mapping(address => uint256) m; // ERROR
mapping(address => uint256) m;
}

uint256 transient v_t;
Expand All @@ -18,24 +18,34 @@ contract Test {
mapping(address => mapping(uint256 => uint256)) transient m2_t;
mapping(address => mapping(uint256 => uint256)) m2_s;

function id() internal view returns (mapping(address => uint256) transient) {
return m_t;
}

function set(uint256 value) public {
// v_t = value;
// v_s = value;
// a_t.push(value);
// v_t += value;
// v_s += value;
// a_t.push(value); // length pushed to transient but value pushed to storage :/
// a_s.push(value);
// a_t[0] = value;
// a_s[0] = value;
// s_t.v = value;
// s_s.v = value;
// s_t.m[msg.sender] = value;
// s_s.m[msg.sender] = value;
// m_t[msg.sender] = value;
// m_s[msg.sender] = value;
// m2_t[msg.sender][0] = value;
// m2_s[msg.sender][0] = value;
// a_t[0] += value;
// a_s[0] += value;
// s_t.v += value;
// s_s.v += value;
// s_t.m[msg.sender] += value; // throw in visit
// s_s.m[msg.sender] += value; // throw in visit
// m_t[msg.sender] += value;
// m_s[msg.sender] += value;
// m2_t[msg.sender][0] += value;
// m2_s[msg.sender][0] += value;

// (true ? m_t : m_s)[msg.sender] += value; // throw in visit
// id()[msg.sender] += value; // throw in visit

// MyStruct transient s_t_ref = s_t;
// s_t_ref.v = value;

// MyStruct transient s;
// assembly { s.slot := 0 } // Error: The suffix ".slot" is not supported by this variable or type.
// s.value = value;
// assembly { s.slot := 0 }
// s.v *= value;
}
}
14 changes: 7 additions & 7 deletions libevmasm/Instruction.h
Expand Up @@ -88,9 +88,9 @@ enum class Instruction: uint8_t
GASLIMIT, ///< get the block's gas limit
CHAINID, ///< get the config's chainid param
SELFBALANCE, ///< get balance of the current account
BASEFEE, ///< get the block's basefee
BLOBHASH = 0x49, ///< get a versioned hash of one of the blobs associated with the transaction
BLOBBASEFEE = 0x4a, ///< get the block's blob basefee
BASEFEE, ///< get the block's basefee
BLOBHASH = 0x49, ///< get a versioned hash of one of the blobs associated with the transaction
BLOBBASEFEE = 0x4a, ///< get the block's blob basefee

POP = 0x50, ///< remove item from stack
MLOAD, ///< load word from memory
Expand All @@ -104,11 +104,11 @@ enum class Instruction: uint8_t
MSIZE, ///< get the size of active memory
GAS, ///< get the amount of available gas
JUMPDEST, ///< set a potential jump destination
TLOAD = 0x5c, ///< load word from transient storage
TSTORE = 0x5d, ///< save word to transient storage
MCOPY = 0x5e, ///< copy between memory areas
TLOAD = 0x5c, ///< load word from transient storage
TSTORE = 0x5d, ///< save word to transient storage
MCOPY = 0x5e, ///< copy between memory areas

PUSH0 = 0x5f, ///< place the value 0 on stack
PUSH0 = 0x5f, ///< place the value 0 on stack
PUSH1 = 0x60, ///< place 1 byte item on stack
PUSH2, ///< place 2 byte item on stack
PUSH3, ///< place 3 byte item on stack
Expand Down
25 changes: 18 additions & 7 deletions libsolidity/analysis/TypeChecker.cpp
Expand Up @@ -106,6 +106,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
return false;
}

// [Amxx] TODO: transient?
void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
{
size_t storageToStorageCopies = 0;
Expand Down Expand Up @@ -261,7 +262,8 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
actualType = TypeProvider::payableAddress();
solAssert(
!actualType->dataStoredIn(DataLocation::CallData) &&
!actualType->dataStoredIn(DataLocation::Storage),
!actualType->dataStoredIn(DataLocation::Storage) &&
!actualType->dataStoredIn(DataLocation::Transient),
""
);
if (!actualType->fullEncodingType(false, _abiEncoderV2, false))
Expand Down Expand Up @@ -674,7 +676,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
BoolResult result = referenceType->validForLocation(referenceType->location());
if (result)
{
bool isLibraryStorageParameter = (_variable.isLibraryFunctionParameter() && referenceType->location() == DataLocation::Storage);
bool isLibraryStorageParameter = (_variable.isLibraryFunctionParameter() && (referenceType->location() == DataLocation::Storage || referenceType->location() == DataLocation::Transient));
// We skip the calldata check for abstract contract constructors.
bool isAbstractConstructorParam = _variable.isConstructorParameter() && m_currentContract && m_currentContract->abstract();
bool callDataCheckRequired =
Expand Down Expand Up @@ -921,7 +923,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
std::string const& suffix = identifierInfo.suffix;
solAssert((std::set<std::string>{"offset", "slot", "length", "selector", "address"}).count(suffix), "");
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage)))
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage) || var->type()->dataStoredIn(DataLocation::Transient)))
{
if (suffix != "slot" && suffix != "offset")
{
Expand Down Expand Up @@ -985,6 +987,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
m_errorReporter.typeError(9068_error, nativeLocationOf(_identifier), "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables.");
return false;
}
else if (var->type()->dataStoredIn(DataLocation::Transient))
{
m_errorReporter.typeError(9068_error, nativeLocationOf(_identifier), "You have to use the \".slot\" or \".offset\" suffix to access transient reference variables.");
return false;
}
else if (var->type()->sizeOnStack() != 1)
{
Expand Down Expand Up @@ -1987,13 +1994,17 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
{
if (auto resultArrayType = dynamic_cast<ArrayType const*>(resultType))
solAssert(
argArrayType->location() != DataLocation::Storage ||
(
argArrayType->location() != DataLocation::Storage &&
argArrayType->location() != DataLocation::Transient
) || (
(
resultArrayType->isPointer() ||
(argArrayType->isByteArrayOrString() && resultArrayType->isByteArrayOrString())
) &&
resultArrayType->location() == DataLocation::Storage
) && (
resultArrayType->location() == DataLocation::Storage ||
resultArrayType->location() == DataLocation::Transient
)
),
"Invalid explicit conversion to storage type."
);
Expand Down Expand Up @@ -3201,7 +3212,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
_memberAccess.location(),
"Member \"" + memberName + "\" is not available in " +
exprType->humanReadableName() +
" outside of storage."
" outside of storage." // TODO: mention transient storage explicitelly?
);
}

Expand Down

0 comments on commit 1f83e79

Please sign in to comment.