mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Support for genesis block that includes a coinbase (#2079)
* Chain init now handles genesis body properly, related unit test creating the genesis with reward * Avoid making block body public by adding a with_reward method * apply_block in all genesis cases works
This commit is contained in:
parent
7ff323c882
commit
ef55b35416
5 changed files with 83 additions and 18 deletions
|
@ -28,7 +28,7 @@ use core::core::hash::{Hash, Hashed, ZERO_HASH};
|
|||
use core::core::merkle_proof::MerkleProof;
|
||||
use core::core::verifier_cache::VerifierCache;
|
||||
use core::core::{
|
||||
Block, BlockHeader, BlockSums, Output, OutputIdentifier, Transaction, TxKernelEntry,
|
||||
Block, BlockHeader, BlockSums, Committed, Output, OutputIdentifier, Transaction, TxKernelEntry,
|
||||
};
|
||||
use core::global;
|
||||
use core::pow;
|
||||
|
@ -1231,6 +1231,8 @@ fn setup_head(
|
|||
}
|
||||
}
|
||||
Err(NotFoundErr(_)) => {
|
||||
let mut sums = BlockSums::default();
|
||||
|
||||
// Save the genesis header with a "zero" header_root.
|
||||
// We will update this later once we have the correct header_root.
|
||||
batch.save_block_header(&genesis.header)?;
|
||||
|
@ -1239,16 +1241,27 @@ fn setup_head(
|
|||
let tip = Tip::from_header(&genesis.header);
|
||||
batch.save_head(&tip)?;
|
||||
|
||||
// Initialize our header MM with the genesis header.
|
||||
txhashset::header_extending(txhashset, &mut batch, |extension| {
|
||||
extension.apply_header(&genesis.header)?;
|
||||
batch.save_block_header(&genesis.header)?;
|
||||
|
||||
if genesis.kernels().len() > 0 {
|
||||
let (utxo_sum, kernel_sum) = (sums, &genesis as &Committed).verify_kernel_sums(
|
||||
genesis.header.overage(),
|
||||
genesis.header.total_kernel_offset(),
|
||||
)?;
|
||||
sums = BlockSums {
|
||||
utxo_sum,
|
||||
kernel_sum,
|
||||
};
|
||||
}
|
||||
txhashset::extending(txhashset, &mut batch, |extension| {
|
||||
extension.apply_block(&genesis)?;
|
||||
extension.validate_roots()?;
|
||||
extension.validate_sizes()?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
batch.save_block_header(&genesis.header)?;
|
||||
|
||||
// Save the block_sums to the db for use later.
|
||||
batch.save_block_sums(&genesis.hash(), &BlockSums::default())?;
|
||||
batch.save_block_sums(&genesis.hash(), &sums)?;
|
||||
|
||||
info!("init: saved genesis: {:?}", genesis.hash());
|
||||
}
|
||||
|
|
|
@ -999,7 +999,7 @@ impl<'a> Extension<'a> {
|
|||
/// Get the header at the specified height based on the current state of the extension.
|
||||
/// Derives the MMR pos from the height (insertion index) and retrieves the header hash.
|
||||
/// Looks the header up in the db by hash.
|
||||
pub fn get_header_by_height(&mut self, height: u64) -> Result<BlockHeader, Error> {
|
||||
pub fn get_header_by_height(&self, height: u64) -> Result<BlockHeader, Error> {
|
||||
let pos = pmmr::insertion_to_pmmr_index(height + 1);
|
||||
if let Some(hash) = self.get_header_hash(pos) {
|
||||
let header = self.batch.get_block_header(&hash)?;
|
||||
|
@ -1227,8 +1227,9 @@ impl<'a> Extension<'a> {
|
|||
/// from the respective MMRs.
|
||||
/// For a significantly faster way of validating full kernel sums see BlockSums.
|
||||
pub fn validate_kernel_sums(&self) -> Result<((Commitment, Commitment)), Error> {
|
||||
let genesis = self.get_header_by_height(0)?;
|
||||
let (utxo_sum, kernel_sum) = self.verify_kernel_sums(
|
||||
self.header.total_overage(),
|
||||
self.header.total_overage(genesis.kernel_mmr_size > 0),
|
||||
self.header.total_kernel_offset(),
|
||||
)?;
|
||||
Ok((utxo_sum, kernel_sum))
|
||||
|
|
|
@ -31,8 +31,9 @@ use chain::Chain;
|
|||
use core::core::hash::Hashed;
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::{Block, BlockHeader, OutputFeatures, OutputIdentifier, Transaction};
|
||||
use core::genesis;
|
||||
use core::global::ChainTypes;
|
||||
use core::libtx::{self, build};
|
||||
use core::libtx::{self, build, reward};
|
||||
use core::pow::Difficulty;
|
||||
use core::{consensus, global, pow};
|
||||
use keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
||||
|
@ -60,14 +61,51 @@ fn setup(dir_name: &str, genesis: Block) -> Chain {
|
|||
#[test]
|
||||
fn mine_empty_chain() {
|
||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
||||
let chain = setup(".grin", pow::mine_genesis_block().unwrap());
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||
mine_some_on_top(".grin", pow::mine_genesis_block().unwrap(), &keychain);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mine_genesis_reward_chain() {
|
||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
||||
|
||||
// add coinbase data from the dev genesis block
|
||||
let mut genesis = genesis::genesis_dev();
|
||||
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||
let key_id = keychain::ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
|
||||
let reward = reward::output(&keychain, &key_id, 0, 0).unwrap();
|
||||
genesis = genesis.with_reward(reward.0, reward.1);
|
||||
|
||||
{
|
||||
// setup a tmp chain to hande tx hashsets
|
||||
let tmp_chain = setup(".grin.tmp", pow::mine_genesis_block().unwrap());
|
||||
tmp_chain.set_txhashset_roots(&mut genesis).unwrap();
|
||||
genesis.header.output_mmr_size = 1;
|
||||
genesis.header.kernel_mmr_size = 1;
|
||||
}
|
||||
|
||||
// get a valid PoW
|
||||
pow::pow_size(
|
||||
&mut genesis.header,
|
||||
Difficulty::unit(),
|
||||
global::proofsize(),
|
||||
global::min_edge_bits(),
|
||||
).unwrap();
|
||||
|
||||
mine_some_on_top(".grin.genesis", genesis, &keychain);
|
||||
}
|
||||
|
||||
fn mine_some_on_top<K>(dir: &str, genesis: Block, keychain: &K)
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let chain = setup(dir, genesis);
|
||||
|
||||
for n in 1..4 {
|
||||
let prev = chain.head_header().unwrap();
|
||||
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter());
|
||||
let pk = ExtKeychainPath::new(1, n as u32, 0, 0, 0).to_identifier();
|
||||
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
|
||||
let reward = libtx::reward::output(keychain, &pk, 0, prev.height).unwrap();
|
||||
let mut b =
|
||||
core::core::Block::new(&prev, vec![], next_header_info.clone().difficulty, reward)
|
||||
.unwrap();
|
||||
|
|
|
@ -262,8 +262,13 @@ impl BlockHeader {
|
|||
|
||||
/// The "total overage" to use when verifying the kernel sums for a full
|
||||
/// chain state. For a full chain state this is 0 - (height * reward).
|
||||
pub fn total_overage(&self) -> i64 {
|
||||
((self.height * REWARD) as i64).checked_neg().unwrap_or(0)
|
||||
pub fn total_overage(&self, genesis_had_reward: bool) -> i64 {
|
||||
let mut reward_count = self.height;
|
||||
if genesis_had_reward {
|
||||
reward_count += 1;
|
||||
}
|
||||
|
||||
((reward_count * REWARD) as i64).checked_neg().unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Total kernel offset for the chain state up to and including this block.
|
||||
|
@ -358,7 +363,7 @@ impl Block {
|
|||
reward_output: (Output, TxKernel),
|
||||
) -> Result<Block, Error> {
|
||||
let mut block =
|
||||
Block::with_reward(prev, txs, reward_output.0, reward_output.1, difficulty)?;
|
||||
Block::from_reward(prev, txs, reward_output.0, reward_output.1, difficulty)?;
|
||||
|
||||
// Now set the pow on the header so block hashing works as expected.
|
||||
{
|
||||
|
@ -421,7 +426,7 @@ impl Block {
|
|||
/// Builds a new block ready to mine from the header of the previous block,
|
||||
/// a vector of transactions and the reward information. Checks
|
||||
/// that all transactions are valid and calculates the Merkle tree.
|
||||
pub fn with_reward(
|
||||
pub fn from_reward(
|
||||
prev: &BlockHeader,
|
||||
txs: Vec<Transaction>,
|
||||
reward_out: Output,
|
||||
|
@ -461,6 +466,14 @@ impl Block {
|
|||
}.cut_through()
|
||||
}
|
||||
|
||||
/// Consumes this block and returns a new block with the coinbase output
|
||||
/// and kernels added
|
||||
pub fn with_reward(mut self, reward_out: Output, reward_kern: TxKernel) -> Block {
|
||||
self.body.outputs.push(reward_out);
|
||||
self.body.kernels.push(reward_kern);
|
||||
self
|
||||
}
|
||||
|
||||
/// Get inputs
|
||||
pub fn inputs(&self) -> &Vec<Input> {
|
||||
&self.body.inputs
|
||||
|
|
|
@ -120,7 +120,7 @@ fn build_block(
|
|||
};
|
||||
|
||||
let (output, kernel, block_fees) = get_coinbase(wallet_listener_url, block_fees)?;
|
||||
let mut b = core::Block::with_reward(&head, txs, output, kernel, difficulty.difficulty)?;
|
||||
let mut b = core::Block::from_reward(&head, txs, output, kernel, difficulty.difficulty)?;
|
||||
|
||||
// making sure we're not spending time mining a useless block
|
||||
b.validate(&head.total_kernel_offset, verifier_cache)?;
|
||||
|
|
Loading…
Reference in a new issue