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 {
GlobalContext internal globalContext;
TransactionContext internal transactionContext;
MessageContext internal messageContext;
TransactionRecord internal transactionRecord;
MessageRecord internal messageRecord;
......@@ -117,6 +116,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmCALLER()
override
public
view
returns (
address _CALLER
)
......@@ -131,6 +131,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmADDRESS()
override
public
view
returns (
address _ADDRESS
)
......@@ -145,6 +146,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmORIGIN()
override
public
view
returns (
address _ORIGIN
)
......@@ -159,6 +161,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmTIMESTAMP()
override
public
view
returns (
uint256 _TIMESTAMP
)
......@@ -173,6 +176,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmGASLIMIT()
override
public
view
returns (
uint256 _GASLIMIT
)
......@@ -187,6 +191,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
function ovmCHAINID()
override
public
view
returns (
uint256 _CHAINID
)
......@@ -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 (_hasAccount(eoa) == true) {
if (_hasEmptyAccount(eoa) == false) {
return;
}
......@@ -570,7 +575,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return Lib_EthUtils.getCode(
_getAccountEthAddress(_contract),
_offset,
_length
length
);
}
......@@ -643,6 +648,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
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.
if (ovmSafetyChecker.isBytecodeSafe(_bytecode) == false) {
_revertWithFlag(RevertFlag.UNSAFE_BYTECODE);
......@@ -863,6 +876,23 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
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.
* @param _address Address of the account to modify.
......@@ -921,7 +951,10 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
)
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);
}
......@@ -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
// on the size of the contract code.
if (_wasAccountAlreadyChanged == false) {
ovmStateManager.incrementTotalUncommittedAccounts();
_useNuisanceGas(
Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE
);
......@@ -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
// "nuisance gas".
if (_wasContractStorageAlreadyChanged == false) {
ovmStateManager.incrementTotalUncommittedContractStorage();
_useNuisanceGas(NUISANCE_GAS_SSTORE);
}
}
......
......@@ -13,6 +13,13 @@ import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
*/
contract OVM_StateManager is iOVM_StateManager {
/**********************
* Contract Constants *
**********************/
bytes32 constant internal EMPTY_ACCOUNT_CODE_HASH = 0x6969696969696969696969696969696969696969696969696969696969696969;
/*******************************************
* Contract Variables: Contract References *
*******************************************/
......@@ -111,7 +118,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getAccount(address _address)
override
public
authenticated
view
returns (
Lib_OVMCodec.Account memory _account
)
......@@ -129,7 +136,7 @@ contract OVM_StateManager is iOVM_StateManager {
)
override
public
authenticated
view
returns (
bool _exists
)
......@@ -137,6 +144,24 @@ contract OVM_StateManager is iOVM_StateManager {
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.
* @param _address Address of the account to modify.
......@@ -163,7 +188,7 @@ contract OVM_StateManager is iOVM_StateManager {
)
override
public
authenticated
view
returns (
uint256 _nonce
)
......@@ -181,7 +206,7 @@ contract OVM_StateManager is iOVM_StateManager {
)
override
public
authenticated
view
returns (
address _ethAddress
)
......@@ -261,16 +286,10 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasAccountAlreadyChanged
)
{
bool wasAccountAlreadyChanged = _testAndSetItemState(
return _testAndSetItemState(
keccak256(abi.encodePacked(_address)),
ItemState.ITEM_CHANGED
);
if (!wasAccountAlreadyChanged) {
totalUncommittedAccounts += 1;
}
return wasAccountAlreadyChanged;
}
/**
......@@ -299,6 +318,17 @@ contract OVM_StateManager is iOVM_StateManager {
return true;
}
/**
* Increments the total number of uncommitted accounts.
*/
function incrementTotalUncommittedAccounts()
override
public
authenticated
{
totalUncommittedAccounts += 1;
}
/**
* Gets the total number of uncommitted accounts.
* @return _total Total uncommitted accounts.
......@@ -306,7 +336,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getTotalUncommittedAccounts()
override
public
authenticated
view
returns (
uint256 _total
)
......@@ -350,7 +380,7 @@ contract OVM_StateManager is iOVM_StateManager {
)
override
public
authenticated
view
returns (
bytes32 _value
)
......@@ -370,7 +400,7 @@ contract OVM_StateManager is iOVM_StateManager {
)
override
public
authenticated
view
returns (
bool _exists
)
......@@ -418,16 +448,10 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasContractStorageAlreadyChanged
)
{
bool wasContractStorageAlreadyChanged = _testAndSetItemState(
return _testAndSetItemState(
keccak256(abi.encodePacked(_contract, _key)),
ItemState.ITEM_CHANGED
);
if (!wasContractStorageAlreadyChanged) {
totalUncommittedContractStorage += 1;
}
return wasContractStorageAlreadyChanged;
}
/**
......@@ -458,6 +482,17 @@ contract OVM_StateManager is iOVM_StateManager {
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.
* @return _total Total uncommitted storage slots.
......@@ -465,7 +500,7 @@ contract OVM_StateManager is iOVM_StateManager {
function getTotalUncommittedContractStorage()
override
public
authenticated
view
returns (
uint256 _total
)
......
......@@ -16,7 +16,8 @@ interface iOVM_ExecutionManager {
INTENTIONAL_REVERT,
EXCEEDS_NUISANCE_GAS,
INVALID_STATE_ACCESS,
UNSAFE_BYTECODE
UNSAFE_BYTECODE,
CREATE_COLLISION
}
struct GlobalContext {
......@@ -61,12 +62,12 @@ interface iOVM_ExecutionManager {
* Context Opcodes *
*******************/
function ovmCALLER() external returns (address _caller);
function ovmADDRESS() external returns (address _address);
function ovmORIGIN() external returns (address _origin);
function ovmTIMESTAMP() external returns (uint256 _timestamp);
function ovmGASLIMIT() external returns (uint256 _gasLimit);
function ovmCHAINID() external returns (uint256 _chainId);
function ovmCALLER() external view returns (address _caller);
function ovmADDRESS() external view returns (address _address);
function ovmORIGIN() external view returns (address _origin);
function ovmTIMESTAMP() external view returns (uint256 _timestamp);
function ovmGASLIMIT() external view returns (uint256 _gasLimit);
function ovmCHAINID() external view returns (uint256 _chainId);
/*******************
......
......@@ -34,17 +34,19 @@ interface iOVM_StateManager {
************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external;
function getAccount(address _address) external returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external returns (bool _exists);
function getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account);
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 getAccountNonce(address _address) external returns (uint256 _nonce);
function getAccountEthAddress(address _address) external returns (address _ethAddress);
function getAccountNonce(address _address) external view returns (uint256 _nonce);
function getAccountEthAddress(address _address) external view returns (address _ethAddress);
function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
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 {
************************************/
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 testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded);
function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged);
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 {
});
}
/**
* Encodes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return _encoded Encoded transaction bytes.
*/
function encodeTransaction(
Transaction memory _transaction
)
......@@ -126,6 +131,11 @@ library Lib_OVMCodec {
);
}
/**
* Hashes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return _hash Hashed transaction
*/
function hashTransaction(
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