Commit 1e438d4b authored by Kelvin Fichter's avatar Kelvin Fichter Committed by GitHub

Various fixes found while working on the fraud proving service (#97)

* Hotfix for decoding rlp values in state transitioner

* Fix for empty code hash and storage roots

* Experimenting with sequencer entrypoint

* We may have messed up nuisance gas

* Changed how we verify keys

* Pad left in state transitioner

* Added some experimental stuff

* Add simplifications for state transitioner

* Further simplifications

* Fix for execution manager

* A few optimizations

* Experimental fixes

* Temporarily change gas limit

* Temp tx index fix

* Fixed bug for generating single-node root hashes

* Add events to state transitioner

* Added revert messages to st

* Added some logging to debug

* Removed console.log in execution manager

* Fixed tests, linted

* Remove gas metering

* Have init set storage root

* Fixed account encoding

* Fix for when storage values do not change

* Added remaining fixes

* Tweaks as per review

* Another sm fix

* More sm fixes

* Fixes in the state manager

* Added more comments

* Fix compilation error

* Another compilation error

* Minor fixes re: review
parent d40468c1
...@@ -3,3 +3,4 @@ artifacts/ ...@@ -3,3 +3,4 @@ artifacts/
cache/ cache/
yarn-error.log yarn-error.log
build/ build/
.DS_STORE
...@@ -434,6 +434,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -434,6 +434,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
} }
} }
/********************** /**********************
* Internal Functions * * Internal Functions *
**********************/ **********************/
......
...@@ -155,8 +155,13 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -155,8 +155,13 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
"Only authenticated addresses in ovmStateManager can call this function" "Only authenticated addresses in ovmStateManager can call this function"
); );
// Check whether we need to start a new epoch, do so if necessary. // Initialize the execution context, must be initialized before we perform any gas metering
_checkNeedsNewEpoch(_transaction.timestamp); // or we'll throw a nuisance gas error.
_initContext(_transaction);
// TEMPORARY: Gas metering is disabled for minnet.
// // Check whether we need to start a new epoch, do so if necessary.
// _checkNeedsNewEpoch(_transaction.timestamp);
// Make sure the transaction's gas limit is valid. We don't revert here because we reserve // Make sure the transaction's gas limit is valid. We don't revert here because we reserve
// reverts for INVALID_STATE_ACCESS. // reverts for INVALID_STATE_ACCESS.
...@@ -164,9 +169,6 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -164,9 +169,6 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
return; return;
} }
// Initialize the execution context.
_initContext(_transaction);
// Run the transaction, make sure to meter the gas usage. // Run the transaction, make sure to meter the gas usage.
uint256 gasProvided = gasleft(); uint256 gasProvided = gasleft();
ovmCALL( ovmCALL(
...@@ -176,8 +178,9 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -176,8 +178,9 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
); );
uint256 gasUsed = gasProvided - gasleft(); uint256 gasUsed = gasProvided - gasleft();
// Update the cumulative gas based on the amount of gas used. // TEMPORARY: Gas metering is disabled for minnet.
_updateCumulativeGas(gasUsed, _transaction.l1QueueOrigin); // // Update the cumulative gas based on the amount of gas used.
// _updateCumulativeGas(gasUsed, _transaction.l1QueueOrigin);
// Wipe the execution context. // Wipe the execution context.
_resetContext(); _resetContext();
...@@ -498,6 +501,8 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -498,6 +501,8 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
address(proxyEOA), address(proxyEOA),
keccak256(Lib_EthUtils.getCode(address(proxyEOA))) keccak256(Lib_EthUtils.getCode(address(proxyEOA)))
); );
// TODO: Set account nonce to zero here (changing in a different PR for auditor convenience).
} }
...@@ -823,6 +828,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -823,6 +828,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
); );
} }
/*************************************** /***************************************
* Public Functions: Execution Context * * Public Functions: Execution Context *
***************************************/ ***************************************/
...@@ -1185,6 +1191,15 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -1185,6 +1191,15 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
) )
internal internal
{ {
// We don't set storage if the value didn't change. Although this acts as a convenient
// optimization, it's also necessary to avoid the case in which a contract with no storage
// attempts to store the value "0" at any key. Putting this value (and therefore requiring
// that the value be committed into the storage trie after execution) would incorrectly
// modify the storage root.
if (_getContractStorage(_contract, _key) == _value) {
return;
}
_checkContractStorageChange(_contract, _key); _checkContractStorageChange(_contract, _key);
ovmStateManager.putContractStorage(_contract, _key, _value); ovmStateManager.putContractStorage(_contract, _key, _value);
} }
...@@ -1234,13 +1249,17 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -1234,13 +1249,17 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
) )
internal internal
{ {
// Start by checking for a load as we only want to charge nuisance gas proportional to
// contract size once.
_checkAccountLoad(_address);
// Check whether the account has been changed before and mark it as changed if not. We need // Check whether the account has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that an account is changed. // this because "nuisance gas" only applies to the first time that an account is changed.
( (
bool _wasAccountAlreadyChanged bool _wasAccountAlreadyChanged
) = ovmStateManager.testAndSetAccountChanged(_address); ) = ovmStateManager.testAndSetAccountChanged(_address);
// If we hadn't already changed the account, then we'll need to charge "nuisance gas" based // If we hadn't already loaded 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(); ovmStateManager.incrementTotalUncommittedAccounts();
...@@ -1304,15 +1323,9 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -1304,15 +1323,9 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
) )
internal internal
{ {
// See `_checkContractStorageLoad` for more information. // Start by checking for load to make sure we have the storage slot and that we charge the
if (gasleft() < MIN_GAS_FOR_INVALID_STATE_ACCESS) { // "nuisance gas" necessary to prove the storage slot state.
_revertWithFlag(RevertFlag.OUT_OF_GAS); _checkContractStorageLoad(_contract, _key);
}
// See `_checkContractStorageLoad` for more information.
if (ovmStateManager.hasContractStorage(_contract, _key) == false) {
_revertWithFlag(RevertFlag.INVALID_STATE_ACCESS);
}
// Check whether the slot has been changed before and mark it as changed if not. We need // Check whether the slot has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that a slot is changed. // this because "nuisance gas" only applies to the first time that a slot is changed.
...@@ -1323,6 +1336,10 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -1323,6 +1336,10 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
// 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) {
// Changing a storage slot means that we're also going to have to change the
// corresponding account, so do an account change check.
_checkAccountChange(_contract);
ovmStateManager.incrementTotalUncommittedContractStorage(); ovmStateManager.incrementTotalUncommittedContractStorage();
_useNuisanceGas(NUISANCE_GAS_SSTORE); _useNuisanceGas(NUISANCE_GAS_SSTORE);
} }
...@@ -1572,23 +1589,25 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver { ...@@ -1572,23 +1589,25 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
return false; return false;
} }
GasMetadataKey cumulativeGasKey; // TEMPORARY: Gas metering is disabled for minnet.
GasMetadataKey prevEpochGasKey; return true;
if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) { // GasMetadataKey cumulativeGasKey;
cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS; // GasMetadataKey prevEpochGasKey;
prevEpochGasKey = GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS; // if (_queueOrigin == Lib_OVMCodec.QueueOrigin.SEQUENCER_QUEUE) {
} else { // cumulativeGasKey = GasMetadataKey.CUMULATIVE_SEQUENCER_QUEUE_GAS;
cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS; // prevEpochGasKey = GasMetadataKey.PREV_EPOCH_SEQUENCER_QUEUE_GAS;
prevEpochGasKey = GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS; // } else {
} // cumulativeGasKey = GasMetadataKey.CUMULATIVE_L1TOL2_QUEUE_GAS;
// prevEpochGasKey = GasMetadataKey.PREV_EPOCH_L1TOL2_QUEUE_GAS;
return ( // }
(
_getGasMetadata(cumulativeGasKey) // return (
- _getGasMetadata(prevEpochGasKey) // (
+ _gasLimit // _getGasMetadata(cumulativeGasKey)
) < gasMeterConfig.maxGasPerQueuePerEpoch // - _getGasMetadata(prevEpochGasKey)
); // + _gasLimit
// ) < gasMeterConfig.maxGasPerQueuePerEpoch
// );
} }
/** /**
......
...@@ -17,8 +17,9 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -17,8 +17,9 @@ contract OVM_StateManager is iOVM_StateManager {
* Contract Constants * * Contract Constants *
**********************/ **********************/
bytes32 constant internal EMPTY_ACCOUNT_CODE_HASH = 0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000; bytes32 constant internal EMPTY_ACCOUNT_STORAGE_ROOT = 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421;
bytes32 constant internal STORAGE_XOR_VALUE = 0xFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEF; bytes32 constant internal EMPTY_ACCOUNT_CODE_HASH = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
bytes32 constant internal STORAGE_XOR_VALUE = 0xFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEF;
/******************************************* /*******************************************
...@@ -137,7 +138,9 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -137,7 +138,9 @@ contract OVM_StateManager is iOVM_StateManager {
public public
authenticated authenticated
{ {
accounts[_address].codeHash = EMPTY_ACCOUNT_CODE_HASH; Lib_OVMCodec.Account storage account = accounts[_address];
account.storageRoot = EMPTY_ACCOUNT_STORAGE_ROOT;
account.codeHash = EMPTY_ACCOUNT_CODE_HASH;
} }
/** /**
...@@ -189,7 +192,10 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -189,7 +192,10 @@ contract OVM_StateManager is iOVM_StateManager {
bool _exists bool _exists
) )
{ {
return accounts[_address].codeHash == EMPTY_ACCOUNT_CODE_HASH; return (
accounts[_address].codeHash == EMPTY_ACCOUNT_CODE_HASH
&& accounts[_address].nonce == 0
);
} }
/** /**
...@@ -275,7 +281,8 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -275,7 +281,8 @@ contract OVM_StateManager is iOVM_StateManager {
{ {
Lib_OVMCodec.Account storage account = accounts[_address]; Lib_OVMCodec.Account storage account = accounts[_address];
account.nonce = 1; account.nonce = 1;
account.codeHash = keccak256(hex''); account.storageRoot = EMPTY_ACCOUNT_STORAGE_ROOT;
account.codeHash = EMPTY_ACCOUNT_CODE_HASH;
account.isFresh = true; account.isFresh = true;
} }
...@@ -315,7 +322,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -315,7 +322,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
{ {
return _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_address)), _getItemHash(_address),
ItemState.ITEM_LOADED ItemState.ITEM_LOADED
); );
} }
...@@ -336,7 +343,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -336,7 +343,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
{ {
return _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_address)), _getItemHash(_address),
ItemState.ITEM_CHANGED ItemState.ITEM_CHANGED
); );
} }
...@@ -356,7 +363,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -356,7 +363,7 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasAccountCommitted bool _wasAccountCommitted
) )
{ {
bytes32 item = keccak256(abi.encodePacked(_address)); bytes32 item = _getItemHash(_address);
if (itemStates[item] != ItemState.ITEM_CHANGED) { if (itemStates[item] != ItemState.ITEM_CHANGED) {
return false; return false;
} }
...@@ -392,7 +399,45 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -392,7 +399,45 @@ contract OVM_StateManager is iOVM_StateManager {
{ {
return totalUncommittedAccounts; return totalUncommittedAccounts;
} }
/**
* Checks whether a given account was changed during execution.
* @param _address Address to check.
* @return Whether or not the account was changed.
*/
function wasAccountChanged(
address _address
)
override
public
view
returns (
bool
)
{
bytes32 item = _getItemHash(_address);
return itemStates[item] >= ItemState.ITEM_CHANGED;
}
/**
* Checks whether a given account was committed after execution.
* @param _address Address to check.
* @return Whether or not the account was committed.
*/
function wasAccountCommitted(
address _address
)
override
public
view
returns (
bool
)
{
bytes32 item = _getItemHash(_address);
return itemStates[item] >= ItemState.ITEM_COMMITTED;
}
/************************************ /************************************
* Public Functions: Storage Access * * Public Functions: Storage Access *
...@@ -496,7 +541,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -496,7 +541,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
{ {
return _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_contract, _key)), _getItemHash(_contract, _key),
ItemState.ITEM_LOADED ItemState.ITEM_LOADED
); );
} }
...@@ -519,7 +564,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -519,7 +564,7 @@ contract OVM_StateManager is iOVM_StateManager {
) )
{ {
return _testAndSetItemState( return _testAndSetItemState(
keccak256(abi.encodePacked(_contract, _key)), _getItemHash(_contract, _key),
ItemState.ITEM_CHANGED ItemState.ITEM_CHANGED
); );
} }
...@@ -541,7 +586,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -541,7 +586,7 @@ contract OVM_StateManager is iOVM_StateManager {
bool _wasContractStorageCommitted bool _wasContractStorageCommitted
) )
{ {
bytes32 item = keccak256(abi.encodePacked(_contract, _key)); bytes32 item = _getItemHash(_contract, _key);
if (itemStates[item] != ItemState.ITEM_CHANGED) { if (itemStates[item] != ItemState.ITEM_CHANGED) {
return false; return false;
} }
...@@ -578,11 +623,92 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -578,11 +623,92 @@ contract OVM_StateManager is iOVM_StateManager {
return totalUncommittedContractStorage; return totalUncommittedContractStorage;
} }
/**
* Checks whether a given storage slot was changed during execution.
* @param _contract Address to check.
* @param _key Key of the storage slot to check.
* @return Whether or not the storage slot was changed.
*/
function wasContractStorageChanged(
address _contract,
bytes32 _key
)
override
public
view
returns (
bool
)
{
bytes32 item = _getItemHash(_contract, _key);
return itemStates[item] >= ItemState.ITEM_CHANGED;
}
/**
* Checks whether a given storage slot was committed after execution.
* @param _contract Address to check.
* @param _key Key of the storage slot to check.
* @return Whether or not the storage slot was committed.
*/
function wasContractStorageCommitted(
address _contract,
bytes32 _key
)
override
public
view
returns (
bool
)
{
bytes32 item = _getItemHash(_contract, _key);
return itemStates[item] >= ItemState.ITEM_COMMITTED;
}
/********************** /**********************
* Internal Functions * * Internal Functions *
**********************/ **********************/
/**
* Generates a unique hash for an address.
* @param _address Address to generate a hash for.
* @return Unique hash for the given address.
*/
function _getItemHash(
address _address
)
internal
pure
returns (
bytes32
)
{
return keccak256(abi.encodePacked(_address));
}
/**
* Generates a unique hash for an address/key pair.
* @param _contract Address to generate a hash for.
* @param _key Key to generate a hash for.
* @return Unique hash for the given pair.
*/
function _getItemHash(
address _contract,
bytes32 _key
)
internal
pure
returns (
bytes32
)
{
return keccak256(abi.encodePacked(
_contract,
_key
));
}
/** /**
* Checks whether an item is in a particular state (ITEM_LOADED or ITEM_CHANGED) and sets the * Checks whether an item is in a particular state (ITEM_LOADED or ITEM_CHANGED) and sets the
* item to the provided state if not. * item to the provided state if not.
......
...@@ -44,7 +44,7 @@ contract OVM_SequencerEntrypoint { ...@@ -44,7 +44,7 @@ contract OVM_SequencerEntrypoint {
bytes32 r = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 1, 32)); bytes32 r = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 1, 32));
bytes32 s = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 33, 32)); bytes32 s = Lib_BytesUtils.toBytes32(Lib_BytesUtils.slice(msg.data, 33, 32));
uint8 v = Lib_BytesUtils.toUint8(msg.data, 65); uint8 v = Lib_BytesUtils.toUint8(msg.data, 65);
// Remainder is the transaction to execute. // Remainder is the transaction to execute.
bytes memory compressedTx = Lib_BytesUtils.slice(msg.data, 66); bytes memory compressedTx = Lib_BytesUtils.slice(msg.data, 66);
bool isEthSignedMessage = transactionType == TransactionType.ETH_SIGNED_MESSAGE; bool isEthSignedMessage = transactionType == TransactionType.ETH_SIGNED_MESSAGE;
......
...@@ -122,23 +122,11 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr ...@@ -122,23 +122,11 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr
); );
require ( require (
_preStateRootBatchHeader.prevTotalElements + _preStateRootProof.index == _transactionBatchHeader.prevTotalElements + _transactionProof.index, _preStateRootBatchHeader.prevTotalElements + _preStateRootProof.index + 1 == _transactionBatchHeader.prevTotalElements + _transactionProof.index,
"Pre-state root global index must equal to the transaction root global index." "Pre-state root global index must equal to the transaction root global index."
); );
deployTransitioner(_preStateRoot, _txHash, _preStateRootProof.index); _deployTransitioner(_preStateRoot, _txHash, _preStateRootProof.index);
}
// NB: Stack too deep :/
function deployTransitioner(bytes32 _preStateRoot, bytes32 _txHash, uint256 _stateTransitionIndex) private {
transitioners[keccak256(abi.encodePacked(_preStateRoot, _txHash))] = iOVM_StateTransitionerFactory(
resolve("OVM_StateTransitionerFactory")
).create(
address(libAddressManager),
_stateTransitionIndex,
_preStateRoot,
_txHash
);
} }
/** /**
...@@ -201,31 +189,11 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr ...@@ -201,31 +189,11 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr
_postStateRoot != transitioner.getPostStateRoot(), _postStateRoot != transitioner.getPostStateRoot(),
"State transition has not been proven fraudulent." "State transition has not been proven fraudulent."
); );
_cancelStateTransition(_postStateRootBatchHeader, _preStateRoot);
cancelStateTransition(_postStateRootBatchHeader, _preStateRoot); // TEMPORARY: Remove the transitioner; for minnet.
} transitioners[keccak256(abi.encodePacked(_preStateRoot, _txHash))] = iOVM_StateTransitioner(0x0000000000000000000000000000000000000000);
// NB: Stack too deep :/
function cancelStateTransition(
Lib_OVMCodec.ChainBatchHeader memory _postStateRootBatchHeader,
bytes32 _preStateRoot
) private {
iOVM_StateCommitmentChain ovmStateCommitmentChain = iOVM_StateCommitmentChain(resolve("OVM_StateCommitmentChain"));
iOVM_BondManager ovmBondManager = iOVM_BondManager(resolve("OVM_BondManager"));
// delete the state batch
ovmStateCommitmentChain.deleteStateBatch(
_postStateRootBatchHeader
);
// Get the timestamp and publisher for that block
(uint256 timestamp, address publisher) = abi.decode(_postStateRootBatchHeader.extraData, (uint256, address));
// slash the bonds at the bond manager
ovmBondManager.finalize(
_preStateRoot,
publisher,
timestamp
);
} }
...@@ -250,4 +218,57 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr ...@@ -250,4 +218,57 @@ contract OVM_FraudVerifier is Lib_AddressResolver, OVM_FraudContributor, iOVM_Fr
{ {
return address(getStateTransitioner(_preStateRoot, _txHash)) != address(0); return address(getStateTransitioner(_preStateRoot, _txHash)) != address(0);
} }
/**
* Deploys a new state transitioner.
* @param _preStateRoot Pre-state root to initialize the transitioner with.
* @param _txHash Hash of the transaction this transitioner will execute.
* @param _stateTransitionIndex Index of the transaction in the chain.
*/
function _deployTransitioner(
bytes32 _preStateRoot,
bytes32 _txHash,
uint256 _stateTransitionIndex
)
internal
{
transitioners[keccak256(abi.encodePacked(_preStateRoot, _txHash))] = iOVM_StateTransitionerFactory(
resolve("OVM_StateTransitionerFactory")
).create(
address(libAddressManager),
_stateTransitionIndex,
_preStateRoot,
_txHash
);
}
/**
* Removes a state transition from the state commitment chain.
* @param _postStateRootBatchHeader Header for the post-state root.
* @param _preStateRoot Pre-state root hash.
*/
function _cancelStateTransition(
Lib_OVMCodec.ChainBatchHeader memory _postStateRootBatchHeader,
bytes32 _preStateRoot
)
internal
{
iOVM_StateCommitmentChain ovmStateCommitmentChain = iOVM_StateCommitmentChain(resolve("OVM_StateCommitmentChain"));
iOVM_BondManager ovmBondManager = iOVM_BondManager(resolve("OVM_BondManager"));
// Delete the state batch.
ovmStateCommitmentChain.deleteStateBatch(
_postStateRootBatchHeader
);
// Get the timestamp and publisher for that block.
(uint256 timestamp, address publisher) = abi.decode(_postStateRootBatchHeader.extraData, (uint256, address));
// Slash the bonds at the bond manager.
ovmBondManager.finalize(
_preStateRoot,
publisher,
timestamp
);
}
} }
...@@ -56,6 +56,8 @@ interface iOVM_StateManager { ...@@ -56,6 +56,8 @@ interface iOVM_StateManager {
function commitAccount(address _address) external returns (bool _wasAccountCommitted); function commitAccount(address _address) external returns (bool _wasAccountCommitted);
function incrementTotalUncommittedAccounts() external; function incrementTotalUncommittedAccounts() external;
function getTotalUncommittedAccounts() external view returns (uint256 _total); function getTotalUncommittedAccounts() external view returns (uint256 _total);
function wasAccountChanged(address _address) external view returns (bool);
function wasAccountCommitted(address _address) external view returns (bool);
/************************************ /************************************
...@@ -70,4 +72,6 @@ interface iOVM_StateManager { ...@@ -70,4 +72,6 @@ interface iOVM_StateManager {
function commitContractStorage(address _contract, bytes32 _key) external returns (bool _wasContractStorageCommitted); function commitContractStorage(address _contract, bytes32 _key) external returns (bool _wasContractStorageCommitted);
function incrementTotalUncommittedContractStorage() external; function incrementTotalUncommittedContractStorage() external;
function getTotalUncommittedContractStorage() external view returns (uint256 _total); function getTotalUncommittedContractStorage() external view returns (uint256 _total);
function wasContractStorageChanged(address _contract, bytes32 _key) external view returns (bool);
function wasContractStorageCommitted(address _contract, bytes32 _key) external view returns (bool);
} }
...@@ -10,6 +10,20 @@ import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; ...@@ -10,6 +10,20 @@ import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
*/ */
interface iOVM_StateTransitioner { interface iOVM_StateTransitioner {
/**********
* Events *
**********/
event AccountCommitted(
address _address
);
event ContractStorageCommitted(
address _address,
bytes32 _key
);
/********************************** /**********************************
* Public Functions: State Access * * Public Functions: State Access *
**********************************/ **********************************/
...@@ -26,19 +40,12 @@ interface iOVM_StateTransitioner { ...@@ -26,19 +40,12 @@ interface iOVM_StateTransitioner {
function proveContractState( function proveContractState(
address _ovmContractAddress, address _ovmContractAddress,
address _ethContractAddress, address _ethContractAddress,
Lib_OVMCodec.EVMAccount calldata _account,
bytes calldata _stateTrieWitness
) external;
function proveEmptyContractState(
address _ovmContractAddress,
bytes calldata _stateTrieWitness bytes calldata _stateTrieWitness
) external; ) external;
function proveStorageSlot( function proveStorageSlot(
address _ovmContractAddress, address _ovmContractAddress,
bytes32 _key, bytes32 _key,
bytes32 _value,
bytes calldata _storageTrieWitness bytes calldata _storageTrieWitness
) external; ) external;
...@@ -64,7 +71,6 @@ interface iOVM_StateTransitioner { ...@@ -64,7 +71,6 @@ interface iOVM_StateTransitioner {
function commitStorageSlot( function commitStorageSlot(
address _ovmContractAddress, address _ovmContractAddress,
bytes32 _key, bytes32 _key,
bytes calldata _stateTrieWitness,
bytes calldata _storageTrieWitness bytes calldata _storageTrieWitness
) external; ) external;
......
...@@ -6,6 +6,7 @@ pragma experimental ABIEncoderV2; ...@@ -6,6 +6,7 @@ pragma experimental ABIEncoderV2;
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol"; import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol"; import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol"; import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
/** /**
* @title Lib_OVMCodec * @title Lib_OVMCodec
...@@ -315,8 +316,16 @@ library Lib_OVMCodec { ...@@ -315,8 +316,16 @@ library Lib_OVMCodec {
// Unfortunately we can't create this array outright because // Unfortunately we can't create this array outright because
// RLPWriter.encodeList will reject fixed-size arrays. Assigning // RLPWriter.encodeList will reject fixed-size arrays. Assigning
// index-by-index circumvents this issue. // index-by-index circumvents this issue.
raw[0] = Lib_RLPWriter.writeUint(_account.nonce); raw[0] = Lib_RLPWriter.writeBytes(
raw[1] = Lib_RLPWriter.writeUint(_account.balance); Lib_Bytes32Utils.removeLeadingZeros(
bytes32(_account.nonce)
)
);
raw[1] = Lib_RLPWriter.writeBytes(
Lib_Bytes32Utils.removeLeadingZeros(
bytes32(_account.balance)
)
);
raw[2] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.storageRoot)); raw[2] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.storageRoot));
raw[3] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.codeHash)); raw[3] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.codeHash));
......
...@@ -145,9 +145,7 @@ library Lib_MerkleTrie { ...@@ -145,9 +145,7 @@ library Lib_MerkleTrie {
{ {
// Special case when inserting the very first node. // Special case when inserting the very first node.
if (_root == KECCAK256_RLP_NULL_BYTES) { if (_root == KECCAK256_RLP_NULL_BYTES) {
return keccak256( return getSingleNodeRootHash(_key, _value);
_makeLeafNode(_key, _value).encoded
);
} }
TrieNode[] memory proof = _parseProof(_proof); TrieNode[] memory proof = _parseProof(_proof);
...@@ -212,7 +210,7 @@ library Lib_MerkleTrie { ...@@ -212,7 +210,7 @@ library Lib_MerkleTrie {
) )
{ {
return keccak256(_makeLeafNode( return keccak256(_makeLeafNode(
_key, Lib_BytesUtils.toNibbles(_key),
_value _value
).encoded); ).encoded);
} }
......
...@@ -57,4 +57,36 @@ library Lib_Bytes32Utils { ...@@ -57,4 +57,36 @@ library Lib_Bytes32Utils {
{ {
return bytes32(uint256(_in)); return bytes32(uint256(_in));
} }
function removeLeadingZeros(
bytes32 _in
)
internal
pure
returns (
bytes memory _out
)
{
bytes memory out;
assembly {
// Figure out how many leading zero bytes to remove.
let shift := 0
for { let i := 0 } and(lt(i, 32), eq(byte(i, _in), 0)) { i := add(i, 1) } {
shift := add(shift, 1)
}
// Reserve some space for our output and fix the free memory pointer.
out := mload(0x40)
mstore(0x40, add(out, 0x40))
// Shift the value and store it into the output bytes.
mstore(add(out, 0x20), shl(mul(shift, 8), _in))
// Store the new size (with leading zero bytes removed) in the output byte size.
mstore(out, sub(32, shift))
}
return out;
}
} }
...@@ -170,6 +170,21 @@ library Lib_BytesUtils { ...@@ -170,6 +170,21 @@ library Lib_BytesUtils {
return slice(_bytes, _start, _bytes.length - _start); return slice(_bytes, _start, _bytes.length - _start);
} }
function toBytes32PadLeft(
bytes memory _bytes
)
internal
pure
returns (bytes32)
{
bytes32 ret;
uint256 len = _bytes.length <= 32 ? _bytes.length : 32;
assembly {
ret := shr(mul(sub(32, len), 8), mload(add(_bytes, 32)))
}
return ret;
}
function toBytes32( function toBytes32(
bytes memory _bytes bytes memory _bytes
) )
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
"test:gas": "buidler test \"test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts\" --no-compile --show-stack-traces", "test:gas": "buidler test \"test/contracts/OVM/execution/OVM_StateManager.gas-spec.ts\" --no-compile --show-stack-traces",
"lint": "yarn run lint:typescript", "lint": "yarn run lint:typescript",
"lint:typescript": "tslint --format stylish --project .", "lint:typescript": "tslint --format stylish --project .",
"lint:fix": "yarn run lint:fix:typescript",
"lint:fix:typescript": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"", "lint:fix:typescript": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"",
"clean": "rm -rf ./artifacts ./build ./cache", "clean": "rm -rf ./artifacts ./build ./cache",
"deploy": "./bin/deploy.js" "deploy": "./bin/deploy.js"
......
...@@ -25,8 +25,11 @@ const callPrecompile = async ( ...@@ -25,8 +25,11 @@ const callPrecompile = async (
if (gasLimit) { if (gasLimit) {
return Helper_PrecompileCaller.callPrecompile( return Helper_PrecompileCaller.callPrecompile(
precompile.address, precompile.address,
precompile.interface.encodeFunctionData(functionName, functionParams || []), precompile.interface.encodeFunctionData(
{gasLimit} functionName,
functionParams || []
),
{ gasLimit }
) )
} }
return Helper_PrecompileCaller.callPrecompile( return Helper_PrecompileCaller.callPrecompile(
...@@ -187,7 +190,7 @@ describe('OVM_ECDSAContractAccount', () => { ...@@ -187,7 +190,7 @@ describe('OVM_ECDSAContractAccount', () => {
it(`should revert on incorrect nonce`, async () => { it(`should revert on incorrect nonce`, async () => {
const alteredNonceTx = { const alteredNonceTx = {
...DEFAULT_EIP155_TX, ...DEFAULT_EIP155_TX,
nonce : 99 nonce: 99,
} }
const message = serializeNativeTransaction(alteredNonceTx) const message = serializeNativeTransaction(alteredNonceTx)
const sig = await signNativeTransaction(wallet, alteredNonceTx) const sig = await signNativeTransaction(wallet, alteredNonceTx)
...@@ -241,7 +244,7 @@ describe('OVM_ECDSAContractAccount', () => { ...@@ -241,7 +244,7 @@ describe('OVM_ECDSAContractAccount', () => {
it(`should revert on insufficient gas`, async () => { it(`should revert on insufficient gas`, async () => {
const alteredInsufficientGasTx = { const alteredInsufficientGasTx = {
...DEFAULT_EIP155_TX, ...DEFAULT_EIP155_TX,
gasLimit : 200000000 gasLimit: 200000000,
} }
const message = serializeNativeTransaction(alteredInsufficientGasTx) const message = serializeNativeTransaction(alteredInsufficientGasTx)
const sig = await signNativeTransaction(wallet, alteredInsufficientGasTx) const sig = await signNativeTransaction(wallet, alteredInsufficientGasTx)
...@@ -257,7 +260,7 @@ describe('OVM_ECDSAContractAccount', () => { ...@@ -257,7 +260,7 @@ describe('OVM_ECDSAContractAccount', () => {
`0x${sig.r}`, //r `0x${sig.r}`, //r
`0x${sig.s}`, //s `0x${sig.s}`, //s
], ],
40000000, 40000000
) )
const ovmREVERT: any = const ovmREVERT: any =
......
...@@ -188,6 +188,7 @@ describe('OVM_StateManager', () => { ...@@ -188,6 +188,7 @@ describe('OVM_StateManager', () => {
beforeEach(async () => { beforeEach(async () => {
await OVM_StateManager.putAccount(DUMMY_ACCOUNTS[0].address, { await OVM_StateManager.putAccount(DUMMY_ACCOUNTS[0].address, {
...DUMMY_ACCOUNTS[0].data, ...DUMMY_ACCOUNTS[0].data,
nonce: 0,
codeHash: EMPTY_ACCOUNT_CODE_HASH, codeHash: EMPTY_ACCOUNT_CODE_HASH,
}) })
}) })
......
...@@ -179,7 +179,10 @@ describe('OVM_FraudVerifier', () => { ...@@ -179,7 +179,10 @@ describe('OVM_FraudVerifier', () => {
DUMMY_OVM_TRANSACTIONS[0], DUMMY_OVM_TRANSACTIONS[0],
DUMMY_TX_CHAIN_ELEMENTS[0], DUMMY_TX_CHAIN_ELEMENTS[0],
DUMMY_BATCH_HEADERS[0], DUMMY_BATCH_HEADERS[0],
DUMMY_BATCH_PROOFS[0] {
...DUMMY_BATCH_PROOFS[0],
index: DUMMY_BATCH_PROOFS[0].index + 1,
}
) )
).to.not.be.reverted ).to.not.be.reverted
...@@ -226,7 +229,10 @@ describe('OVM_FraudVerifier', () => { ...@@ -226,7 +229,10 @@ describe('OVM_FraudVerifier', () => {
DUMMY_OVM_TRANSACTIONS[0], DUMMY_OVM_TRANSACTIONS[0],
DUMMY_TX_CHAIN_ELEMENTS[0], DUMMY_TX_CHAIN_ELEMENTS[0],
DUMMY_BATCH_HEADERS[0], DUMMY_BATCH_HEADERS[0],
DUMMY_BATCH_PROOFS[0] {
...DUMMY_BATCH_PROOFS[0],
index: DUMMY_BATCH_PROOFS[0].index + 1,
}
) )
}) })
...@@ -430,7 +436,10 @@ describe('OVM_FraudVerifier', () => { ...@@ -430,7 +436,10 @@ describe('OVM_FraudVerifier', () => {
DUMMY_OVM_TRANSACTIONS[1], DUMMY_OVM_TRANSACTIONS[1],
DUMMY_TX_CHAIN_ELEMENTS[0], DUMMY_TX_CHAIN_ELEMENTS[0],
DUMMY_BATCH_HEADERS[0], DUMMY_BATCH_HEADERS[0],
DUMMY_BATCH_PROOFS[0] {
...DUMMY_BATCH_PROOFS[0],
index: DUMMY_BATCH_PROOFS[0].index + 1,
}
) )
).to.not.be.reverted ).to.not.be.reverted
...@@ -473,7 +482,10 @@ describe('OVM_FraudVerifier', () => { ...@@ -473,7 +482,10 @@ describe('OVM_FraudVerifier', () => {
DUMMY_OVM_TRANSACTIONS[1], DUMMY_OVM_TRANSACTIONS[1],
DUMMY_TX_CHAIN_ELEMENTS[1], DUMMY_TX_CHAIN_ELEMENTS[1],
DUMMY_BATCH_HEADERS[1], DUMMY_BATCH_HEADERS[1],
DUMMY_BATCH_PROOFS[0] {
...DUMMY_BATCH_PROOFS[0],
index: DUMMY_BATCH_PROOFS[0].index + 1,
}
) )
// finalize it as well // finalize it as well
...@@ -506,7 +518,10 @@ describe('OVM_FraudVerifier', () => { ...@@ -506,7 +518,10 @@ describe('OVM_FraudVerifier', () => {
DUMMY_OVM_TRANSACTIONS[1], DUMMY_OVM_TRANSACTIONS[1],
DUMMY_TX_CHAIN_ELEMENTS[1], DUMMY_TX_CHAIN_ELEMENTS[1],
DUMMY_BATCH_HEADERS[1], DUMMY_BATCH_HEADERS[1],
DUMMY_BATCH_PROOFS[0] {
...DUMMY_BATCH_PROOFS[0],
index: DUMMY_BATCH_PROOFS[0].index + 1,
}
) )
// finalize the new fraud first // finalize the new fraud first
......
...@@ -96,6 +96,7 @@ describe('OVM_StateTransitioner', () => { ...@@ -96,6 +96,7 @@ describe('OVM_StateTransitioner', () => {
let account: any let account: any
beforeEach(() => { beforeEach(() => {
Mock__OVM_StateManager.smocked.hasAccount.will.return.with(false) Mock__OVM_StateManager.smocked.hasAccount.will.return.with(false)
Mock__OVM_StateManager.smocked.hasEmptyAccount.will.return.with(false)
account = { account = {
nonce: 0, nonce: 0,
balance: 0, balance: 0,
...@@ -104,23 +105,6 @@ describe('OVM_StateTransitioner', () => { ...@@ -104,23 +105,6 @@ describe('OVM_StateTransitioner', () => {
} }
}) })
describe('when provided an invalid code hash', () => {
beforeEach(() => {
account.codeHash = NON_NULL_BYTES32
})
it('should revert', async () => {
await expect(
OVM_StateTransitioner.proveContractState(
ovmContractAddress,
ethContractAddress,
account,
'0x'
)
).to.be.revertedWith('Invalid code hash provided.')
})
})
describe('when provided a valid code hash', () => { describe('when provided a valid code hash', () => {
beforeEach(async () => { beforeEach(async () => {
ethContractAddress = OVM_StateTransitioner.address ethContractAddress = OVM_StateTransitioner.address
...@@ -137,7 +121,6 @@ describe('OVM_StateTransitioner', () => { ...@@ -137,7 +121,6 @@ describe('OVM_StateTransitioner', () => {
OVM_StateTransitioner.proveContractState( OVM_StateTransitioner.proveContractState(
ovmContractAddress, ovmContractAddress,
ethContractAddress, ethContractAddress,
account,
proof proof
) )
).to.be.reverted ).to.be.reverted
...@@ -170,14 +153,11 @@ describe('OVM_StateTransitioner', () => { ...@@ -170,14 +153,11 @@ describe('OVM_StateTransitioner', () => {
}) })
it('should put the account in the state manager', async () => { it('should put the account in the state manager', async () => {
await expect( await OVM_StateTransitioner.proveContractState(
OVM_StateTransitioner.proveContractState( ovmContractAddress,
ovmContractAddress, ethContractAddress,
ethContractAddress, proof
account, )
proof
)
).to.not.be.reverted
expect( expect(
Mock__OVM_StateManager.smocked.putAccount.calls[0] Mock__OVM_StateManager.smocked.putAccount.calls[0]
...@@ -212,7 +192,6 @@ describe('OVM_StateTransitioner', () => { ...@@ -212,7 +192,6 @@ describe('OVM_StateTransitioner', () => {
OVM_StateTransitioner.proveStorageSlot( OVM_StateTransitioner.proveStorageSlot(
NON_ZERO_ADDRESS, NON_ZERO_ADDRESS,
NON_NULL_BYTES32, NON_NULL_BYTES32,
NON_NULL_BYTES32,
'0x' '0x'
) )
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -250,12 +229,7 @@ describe('OVM_StateTransitioner', () => { ...@@ -250,12 +229,7 @@ describe('OVM_StateTransitioner', () => {
it('should revert', async () => { it('should revert', async () => {
await expect( await expect(
OVM_StateTransitioner.proveStorageSlot( OVM_StateTransitioner.proveStorageSlot(ZERO_ADDRESS, key, proof)
ZERO_ADDRESS,
key,
val,
proof
)
).to.be.reverted ).to.be.reverted
}) })
}) })
...@@ -285,12 +259,7 @@ describe('OVM_StateTransitioner', () => { ...@@ -285,12 +259,7 @@ describe('OVM_StateTransitioner', () => {
it('should insert the storage slot', async () => { it('should insert the storage slot', async () => {
await expect( await expect(
OVM_StateTransitioner.proveStorageSlot( OVM_StateTransitioner.proveStorageSlot(ZERO_ADDRESS, key, proof)
ZERO_ADDRESS,
key,
val,
proof
)
).to.not.be.reverted ).to.not.be.reverted
expect( expect(
...@@ -329,6 +298,9 @@ describe('OVM_StateTransitioner', () => { ...@@ -329,6 +298,9 @@ describe('OVM_StateTransitioner', () => {
describe('when the account was not changed or has already been committed', () => { describe('when the account was not changed or has already been committed', () => {
before(() => { before(() => {
Mock__OVM_StateManager.smocked.getTotalUncommittedContractStorage.will.return.with(
0
)
Mock__OVM_StateManager.smocked.commitAccount.will.return.with(false) Mock__OVM_StateManager.smocked.commitAccount.will.return.with(false)
}) })
...@@ -336,7 +308,7 @@ describe('OVM_StateTransitioner', () => { ...@@ -336,7 +308,7 @@ describe('OVM_StateTransitioner', () => {
await expect( await expect(
OVM_StateTransitioner.commitContractState(ovmContractAddress, '0x') OVM_StateTransitioner.commitContractState(ovmContractAddress, '0x')
).to.be.revertedWith( ).to.be.revertedWith(
'Account was not changed or has already been committed.' `Account state wasn't changed or has already been committed`
) )
}) })
}) })
...@@ -425,14 +397,9 @@ describe('OVM_StateTransitioner', () => { ...@@ -425,14 +397,9 @@ describe('OVM_StateTransitioner', () => {
it('should revert', async () => { it('should revert', async () => {
await expect( await expect(
OVM_StateTransitioner.commitStorageSlot( OVM_StateTransitioner.commitStorageSlot(ovmContractAddress, key, '0x')
ovmContractAddress,
key,
'0x',
'0x'
)
).to.be.revertedWith( ).to.be.revertedWith(
'Storage slot was not changed or has already been committed.' `Storage slot value wasn't changed or has already been committed.`
) )
}) })
}) })
...@@ -505,7 +472,6 @@ describe('OVM_StateTransitioner', () => { ...@@ -505,7 +472,6 @@ describe('OVM_StateTransitioner', () => {
OVM_StateTransitioner.commitStorageSlot( OVM_StateTransitioner.commitStorageSlot(
ovmContractAddress, ovmContractAddress,
key, key,
accountTrieProof,
storageTrieProof storageTrieProof
) )
).to.not.be.reverted ).to.not.be.reverted
......
...@@ -45,8 +45,11 @@ describe('Lib_RLPWriter', () => { ...@@ -45,8 +45,11 @@ describe('Lib_RLPWriter', () => {
describe('Use of library with other memory-modifying operations', () => { describe('Use of library with other memory-modifying operations', () => {
it('should allow creation of a contract beforehand and still work', async () => { it('should allow creation of a contract beforehand and still work', async () => {
const randomAddress = '0x1234123412341234123412341234123412341234' const randomAddress = '0x1234123412341234123412341234123412341234'
const rlpEncodedRandomAddress = '0x941234123412341234123412341234123412341234' const rlpEncodedRandomAddress =
const encoded = await Lib_RLPWriter.callStatic.writeAddressWithOtherMemory(randomAddress) '0x941234123412341234123412341234123412341234'
const encoded = await Lib_RLPWriter.callStatic.writeAddressWithOtherMemory(
randomAddress
)
expect(encoded).to.eq(rlpEncodedRandomAddress) expect(encoded).to.eq(rlpEncodedRandomAddress)
}) })
}) })
......
...@@ -24,7 +24,7 @@ export const ZERO_ADDRESS = makeAddress('00') ...@@ -24,7 +24,7 @@ export const ZERO_ADDRESS = makeAddress('00')
export const NON_ZERO_ADDRESS = makeAddress('11') export const NON_ZERO_ADDRESS = makeAddress('11')
export const VERIFIED_EMPTY_CONTRACT_HASH = export const VERIFIED_EMPTY_CONTRACT_HASH =
'0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000' '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
export const STORAGE_XOR_VALUE = export const STORAGE_XOR_VALUE =
'0xFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEF' '0xFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEFFEEDFACECAFEBEEF'
...@@ -47,6 +47,6 @@ export const getStorageXOR = (key: string): string => { ...@@ -47,6 +47,6 @@ export const getStorageXOR = (key: string): string => {
} }
export const EMPTY_ACCOUNT_CODE_HASH = export const EMPTY_ACCOUNT_CODE_HASH =
'0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000' '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
export const KECCAK_256_NULL = export const KECCAK_256_NULL =
'0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
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