BlockFoundersReward

This commit is contained in:
Svyatoslav Nikolsky 2018-12-24 16:34:58 +03:00
parent 736c21234b
commit 9398ff2321
8 changed files with 204 additions and 1 deletions

2
Cargo.lock generated
View File

@ -807,6 +807,7 @@ version = "0.1.0"
dependencies = [
"bitcrypto 0.1.0",
"chain 0.1.0",
"keys 0.1.0",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1585,6 +1586,7 @@ dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"db 0.1.0",
"keys 0.1.0",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"network 0.1.0",

View File

@ -6,6 +6,7 @@ authors = ["debris <marek.kotewicz@gmail.com>"]
[dependencies]
lazy_static = "1.0"
chain = { path = "../chain" }
keys = { path = "../keys" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }
bitcrypto = { path = "../crypto" }

View File

@ -1,3 +1,4 @@
use keys::Address;
use {Network, Magic, Deployment, crypto};
lazy_static! {
@ -47,6 +48,13 @@ pub struct ConsensusParams {
/// Optimal blocks interval (in seconds).
pub pow_target_spacing: u32,
///
pub subsidy_slow_start_interval: u32,
///
pub subsidy_halving_interval: u32,
///
pub founders_addresses: Vec<Address>,
/// Equihash (N, K) parameters.
pub equihash_params: Option<(u32, u32)>,
@ -144,6 +152,59 @@ impl ConsensusParams {
pow_max_adjust_up: 16,
pow_target_spacing: (2.5 * 60.0) as u32,
subsidy_slow_start_interval: 20_000,
subsidy_halving_interval: 840_000,
founders_addresses: vec![
"t3Vz22vK5z2LcKEdg16Yv4FFneEL1zg9ojd".into(),
"t3cL9AucCajm3HXDhb5jBnJK2vapVoXsop3".into(),
"t3fqvkzrrNaMcamkQMwAyHRjfDdM2xQvDTR".into(),
"t3TgZ9ZT2CTSK44AnUPi6qeNaHa2eC7pUyF".into(),
"t3SpkcPQPfuRYHsP5vz3Pv86PgKo5m9KVmx".into(),
"t3Xt4oQMRPagwbpQqkgAViQgtST4VoSWR6S".into(),
"t3ayBkZ4w6kKXynwoHZFUSSgXRKtogTXNgb".into(),
"t3adJBQuaa21u7NxbR8YMzp3km3TbSZ4MGB".into(),
"t3K4aLYagSSBySdrfAGGeUd5H9z5Qvz88t2".into(),
"t3RYnsc5nhEvKiva3ZPhfRSk7eyh1CrA6Rk".into(),
"t3Ut4KUq2ZSMTPNE67pBU5LqYCi2q36KpXQ".into(),
"t3ZnCNAvgu6CSyHm1vWtrx3aiN98dSAGpnD".into(),
"t3fB9cB3eSYim64BS9xfwAHQUKLgQQroBDG".into(),
"t3cwZfKNNj2vXMAHBQeewm6pXhKFdhk18kD".into(),
"t3YcoujXfspWy7rbNUsGKxFEWZqNstGpeG4".into(),
"t3bLvCLigc6rbNrUTS5NwkgyVrZcZumTRa4".into(),
"t3VvHWa7r3oy67YtU4LZKGCWa2J6eGHvShi".into(),
"t3eF9X6X2dSo7MCvTjfZEzwWrVzquxRLNeY".into(),
"t3esCNwwmcyc8i9qQfyTbYhTqmYXZ9AwK3X".into(),
"t3M4jN7hYE2e27yLsuQPPjuVek81WV3VbBj".into(),
"t3gGWxdC67CYNoBbPjNvrrWLAWxPqZLxrVY".into(),
"t3LTWeoxeWPbmdkUD3NWBquk4WkazhFBmvU".into(),
"t3P5KKX97gXYFSaSjJPiruQEX84yF5z3Tjq".into(),
"t3f3T3nCWsEpzmD35VK62JgQfFig74dV8C9".into(),
"t3Rqonuzz7afkF7156ZA4vi4iimRSEn41hj".into(),
"t3fJZ5jYsyxDtvNrWBeoMbvJaQCj4JJgbgX".into(),
"t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW".into(),
"t3WeKQDxCijL5X7rwFem1MTL9ZwVJkUFhpF".into(),
"t3Y9FNi26J7UtAUC4moaETLbMo8KS1Be6ME".into(),
"t3aNRLLsL2y8xcjPheZZwFy3Pcv7CsTwBec".into(),
"t3gQDEavk5VzAAHK8TrQu2BWDLxEiF1unBm".into(),
"t3Rbykhx1TUFrgXrmBYrAJe2STxRKFL7G9r".into(),
"t3aaW4aTdP7a8d1VTE1Bod2yhbeggHgMajR".into(),
"t3YEiAa6uEjXwFL2v5ztU1fn3yKgzMQqNyo".into(),
"t3g1yUUwt2PbmDvMDevTCPWUcbDatL2iQGP".into(),
"t3dPWnep6YqGPuY1CecgbeZrY9iUwH8Yd4z".into(),
"t3QRZXHDPh2hwU46iQs2776kRuuWfwFp4dV".into(),
"t3enhACRxi1ZD7e8ePomVGKn7wp7N9fFJ3r".into(),
"t3PkLgT71TnF112nSwBToXsD77yNbx2gJJY".into(),
"t3LQtHUDoe7ZhhvddRv4vnaoNAhCr2f4oFN".into(),
"t3fNcdBUbycvbCtsD2n9q3LuxG7jVPvFB8L".into(),
"t3dKojUU2EMjs28nHV84TvkVEUDu1M1FaEx".into(),
"t3aKH6NiWN1ofGd8c19rZiqgYpkJ3n679ME".into(),
"t3MEXDF9Wsi63KwpPuQdD6by32Mw2bNTbEa".into(),
"t3WDhPfik343yNmPTqtkZAoQZeqA83K7Y3f".into(),
"t3PSn5TbMMAEw7Eu36DYctFezRzpX1hzf3M".into(),
"t3R3Y5vnBLrEn8L6wFjPjBLnxSUQsKnmFpv".into(),
"t3Pcm737EsVkGTbhsu2NekKtJeG92mvYyoN".into(),
],
equihash_params: Some((200, 9)),
joinsplit_verification_key: mainnet_pghr_verification_key(),
@ -169,6 +230,59 @@ impl ConsensusParams {
pow_max_adjust_up: 16,
pow_target_spacing: (2.5 * 60.0) as u32,
subsidy_slow_start_interval: 20_000,
subsidy_halving_interval: 840_000,
founders_addresses: vec![
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
"t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2".into(),
"t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy".into(),
"t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo".into(),
"t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf".into(),
"t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj".into(),
"t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9".into(),
"t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12".into(),
"t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC".into(),
"t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp".into(),
"t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo".into(),
"t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL".into(),
"t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ".into(),
"t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB".into(),
"t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK".into(),
"t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT".into(),
"t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY".into(),
"t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC".into(),
"t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC".into(),
"t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj".into(),
"t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL".into(),
"t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h".into(),
"t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH".into(),
"t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R".into(),
"t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le".into(),
"t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka".into(),
"t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a".into(),
"t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn".into(),
"t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d".into(),
"t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL".into(),
"t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J".into(),
"t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn".into(),
"t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG".into(),
"t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n".into(),
"t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t".into(),
"t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp".into(),
"t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5".into(),
"t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc".into(),
"t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy".into(),
"t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9".into(),
"t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp".into(),
"t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ".into(),
"t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4".into(),
"t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP".into(),
"t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ".into(),
"t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX".into(),
"t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt".into(),
],
equihash_params: Some((200, 9)),
joinsplit_verification_key: testnet_pghr_verification_key(),
@ -194,6 +308,12 @@ impl ConsensusParams {
pow_max_adjust_up: 0,
pow_target_spacing: (2.5 * 60.0) as u32,
subsidy_slow_start_interval: 0,
subsidy_halving_interval: 150,
founders_addresses: vec![
"t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg".into(),
],
equihash_params: Some((200, 9)),
joinsplit_verification_key: regtest_pghr_verification_key(),
@ -219,6 +339,12 @@ impl ConsensusParams {
pow_max_adjust_up: 0,
pow_target_spacing: (2.5 * 60.0) as u32,
subsidy_slow_start_interval: 0,
subsidy_halving_interval: 150,
founders_addresses: vec![
"t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg".into(),
],
equihash_params: None,
joinsplit_verification_key: unitest_pghr_verification_key(),
@ -285,6 +411,38 @@ impl ConsensusParams {
height >= self.sapling_height
}
pub fn founder_address(&self, height: u32) -> Option<Address> {
let last_founders_reward_block_height = self.subsidy_halving_interval + self.subsidy_slow_start_interval / 2 - 1;
if height == 0 || height > last_founders_reward_block_height {
return None;
}
let founders_len = self.founders_addresses.len() as u32;
let address_change_interval = (last_founders_reward_block_height + founders_len) / founders_len;
let address_index = height / address_change_interval;
Some(self.founders_addresses[address_index as usize].clone())
}
pub fn founder_subsidy(&self, height: u32) -> u64 {
let mut subsidy = 1250000000u64;
if height < self.subsidy_slow_start_interval / 2 {
subsidy /= self.subsidy_slow_start_interval as u64;
subsidy *= height as u64;
} else if height < self.subsidy_slow_start_interval {
subsidy /= self.subsidy_slow_start_interval as u64;
subsidy *= height as u64 + 1;
} else {
let halvings = (height - self.subsidy_slow_start_interval / 2) / self.subsidy_halving_interval;
if halvings >= 64 {
return 0;
}
subsidy >>= halvings as u64;
}
subsidy
}
pub fn consensus_branch_id(&self, height: u32) -> u32 {
// sapling upgrade
if height >= self.sapling_height {

View File

@ -5,6 +5,7 @@ extern crate chain;
extern crate primitives;
extern crate serialization;
extern crate bitcrypto as crypto;
extern crate keys;
extern crate rustc_hex as hex;
mod consensus;

View File

@ -10,6 +10,7 @@ rayon = "1.0"
parking_lot = "0.4"
byteorder = "1.2"
lazy_static = "1.2.0"
keys = { path = "../keys" }
primitives = { path = "../primitives" }
chain = { path = "../chain" }
serialization = { path = "../serialization" }

View File

@ -1,6 +1,7 @@
use keys::Address;
use network::{ConsensusParams};
use storage::{TransactionOutputProvider, BlockHeaderProvider};
use script;
use script::{self, Builder};
use sigops::{transaction_sigops};
use work::block_reward_satoshi;
use duplex_store::DuplexTransactionOutputProvider;
@ -16,6 +17,7 @@ pub struct BlockAcceptor<'a> {
pub sigops: BlockSigops<'a>,
pub coinbase_claim: BlockCoinbaseClaim<'a>,
pub coinbase_script: BlockCoinbaseScript<'a>,
pub founders_reward: BlockFoundersReward<'a>,
}
impl<'a> BlockAcceptor<'a> {
@ -33,6 +35,7 @@ impl<'a> BlockAcceptor<'a> {
coinbase_script: BlockCoinbaseScript::new(block, consensus, height),
coinbase_claim: BlockCoinbaseClaim::new(block, store, height),
sigops: BlockSigops::new(block, store, consensus),
founders_reward: BlockFoundersReward::new(block, consensus, height),
}
}
@ -42,6 +45,7 @@ impl<'a> BlockAcceptor<'a> {
self.serialized_size.check()?;
self.coinbase_claim.check()?;
self.coinbase_script.check()?;
self.founders_reward.check()?;
Ok(())
}
}
@ -260,6 +264,39 @@ impl<'a> BlockCoinbaseScript<'a> {
}
}
pub struct BlockFoundersReward<'a> {
block: CanonBlock<'a>,
founder_address: Option<Address>,
founder_reward: u64,
}
impl<'a> BlockFoundersReward<'a> {
fn new(block: CanonBlock<'a>, consensus_params: &ConsensusParams, height: u32) -> Self {
BlockFoundersReward {
block: block,
founder_address: consensus_params.founder_address(height),
founder_reward: consensus_params.founder_subsidy(height),
}
}
fn check(&self) -> Result<(), Error> {
if let Some(ref founder_address) = self.founder_address {
let script = Builder::build_p2sh(&founder_address.hash);
let has_founders_reward = self.block.transactions.first()
.map(|tx| tx.raw.outputs.iter().any(|output|
**output.script_pubkey == *script &&
output.value == self.founder_reward))
.unwrap_or(false);
if !has_founders_reward {
return Err(Error::MissingFoundersReward);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
extern crate test_data;

View File

@ -59,6 +59,8 @@ pub enum Error {
InvalidEquihashSolution,
/// Invalid block version
InvalidVersion,
/// Block' coinbase is missing founders reward output.
MissingFoundersReward,
}
impl From<DBError> for Error {

View File

@ -65,6 +65,7 @@ extern crate rustc_hex as hex;
extern crate storage;
extern crate chain;
extern crate keys;
extern crate network;
extern crate primitives;
extern crate serialization as ser;