void BasicGasPricer::update(BlockChain const &_bc) { unsigned c = 0; h256 p = _bc.currentHash(); m_gasPerBlock = _bc.info(p).gasLimit(); map<u256, u256> dist; u256 total = 0; // make gasPrice versus gasUsed distribution for the last 1000 blocks while (c < 1000 && p) { BlockHeader bi = _bc.info(p); if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); BlockReceipts brs(_bc.receipts(bi.hash())); size_t i = 0; for (auto const &tr: r[1]) { Transaction tx(tr.data(), CheckTransaction::None); u256 gu = brs.receipts[i].gasUsed(); dist[tx.gasPrice()] += gu; total += gu; i++; } } p = bi.parentHash(); ++c; } // fill m_octiles with weighted gasPrices if (total > 0) { m_octiles[0] = dist.begin()->first; // calc mean u256 mean = 0; for (auto const &i: dist) mean += i.first * i.second; mean /= total; // calc standard deviation u256 sdSquared = 0; for (auto const &i: dist) sdSquared += i.second * (i.first - mean) * (i.first - mean); sdSquared /= total; if (sdSquared) { long double sd = sqrt(sdSquared.convert_to<long double>()); long double normalizedSd = sd / mean.convert_to<long double>(); // calc octiles normalized to gaussian distribution boost::math::normal gauss(1.0, (normalizedSd > 0.01) ? normalizedSd : 0.01); for (size_t i = 1; i < 8; i++) m_octiles[i] = u256(mean.convert_to<long double>() * boost::math::quantile(gauss, i / 8.0)); m_octiles[8] = dist.rbegin()->first; } else { for (size_t i = 0; i < 9; i++) m_octiles[i] = (i + 1) * mean / 5; } } }
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) { // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE BlockInfo bi(_block, _checkNonce); assert(m_previousBlock.hash == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash); assert(rootHash() == m_previousBlock.stateRoot); #endif if (m_currentBlock.parentHash != m_previousBlock.hash) BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. m_currentBlock.populate(_block, _checkNonce); m_currentBlock.verifyInternals(_block); // cnote << "playback begins:" << m_state.root(); // cnote << m_state; MemoryDB tm; GenericTrieDB<MemoryDB> transactionsTrie(&tm); transactionsTrie.init(); MemoryDB rm; GenericTrieDB<MemoryDB> receiptsTrie(&rm); receiptsTrie.init(); LastHashes lh = getLastHashes(_bc, (unsigned)m_previousBlock.number); // All ok with the block generally. Play back the transactions now... unsigned i = 0; for (auto const& tr: RLP(_block)[1]) { RLPStream k; k << i; transactionsTrie.insert(&k.out(), tr.data()); execute(lh, tr.data()); RLPStream receiptrlp; m_receipts.back().streamRLP(receiptrlp); receiptsTrie.insert(&k.out(), &receiptrlp.out()); ++i; } if (transactionsTrie.root() != m_currentBlock.transactionsRoot) { cwarn << "Bad transactions state root!"; BOOST_THROW_EXCEPTION(InvalidTransactionsStateRoot()); } if (receiptsTrie.root() != m_currentBlock.receiptsRoot) { cwarn << "Bad receipts state root."; cwarn << "Block:" << toHex(_block); cwarn << "Block RLP:" << RLP(_block); cwarn << "Calculated: " << receiptsTrie.root(); for (unsigned j = 0; j < i; ++j) { RLPStream k; k << j; auto b = asBytes(receiptsTrie.at(&k.out())); cwarn << j << ": "; cwarn << "RLP: " << RLP(b); cwarn << "Hex: " << toHex(b); cwarn << TransactionReceipt(&b); } cwarn << "Recorded: " << m_currentBlock.receiptsRoot; auto rs = _bc.receipts(m_currentBlock.hash); for (unsigned j = 0; j < rs.receipts.size(); ++j) { auto b = rs.receipts[j].rlp(); cwarn << j << ": "; cwarn << "RLP: " << RLP(b); cwarn << "Hex: " << toHex(b); cwarn << rs.receipts[j]; } BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } if (m_currentBlock.logBloom != logBloom()) { cwarn << "Bad log bloom!"; BOOST_THROW_EXCEPTION(InvalidLogBloom()); } // Initialise total difficulty calculation. u256 tdIncrease = m_currentBlock.difficulty; // Check uncles & apply their rewards to state. set<h256> nonces = { m_currentBlock.nonce }; Addresses rewarded; set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); for (auto const& i: RLP(_block)[2]) { if (knownUncles.count(sha3(i.data()))) BOOST_THROW_EXCEPTION(UncleInChain(knownUncles, sha3(i.data()) )); BlockInfo uncle = BlockInfo::fromHeader(i.data()); if (nonces.count(uncle.nonce)) BOOST_THROW_EXCEPTION(DuplicateUncleNonce()); BlockInfo uncleParent(_bc.block(uncle.parentHash)); if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) BOOST_THROW_EXCEPTION(UncleTooOld()); uncle.verifyParent(uncleParent); nonces.insert(uncle.nonce); tdIncrease += uncle.difficulty; rewarded.push_back(uncle.coinbaseAddress); } applyRewards(rewarded); // Commit all cached state changes to the state trie. commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { cwarn << "Bad state root!"; cnote << "Given to be:" << m_currentBlock.stateRoot; cnote << TrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot); cnote << "Calculated to be:" << rootHash(); cnote << m_state; cnote << *this; // Rollback the trie. m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidStateRoot()); } if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } return tdIncrease; }