Commit 7b3a9894 authored by Kelvin Fichter's avatar Kelvin Fichter

Added CREATE fix

parent 73da687e
...@@ -34,7 +34,6 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -34,7 +34,6 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
GlobalContext internal globalContext; GlobalContext internal globalContext;
TransactionContext internal transactionContext; TransactionContext internal transactionContext;
MessageContext internal messageContext; MessageContext internal messageContext;
TransactionRecord internal transactionRecord; TransactionRecord internal transactionRecord;
MessageRecord internal messageRecord; MessageRecord internal messageRecord;
...@@ -117,6 +116,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -117,6 +116,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmCALLER() function ovmCALLER()
override override
public public
view
returns ( returns (
address _CALLER address _CALLER
) )
...@@ -131,6 +131,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -131,6 +131,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmADDRESS() function ovmADDRESS()
override override
public public
view
returns ( returns (
address _ADDRESS address _ADDRESS
) )
...@@ -145,6 +146,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -145,6 +146,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmORIGIN() function ovmORIGIN()
override override
public public
view
returns ( returns (
address _ORIGIN address _ORIGIN
) )
...@@ -159,6 +161,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -159,6 +161,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmTIMESTAMP() function ovmTIMESTAMP()
override override
public public
view
returns ( returns (
uint256 _TIMESTAMP uint256 _TIMESTAMP
) )
...@@ -173,6 +176,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -173,6 +176,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmGASLIMIT() function ovmGASLIMIT()
override override
public public
view
returns ( returns (
uint256 _GASLIMIT uint256 _GASLIMIT
) )
...@@ -187,6 +191,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -187,6 +191,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmCHAINID() function ovmCHAINID()
override override
public public
view
returns ( returns (
uint256 _CHAINID uint256 _CHAINID
) )
...@@ -359,7 +364,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -359,7 +364,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
} }
// If the user already has an EOA account, then there's no need to perform this operation. // If the user already has an EOA account, then there's no need to perform this operation.
if (_hasAccount(eoa) == true) { if (_hasEmptyAccount(eoa) == false) {
return; return;
} }
...@@ -570,7 +575,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -570,7 +575,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return Lib_EthUtils.getCode( return Lib_EthUtils.getCode(
_getAccountEthAddress(_contract), _getAccountEthAddress(_contract),
_offset, _offset,
_length length
); );
} }
...@@ -643,6 +648,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -643,6 +648,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return; return;
} }
// We need to be sure that the user isn't trying to use a contract creation to overwrite
// some existing contract. On L1, users will prove that no contract exists at the address
// and the OVM_FraudVerifier will populate the code hash of this address with a special
// value that represents "known to be an empty account."
if (_hasEmptyAccount(_address) == false) {
_revertWithFlag(RevertFlag.CREATE_COLLISION);
}
// Check the creation bytecode against the OVM_SafetyChecker. // Check the creation bytecode against the OVM_SafetyChecker.
if (ovmSafetyChecker.isBytecodeSafe(_bytecode) == false) { if (ovmSafetyChecker.isBytecodeSafe(_bytecode) == false) {
_revertWithFlag(RevertFlag.UNSAFE_BYTECODE); _revertWithFlag(RevertFlag.UNSAFE_BYTECODE);
...@@ -863,6 +876,23 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -863,6 +876,23 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return ovmStateManager.hasAccount(_address); return ovmStateManager.hasAccount(_address);
} }
/**
* Checks whether a known empty account exists within the OVM_StateManager.
* @param _address Address of the account to check.
* @return _exists Whether or not the account empty exists.
*/
function _hasEmptyAccount(
address _address
)
internal
returns (
bool _exists
)
{
_checkAccountLoad(_address);
return ovmStateManager.hasEmptyAccount(_address);
}
/** /**
* Sets the nonce of an account. * Sets the nonce of an account.
* @param _address Address of the account to modify. * @param _address Address of the account to modify.
...@@ -921,7 +951,10 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -921,7 +951,10 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
) )
internal internal
{ {
_checkAccountChange(_address); // Although it seems like `_checkAccountChange` would be more appropriate here, we don't
// actually consider an account "changed" until it's inserted into the state (in this case
// by `_commitPendingAccount`).
_checkAccountLoad(_address);
ovmStateManager.initPendingAccount(_address); ovmStateManager.initPendingAccount(_address);
} }
...@@ -1034,6 +1067,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -1034,6 +1067,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
// If we hadn't already changed the account, then we'll need to charge "nuisance gas" based // If we hadn't already changed the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code. // on the size of the contract code.
if (_wasAccountAlreadyChanged == false) { if (_wasAccountAlreadyChanged == false) {
ovmStateManager.incrementTotalUncommittedAccounts();
_useNuisanceGas( _useNuisanceGas(
Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE
); );
...@@ -1092,6 +1126,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -1092,6 +1126,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
// If we hadn't already changed the account, then we'll need to charge some fixed amount of // If we hadn't already changed the account, then we'll need to charge some fixed amount of
// "nuisance gas". // "nuisance gas".
if (_wasContractStorageAlreadyChanged == false) { if (_wasContractStorageAlreadyChanged == false) {
ovmStateManager.incrementTotalUncommittedContractStorage();
_useNuisanceGas(NUISANCE_GAS_SSTORE); _useNuisanceGas(NUISANCE_GAS_SSTORE);
} }
} }
......
...@@ -13,6 +13,13 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; ...@@ -13,6 +13,13 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
*/ */
contract OVM_StateManager is iOVM_StateManager { contract OVM_StateManager is iOVM_StateManager {
/**********************
* Contract Constants *
**********************/
bytes32 constant internal EMPTY_ACCOUNT_CODE_HASH = 0x6969696969696969696969696969696969696969696969696969696969696969;
/******************************************* /*******************************************
* Contract Variables: Contract References * * Contract Variables: Contract References *
*******************************************/ *******************************************/
...@@ -111,7 +118,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -111,7 +118,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getAccount(address _address) function getAccount(address _address)
override override
public public
authenticated view
returns ( returns (
Lib_OVMCodec.Account memory _account Lib_OVMCodec.Account memory _account
) )
...@@ -129,7 +136,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -129,7 +136,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
override override
public public
authenticated view
returns ( returns (
bool _exists bool _exists
) )
...@@ -137,6 +144,24 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -137,6 +144,24 @@ contract OVM_StateManager is iOVM_StateManager {
return accounts[_address].codeHash != bytes32(0); return accounts[_address].codeHash != bytes32(0);
} }
/**
* Checks whether the state has a given known empty account.
* @param _address Address of the account to check.
* @return _exists Whether or not the state has the empty account.
*/
function hasEmptyAccount(
address _address
)
override
public
view
returns (
bool _exists
)
{
return accounts[_address].codeHash == EMPTY_ACCOUNT_CODE_HASH;
}
/** /**
* Sets the nonce of an account. * Sets the nonce of an account.
* @param _address Address of the account to modify. * @param _address Address of the account to modify.
...@@ -163,7 +188,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -163,7 +188,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
override override
public public
authenticated view
returns ( returns (
uint256 _nonce uint256 _nonce
) )
...@@ -181,7 +206,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -181,7 +206,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
override override
public public
authenticated view
returns ( returns (
address _ethAddress address _ethAddress
) )
...@@ -261,16 +286,10 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -261,16 +286,10 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasAccountAlreadyChanged bool _wasAccountAlreadyChanged
) )
{ {
bool wasAccountAlreadyChanged = _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_address)), keccak256(abi.encodePacked(_address)),
ItemState.ITEM_CHANGED ItemState.ITEM_CHANGED
); );
if (!wasAccountAlreadyChanged) {
totalUncommittedAccounts += 1;
}
return wasAccountAlreadyChanged;
} }
/** /**
...@@ -299,6 +318,17 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -299,6 +318,17 @@ contract OVM_StateManager is iOVM_StateManager {
return true; return true;
} }
/**
* Increments the total number of uncommitted accounts.
*/
function incrementTotalUncommittedAccounts()
override
public
authenticated
{
totalUncommittedAccounts += 1;
}
/** /**
* Gets the total number of uncommitted accounts. * Gets the total number of uncommitted accounts.
* @return _total Total uncommitted accounts. * @return _total Total uncommitted accounts.
...@@ -306,7 +336,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -306,7 +336,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getTotalUncommittedAccounts() function getTotalUncommittedAccounts()
override override
public public
authenticated view
returns ( returns (
uint256 _total uint256 _total
) )
...@@ -350,7 +380,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -350,7 +380,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
override override
public public
authenticated view
returns ( returns (
bytes32 _value bytes32 _value
) )
...@@ -370,7 +400,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -370,7 +400,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
override override
public public
authenticated view
returns ( returns (
bool _exists bool _exists
) )
...@@ -418,16 +448,10 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -418,16 +448,10 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasContractStorageAlreadyChanged bool _wasContractStorageAlreadyChanged
) )
{ {
bool wasContractStorageAlreadyChanged = _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_contract, _key)), keccak256(abi.encodePacked(_contract, _key)),
ItemState.ITEM_CHANGED ItemState.ITEM_CHANGED
); );
if (!wasContractStorageAlreadyChanged) {
totalUncommittedContractStorage += 1;
}
return wasContractStorageAlreadyChanged;
} }
/** /**
...@@ -458,6 +482,17 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -458,6 +482,17 @@ contract OVM_StateManager is iOVM_StateManager {
return true; return true;
} }
/**
* Increments the total number of uncommitted storage slots.
*/
function incrementTotalUncommittedContractStorage()
override
public
authenticated
{
totalUncommittedContractStorage += 1;
}
/** /**
* Gets the total number of uncommitted storage slots. * Gets the total number of uncommitted storage slots.
* @return _total Total uncommitted storage slots. * @return _total Total uncommitted storage slots.
...@@ -465,7 +500,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -465,7 +500,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getTotalUncommittedContractStorage() function getTotalUncommittedContractStorage()
override override
public public
authenticated view
returns ( returns (
uint256 _total uint256 _total
) )
......
...@@ -16,7 +16,8 @@ interface iOVM_ExecutionManager { ...@@ -16,7 +16,8 @@ interface iOVM_ExecutionManager {
INTENTIONAL_REVERT, INTENTIONAL_REVERT,
EXCEEDS_NUISANCE_GAS, EXCEEDS_NUISANCE_GAS,
INVALID_STATE_ACCESS, INVALID_STATE_ACCESS,
UNSAFE_BYTECODE UNSAFE_BYTECODE,
CREATE_COLLISION
} }
struct GlobalContext { struct GlobalContext {
...@@ -61,12 +62,12 @@ interface iOVM_ExecutionManager { ...@@ -61,12 +62,12 @@ interface iOVM_ExecutionManager {
* Context Opcodes * * Context Opcodes *
*******************/ *******************/
function ovmCALLER() external returns (address _caller); function ovmCALLER() external view returns (address _caller);
function ovmADDRESS() external returns (address _address); function ovmADDRESS() external view returns (address _address);
function ovmORIGIN() external returns (address _origin); function ovmORIGIN() external view returns (address _origin);
function ovmTIMESTAMP() external returns (uint256 _timestamp); function ovmTIMESTAMP() external view returns (uint256 _timestamp);
function ovmGASLIMIT() external returns (uint256 _gasLimit); function ovmGASLIMIT() external view returns (uint256 _gasLimit);
function ovmCHAINID() external returns (uint256 _chainId); function ovmCHAINID() external view returns (uint256 _chainId);
/******************* /*******************
......
...@@ -34,17 +34,19 @@ interface iOVM_StateManager { ...@@ -34,17 +34,19 @@ interface iOVM_StateManager {
************************************/ ************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external; function putAccount(address _address, Lib_OVMCodec.Account memory _account) external;
function getAccount(address _address) external returns (Lib_OVMCodec.Account memory _account); function getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external returns (bool _exists); function hasAccount(address _address) external view returns (bool _exists);
function hasEmptyAccount(address _address) external view returns (bool _exists);
function setAccountNonce(address _address, uint256 _nonce) external; function setAccountNonce(address _address, uint256 _nonce) external;
function getAccountNonce(address _address) external returns (uint256 _nonce); function getAccountNonce(address _address) external view returns (uint256 _nonce);
function getAccountEthAddress(address _address) external returns (address _ethAddress); function getAccountEthAddress(address _address) external view returns (address _ethAddress);
function initPendingAccount(address _address) external; function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external; function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded); function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged); function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
function commitAccount(address _address) external returns (bool _wasAccountCommitted); function commitAccount(address _address) external returns (bool _wasAccountCommitted);
function getTotalUncommittedAccounts() external returns (uint256 _total); function incrementTotalUncommittedAccounts() external;
function getTotalUncommittedAccounts() external view returns (uint256 _total);
/************************************ /************************************
...@@ -52,10 +54,11 @@ interface iOVM_StateManager { ...@@ -52,10 +54,11 @@ interface iOVM_StateManager {
************************************/ ************************************/
function putContractStorage(address _contract, bytes32 _key, bytes32 _value) external; function putContractStorage(address _contract, bytes32 _key, bytes32 _value) external;
function getContractStorage(address _contract, bytes32 _key) external returns (bytes32 _value); function getContractStorage(address _contract, bytes32 _key) external view returns (bytes32 _value);
function hasContractStorage(address _contract, bytes32 _key) external returns (bool _exists); function hasContractStorage(address _contract, bytes32 _key) external returns (bool _exists);
function testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded); function testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded);
function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged); function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged);
function commitContractStorage(address _contract, bytes32 _key) external returns (bool _wasContractStorageCommitted); function commitContractStorage(address _contract, bytes32 _key) external returns (bool _wasContractStorageCommitted);
function getTotalUncommittedContractStorage() external returns (uint256 _total); function incrementTotalUncommittedContractStorage() external;
function getTotalUncommittedContractStorage() external view returns (uint256 _total);
} }
...@@ -106,6 +106,11 @@ library Lib_OVMCodec { ...@@ -106,6 +106,11 @@ library Lib_OVMCodec {
}); });
} }
/**
* Encodes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return _encoded Encoded transaction bytes.
*/
function encodeTransaction( function encodeTransaction(
Transaction memory _transaction Transaction memory _transaction
) )
...@@ -126,6 +131,11 @@ library Lib_OVMCodec { ...@@ -126,6 +131,11 @@ library Lib_OVMCodec {
); );
} }
/**
* Hashes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return _hash Hashed transaction
*/
function hashTransaction( function hashTransaction(
Transaction memory _transaction Transaction memory _transaction
) )
......
import { expect } from '../../../setup'
describe('OVM_ECDSAContractAccount', () => {
describe('execute', () => {
describe('when provided an invalid signature', () => {
it('should revert', async () => {
})
})
describe('when provided a valid signature', () => {
describe('when provided an invalid nonce', () => {
it('should revert', async () => {
})
})
describe('when provided a valid nonce', () => {
describe('when executing ovmCREATE', () => {
it('should return the address of the created contract', async () => {
})
})
describe('when executing ovmCALL', () => {
it('should return the result of the call', async () => {
})
})
})
})
})
})
import { expect } from '../../../setup'
describe('OVM_StateTransitioner', () => {
describe('proveContractState', () => {
describe('when provided an invalid code hash', () => {
it('should revert', async () => {
})
})
describe('when provided a valid code hash', () => {
describe('when provided an invalid account inclusion proof', () => {
it('should revert', async () => {
})
})
describe('when provided a valid account inclusion proof', () => {
})
})
})
describe('proveStorageSlot', () => {
describe('when the corresponding account is not proven', () => {
it('should revert', async () => {
})
})
describe('when the corresponding account is proven', () => {
describe('when provided an invalid slot inclusion proof', () => {
it('should revert', async () => {
})
})
describe('when provided a valid slot inclusion proof', () => {
})
})
})
describe('applyTransaction', () => {
// TODO
})
describe('commitContractState', () => {
describe('when the account was not changed', () => {
it('should revert', async () => {
})
})
describe('when the account was changed', () => {
describe('when the account has not been committed', () => {
it('should commit the account and update the state', async () => {
})
})
describe('when the account was already committed', () => {
it('should revert', () => {
})
})
})
})
describe('commitStorageSlot', () => {
describe('when the slot was not changed', () => {
it('should revert', async () => {
})
})
describe('when the slot was changed', () => {
describe('when the slot has not been committed', () => {
it('should commit the slot and update the state', async () => {
})
})
describe('when the slot was already committed', () => {
it('should revert', () => {
})
})
})
})
describe('completeTransition', () => {
describe('when there are uncommitted accounts', () => {
it('should revert', async () => {
})
})
describe('when there are uncommitted storage slots', () => {
it('should revert', async () => {
})
})
describe('when all state changes are committed', () => {
})
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment