From 0349f7bf057f691618f97e88bec0a1624e517d08 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jan 2014 10:18:59 +0000 Subject: [PATCH] Some repotting. --- libethereum/AddressState.cpp | 10 ++ libethereum/AddressState.h | 48 +++++++++ libethereum/BlockInfo.cpp | 39 +++++++ libethereum/BlockInfo.h | 26 +++++ libethereum/Common.h | 18 ++++ libethereum/Exceptions.h | 27 +++++ libethereum/Instruction.h | 62 +++++++++++ libethereum/State.cpp | 71 ++++--------- libethereum/State.h | 197 +++-------------------------------- libethereum/Trie.h | 4 - 10 files changed, 266 insertions(+), 236 deletions(-) create mode 100644 libethereum/AddressState.cpp create mode 100644 libethereum/AddressState.h create mode 100644 libethereum/BlockInfo.cpp create mode 100644 libethereum/BlockInfo.h create mode 100644 libethereum/Exceptions.h create mode 100644 libethereum/Instruction.h diff --git a/libethereum/AddressState.cpp b/libethereum/AddressState.cpp new file mode 100644 index 000000000..612312a7f --- /dev/null +++ b/libethereum/AddressState.cpp @@ -0,0 +1,10 @@ +#include "Trie.h" +#include "AddressState.h" +using namespace std; +using namespace eth; + +u256 AddressState::memoryHash() const +{ + return hash256(m_memory); +} + diff --git a/libethereum/AddressState.h b/libethereum/AddressState.h new file mode 100644 index 000000000..621e12d70 --- /dev/null +++ b/libethereum/AddressState.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Common.h" +#include "RLP.h" + +namespace eth +{ + +enum class AddressType +{ + Normal, + Contract +}; + +class AddressState +{ +public: + AddressState(AddressType _type = AddressType::Normal): m_type(_type), m_balance(0), m_nonce(0) {} + + AddressType type() const { return m_type; } + u256& balance() { return m_balance; } + u256 const& balance() const { return m_balance; } + u256& nonce() { return m_nonce; } + u256 const& nonce() const { return m_nonce; } + std::map& memory() { assert(m_type == AddressType::Contract); return m_memory; } + std::map const& memory() const { assert(m_type == AddressType::Contract); return m_memory; } + + u256 memoryHash() const; + + std::string toString() const + { + if (m_type == AddressType::Normal) + return rlpList(m_balance, toCompactBigEndianString(m_nonce)); + if (m_type == AddressType::Contract) + return rlpList(m_balance, toCompactBigEndianString(m_nonce), toCompactBigEndianString(memoryHash())); + return ""; + } + +private: + AddressType m_type; + u256 m_balance; + u256 m_nonce; + u256Map m_memory; +}; + +} + + diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp new file mode 100644 index 000000000..5231027fe --- /dev/null +++ b/libethereum/BlockInfo.cpp @@ -0,0 +1,39 @@ +#include "RLP.h" +#include "BlockInfo.h" +using namespace std; +using namespace eth; + +void populateAndVerify(bytesConstRef _block, u256 _number) +{ + number = _number; + + RLP root(_block); + try + { + RLP header = root[0]; + hash = eth::sha256(_block); + parentHash = header[0].toFatInt(); + sha256Uncles = header[1].toFatInt(); + coinbaseAddress = header[2].toFatInt(); + sha256Transactions = header[3].toFatInt(); + difficulty = header[4].toFatInt(); + timestamp = header[5].toFatInt(); + nonce = header[6].toFatInt(); + } + catch (RLP::BadCast) + { + throw InvalidBlockFormat(); + } + + if (sha256Transactions != sha256(root[1].data())) + throw InvalidTransactionsHash(); + + if (sha256Uncles != sha256(root[2].data())) + throw InvalidUnclesHash(); + + // TODO: check timestamp. + // TODO: check difficulty against timestamp. + // TODO: check proof of work. + + // TODO: check each transaction. +} diff --git a/libethereum/BlockInfo.h b/libethereum/BlockInfo.h new file mode 100644 index 000000000..39d15b089 --- /dev/null +++ b/libethereum/BlockInfo.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Common.h" + +namespace eth +{ + +struct BlockInfo +{ +public: + u256 hash; + u256 parentHash; + u256 sha256Uncles; + u256 coinbaseAddress; + u256 sha256Transactions; + u256 difficulty; + u256 timestamp; + u256 nonce; + u256 number; + + void populateAndVerify(bytesConstRef _block, u256 _number); +}; + +} + + diff --git a/libethereum/Common.h b/libethereum/Common.h index e85320ee9..a2460da53 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include #include @@ -27,6 +29,10 @@ using sint = int64_t; using u256s = std::vector; using u160s = std::vector; +using StringMap = std::map; +using u256Map = std::map; +using HexMap = std::map; + template std::string toString(_T const& _t) { std::ostringstream o; o << _t; return o.str(); } template inline std::string asHex(_T const& _data, int _w = 2) @@ -143,6 +149,18 @@ inline std::string randomWord() return ret; } +template +inline u160 low160(_T const& _t) +{ + return (u160)(_t & ((((_T)1) << 160) - 1)); +} + +template +inline u160 as160(_T const& _t) +{ + return (u160)(_t & ((((_T)1) << 160) - 1)); +} + template inline std::vector<_T>& operator+=(std::vector<_T>& _a, std::vector<_T> const& _b) { auto s = _a.size(); diff --git a/libethereum/Exceptions.h b/libethereum/Exceptions.h new file mode 100644 index 000000000..437ac3d32 --- /dev/null +++ b/libethereum/Exceptions.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "Common.h" + +namespace eth +{ + +class NotEnoughCash: public std::exception {}; +class BadInstruction: public std::exception {}; +class StackTooSmall: public std::exception { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; +class OperandOutOfRange: public std::exception { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; }; +class ExecutionException: public std::exception {}; +class NoSuchContract: public std::exception {}; +class ContractAddressCollision: public std::exception {}; +class FeeTooSmall: public std::exception {}; +class InvalidSignature: public std::exception {}; +class InvalidTransactionFormat: public std::exception {}; +class InvalidBlockFormat: public std::exception {}; +class InvalidUnclesHash: public std::exception {}; +class InvalidTransactionsHash: public std::exception {}; +class InvalidTransaction: public std::exception {}; +class InvalidDifficulty: public std::exception {}; +class InvalidTimestamp: public std::exception {}; +class InvalidNonce: public std::exception {}; + +} diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h new file mode 100644 index 000000000..da27c0ec9 --- /dev/null +++ b/libethereum/Instruction.h @@ -0,0 +1,62 @@ +#pragma once + +namespace eth +{ + +// TODO: Update comments. + +/// Virtual machine bytecode instruction. +enum class Instruction: uint8_t +{ + STOP = 0x00, ///< halts execution + ADD, ///< Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256 + SUB, ///< Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256 + MUL, ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256 + DIV, ///< Rx Ry Rz - sets Rz <- floor(Rx / Ry) + SDIV, ///< Rx Ry Rz - like DIV, except it treats values above 2^255 as negative (ie. 2^256 - x -> -x) + MOD, ///< Rx Ry Rz - sets Rz <- Rx mod Ry + SMOD, ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers) + EXP, ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256 + NEG, ///< Rx Ry - sets Ry <- 2^256 - Rx + LT, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0 + LE, ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0 + GT, ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0 + GE, ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0 + EQ, ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0 + NOT, ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0 + MYADDRESS = 0x10, ///< Rx - sets Rx to the contract's own address + TXSENDER, ///< pushes the transaction sender + TXVALUE , ///< pushes the transaction value + TXFEE, ///< pushes the transaction fee + TXDATAN, ///< pushes the number of data items + TXDATA, ///< pops one item and pushes data item S[-1], or zero if index out of range + BLK_PREVHASH, ///< pushes the hash of the previous block (NOT the current one since that's impossible!) + BLK_COINBASE, ///< pushes the coinbase of the current block + BLK_TIMESTAMP, ///< pushes the timestamp of the current block + BLK_NUMBER, ///< pushes the current block number + BLK_DIFFICULTY, ///< pushes the difficulty of the current block + SHA256 = 0x20, ///< sets Ry <- SHA256(Rx) + RIPEMD160, ///< Rx Ry - sets Ry <- RIPEMD160(Rx) + ECMUL, ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity + ECADD, ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb) + ECSIGN, ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy` + ECRECOVER, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx` + ECVALID, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx` + PUSH = 0x30, + POP, + DUP, + DUPN, + SWAP, + SWAPN, + LOAD, + STORE, + JMP = 0x40, ///< Rx - sets the index pointer to the value at Rx + JMPI, ///< Rx Ry - if Rx != 0, sets the index pointer to Ry + IND, ///< pushes the index pointer. + EXTRO = 0x50, ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz + BALANCE, ///< Rx - returns the ether balance of address Rx + MKTX = 0x60, ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract. + SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address +}; + +} diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 85b953b28..ee963a57e 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1,5 +1,8 @@ #include #include +#include "Trie.h" +#include "Instruction.h" +#include "Exceptions.h" #include "sha256.h" #include "State.h" using namespace std; @@ -100,75 +103,53 @@ mt19937_64& State::engine() return *s_engine; } -bool State::execute(Transaction const& _t, Address _sender) +u256 State::contractMemory(Address _contract, u256 _memory) const +{ + auto m = m_current.find(_contract); + if (m == m_current.end()) + return 0; + auto i = m->second.memory().find(_memory); + return i == m->second.memory().end() ? 0 : i->second; +} + +void State::execute(Transaction const& _t, Address _sender) { // Entry point for a contract-originated transaction. if (_t.nonce != transactionsFrom(_sender)) - { - // Nonce is wrong. - // Error reporting? - return false; - } + throw InvalidNonce(); if (balance(_sender) < _t.value + _t.fee) - { - // Sender balance too low. - // Error reporting? - return false; - } + throw NotEnoughCash(); if (_t.receiveAddress) { - assert(subBalance(_sender, _t.value)); + assert(subBalance(_sender, _t.value + _t.fee)); addBalance(_t.receiveAddress, _t.value); + addBalance(m_minerAddress, _t.fee); if (isContractAddress(_t.receiveAddress)) { - u256 minerFee = 0; - - try - { - execute(_t.receiveAddress, _sender, _t.value, _t.fee, _t.data, &minerFee); - addBalance(m_minerAddress, minerFee); - return true; - } - catch (...) - { - // Execution error. - // Error reporting? - addBalance(m_minerAddress, minerFee); - throw ExecutionException(); - } + MinerFeeAdder feeAdder({this, 0}); // will add fee on destruction. + execute(_t.receiveAddress, _sender, _t.value, _t.fee, _t.data, &feeAdder.fee); } - else - return true; } else { if (_t.fee < _t.data.size() * c_memoryFee + c_newContractFee) - { - // Fee too small. - // Error reporting? - return false; - } + throw FeeTooSmall(); Address newAddress = low160(_t.sha256()); if (isContractAddress(newAddress)) - { - // Contract collision. - // Error reporting? - return false; - } + throw ContractAddressCollision(); - // auto& mem = m_current[newAddress].memory(); for (uint i = 0; i < _t.data.size(); ++i) mem[i] = _t.data[i]; - assert(subBalance(_sender, _t.value)); + assert(subBalance(_sender, _t.value + _t.fee)); addBalance(newAddress, _t.value); - return true; + addBalance(m_minerAddress, _t.fee); } } @@ -198,12 +179,6 @@ void State::execute(Address _myAddress, Address _txSender, u256 _txValue, u256 _ myMemory.erase(_n); }; - if (balance(_myAddress) < _txFee) - throw NotEnoughCash(); - - subBalance(_myAddress, _txFee); - *_totalFee += _txFee; - u256 curPC = 0; u256 nextPC = 1; u256 stepCount = 0; diff --git a/libethereum/State.h b/libethereum/State.h index a47cfe85a..def1f7607 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -1,188 +1,17 @@ #pragma once -#include #include #include #include -#include "Trie.h" +#include "Exceptions.h" +#include "AddressState.h" +#include "BlockInfo.h" #include "RLP.h" #include "Common.h" namespace eth { -/// Virtual machine bytecode instruction. -enum class Instruction: uint8_t -{ - STOP = 0x00, ///< halts execution - ADD, ///< Rx Ry Rz - sets Rz <- Rx + Ry mod 2^256 - SUB, ///< Rx Ry Rz - sets Rz <- Rx - Ry mod 2^256 - MUL, ///< Rx Ry Rz - sets Rz <- Rx * Ry mod 2^256 - DIV, ///< Rx Ry Rz - sets Rz <- floor(Rx / Ry) - SDIV, ///< Rx Ry Rz - like DIV, except it treats values above 2^255 as negative (ie. 2^256 - x -> -x) - MOD, ///< Rx Ry Rz - sets Rz <- Rx mod Ry - SMOD, ///< Rx Ry Rz - like MOD, but for signed values just like SDIV (using Python's convention with negative numbers) - EXP, ///< Rx Ry Rz - sets Rz <- Rx ^ Ry mod 2^256 - NEG, ///< Rx Ry - sets Ry <- 2^256 - Rx - LT, ///< Rx Ry Rz - sets Rz <- 1 if Rx < Ry else 0 - LE, ///< Rx Ry Rz - sets Rz <- 1 if Rx <= Ry else 0 - GT, ///< Rx Ry Rz - sets Rz <- 1 if Rx > Ry else 0 - GE, ///< Rx Ry Rz - sets Rz <- 1 if Rx >= Ry else 0 - EQ, ///< Rx Ry Rz - sets Rz <- 1 if Rx = Ry else 0 - NOT, ///< Rx Ry - sets Ry <- 1 if Rx = 0 else 0 - MYADDRESS = 0x10, ///< Rx - sets Rx to the contract's own address - TXSENDER, ///< pushes the transaction sender - TXVALUE , ///< pushes the transaction value - TXFEE, ///< pushes the transaction fee - TXDATAN, ///< pushes the number of data items - TXDATA, ///< pops one item and pushes data item S[-1], or zero if index out of range - BLK_PREVHASH, ///< pushes the hash of the previous block (NOT the current one since that's impossible!) - BLK_COINBASE, ///< pushes the coinbase of the current block - BLK_TIMESTAMP, ///< pushes the timestamp of the current block - BLK_NUMBER, ///< pushes the current block number - BLK_DIFFICULTY, ///< pushes the difficulty of the current block - SHA256 = 0x20, ///< sets Ry <- SHA256(Rx) - RIPEMD160, ///< Rx Ry - sets Ry <- RIPEMD160(Rx) - ECMUL, ///< Rx Ry Rz Ra Rb - sets (Ra, Rb) = Rz * (Rx, Ry) in secp256k1, using (0,0) for the point at infinity - ECADD, ///< Rx Ry Rz Ra Rb Rc - sets (Rb, Rc) = (Rx, Ry) + (Ra, Rb) - ECSIGN, ///< Rx Ry Rz Ra Rb - sets(Rz, Ra, Rb)as the(r,s,prefix)values of an Electrum-style RFC6979 deterministic signature ofRxwith private keyRy` - ECRECOVER, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx` - ECVALID, ///< Rx Ry Rz Ra Rb Rc - sets(Rb, Rc)as the public key from the signature(Ry, Rz, Ra)of the message hashRx` - PUSH = 0x30, - POP, - DUP, - DUPN, - SWAP, - SWAPN, - LOAD, - STORE, - JMP = 0x40, ///< Rx - sets the index pointer to the value at Rx - JMPI, ///< Rx Ry - if Rx != 0, sets the index pointer to Ry - IND, ///< pushes the index pointer. - EXTRO = 0x50, ///< Rx Ry Rz - looks at the contract at address Rx and its memory state Ry, and outputs the result to Rz - BALANCE, ///< Rx - returns the ether balance of address Rx - MKTX = 0x60, ///< Rx Ry Rz Rw Rv - sends Ry ether to Rx plus Rz fee with Rw data items starting from memory index Rv (and then reading to (Rv + 1), (Rv + 2) etc). Note that if Rx = 0 then this creates a new contract. - SUICIDE = 0xff ///< Rx - destroys the contract and clears all memory, sending the entire balance plus the negative fee from clearing memory minus TXFEE to the address -}; - -class NotEnoughCash: public std::exception {}; -class BadInstruction: public std::exception {}; -class StackTooSmall: public std::exception { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; -class OperandOutOfRange: public std::exception { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; }; -class ExecutionException: public std::exception {}; -class NoSuchContract: public std::exception {}; -class InvalidSignature: public std::exception {}; -class InvalidTransactionFormat: public std::exception {}; -class InvalidBlockFormat: public std::exception {}; -class InvalidUnclesHash: public std::exception {}; -class InvalidTransactionsHash: public std::exception {}; -class InvalidTransaction: public std::exception {}; -class InvalidDifficulty: public std::exception {}; -class InvalidTimestamp: public std::exception {}; -class InvalidNonce: public std::exception {}; - -struct BlockInfo -{ -public: - u256 hash; - u256 parentHash; - u256 sha256Uncles; - u256 coinbaseAddress; - u256 sha256Transactions; - u256 difficulty; - u256 timestamp; - u256 nonce; - u256 number; - - void populateAndVerify(bytesConstRef _block, u256 _number) - { - number = _number; - - RLP root(_block); - try - { - RLP header = root[0]; - hash = eth::sha256(_block); - parentHash = header[0].toFatInt(); - sha256Uncles = header[1].toFatInt(); - coinbaseAddress = header[2].toFatInt(); - sha256Transactions = header[3].toFatInt(); - difficulty = header[4].toFatInt(); - timestamp = header[5].toFatInt(); - nonce = header[6].toFatInt(); - } - catch (RLP::BadCast) - { - throw InvalidBlockFormat(); - } - - if (sha256Transactions != sha256(root[1].data())) - throw InvalidTransactionsHash(); - - if (sha256Uncles != sha256(root[2].data())) - throw InvalidUnclesHash(); - - // TODO: check timestamp. - // TODO: check difficulty against timestamp. - // TODO: check proof of work. - - // TODO: check each transaction. - } -}; - -enum class AddressType -{ - Normal, - Contract -}; - -class AddressState -{ -public: - AddressState(AddressType _type = AddressType::Normal): m_type(_type), m_balance(0), m_nonce(0) {} - - AddressType type() const { return m_type; } - u256& balance() { return m_balance; } - u256 const& balance() const { return m_balance; } - u256& nonce() { return m_nonce; } - u256 const& nonce() const { return m_nonce; } - std::map& memory() { assert(m_type == AddressType::Contract); return m_memory; } - std::map const& memory() const { assert(m_type == AddressType::Contract); return m_memory; } - - u256 memoryHash() const - { - return hash256(m_memory); - } - - std::string toString() const - { - if (m_type == AddressType::Normal) - return rlpList(m_balance, toCompactBigEndianString(m_nonce)); - if (m_type == AddressType::Contract) - return rlpList(m_balance, toCompactBigEndianString(m_nonce), toCompactBigEndianString(memoryHash())); - return ""; - } - -private: - AddressType m_type; - u256 m_balance; - u256 m_nonce; - u256Map m_memory; -}; - -template -inline u160 low160(_T const& _t) -{ - return (u160)(_t & ((((_T)1) << 160) - 1)); -} - -template -inline u160 as160(_T const& _t) -{ - return (u160)(_t & ((((_T)1) << 160) - 1)); -} - - struct Signature { byte v; @@ -225,10 +54,17 @@ public: static std::mt19937_64& engine(); bool verify(bytes const& _block); - bool execute(bytes const& _rlp) { try { Transaction t(_rlp); return execute(t, t.sender()); } catch (...) { return false; } } // remove const_cast once vector_ref can handle const vector* properly. + bool execute(bytes const& _rlp) { try { Transaction t(_rlp); execute(t, t.sender()); } catch (...) { return false; } } private: - bool execute(Transaction const& _t, Address _sender); + struct MinerFeeAdder + { + ~MinerFeeAdder() { state->addBalance(state->m_minerAddress, fee); } + State* state; + u256 fee; + }; + + void execute(Transaction const& _t, Address _sender); bool isNormalAddress(Address _address) const { auto it = m_current.find(_address); return it != m_current.end() && it->second.type() == AddressType::Normal; } bool isContractAddress(Address _address) const { auto it = m_current.find(_address); return it != m_current.end() && it->second.type() == AddressType::Contract; } @@ -238,14 +74,7 @@ private: // bigint as we don't want any accidental problems with -ve numbers. bool subBalance(Address _id, bigint _amount) { auto it = m_current.find(_id); if (it == m_current.end() || (bigint)it->second.balance() < _amount) return false; it->second.balance() = (u256)((bigint)it->second.balance() - _amount); return true; } - u256 contractMemory(Address _contract, u256 _memory) const - { - auto m = m_current.find(_contract); - if (m == m_current.end()) - return 0; - auto i = m->second.memory().find(_memory); - return i == m->second.memory().end() ? 0 : i->second; - } + u256 contractMemory(Address _contract, u256 _memory) const; u256 transactionsFrom(Address _address) { auto it = m_current.find(_address); return it == m_current.end() ? 0 : it->second.nonce(); } diff --git a/libethereum/Trie.h b/libethereum/Trie.h index dcebf97af..4941197e5 100644 --- a/libethereum/Trie.h +++ b/libethereum/Trie.h @@ -7,10 +7,6 @@ namespace eth { -using StringMap = std::map; -using u256Map = std::map; -using HexMap = std::map; - u256 hash256(StringMap const& _s); u256 hash256(u256Map const& _s); std::string hexPrefixEncode(bytes const& _hexVector, bool _terminated = false, int _begin = 0, int _end = -1);