BlockFoundersReward
This commit is contained in:
parent
736c21234b
commit
9398ff2321
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue