Skip to content

Commit

Permalink
integrate bitcoin to runtime and add genesis (paritytech#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
atenjin authored Jun 18, 2020
1 parent 58281fd commit 2c7fec4
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 183 deletions.
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub use pallet_timestamp::Call as TimestampCall;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
// xrml re-exports
#[cfg(feature = "std")]
pub use xrml_bridge_bitcoin::h256_conv_endian_from_str;
pub use xrml_bridge_bitcoin::{BTCHeader, BTCNetwork, BTCParams, Compact, H256 as BTCHash};

impl_opaque_keys! {
pub struct SessionKeys {
Expand Down Expand Up @@ -216,6 +220,10 @@ impl xrml_assets::Trait for Runtime {
type DetermineTokenJackpotAccountId = Tmp;
}

impl xrml_bridge_bitcoin::Trait for Runtime {
type Event = Event;
}

construct_runtime!(
pub enum Runtime where
Block = Block,
Expand All @@ -231,6 +239,7 @@ construct_runtime!(

TransactionPayment: pallet_transaction_payment::{Module, Storage},
XAssets: xrml_assets::{Module, Call, Storage, Event<T>},
XBridgeBitcoin: xrml_bridge_bitcoin::{Module, Call, Storage, Event<T>, Config},
}
);

Expand Down
35 changes: 34 additions & 1 deletion src/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chainx_runtime::{
AccountId, AuraConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig, SystemConfig,
h256_conv_endian_from_str, AccountId, AuraConfig, BTCHeader, BTCNetwork, BTCParams, Compact,
GenesisConfig, GrandpaConfig, Signature, SudoConfig, SystemConfig, XBridgeBitcoinConfig,
WASM_BINARY,
};
use sc_service::ChainType;
Expand Down Expand Up @@ -125,5 +126,37 @@ fn testnet_genesis(
pallet_sudo: Some(SudoConfig {
key: root_key.clone(),
}),
xrml_bridge_bitcoin: Some(XBridgeBitcoinConfig {
genesis_header_and_height: (
BTCHeader {
version: 536870912,
previous_header_hash: h256_conv_endian_from_str(
"0000000000000000000a4adf6c5192128535d4dcb56cfb5753755f8d392b26bf",
),
merkle_root_hash: h256_conv_endian_from_str(
"1d21e60acb0b12e5cfd3f775edb647f982a2d666f9886b2f61ea5e72577b0f5e",
),
time: 1558168296,
bits: Compact::new(388627269),
nonce: 1439505020,
},
576576,
),
genesis_hash: h256_conv_endian_from_str(
"0000000000000000001721f58deb88b0710295a02551f0dde1e2e231a15f1882",
),
params_info: BTCParams::new(
486604799, // max_bits
2 * 60 * 60, // block_max_future
2 * 7 * 24 * 60 * 60, // target_timespan_seconds
10 * 60, // target_spacing_seconds
4, // retargeting_factor
), // retargeting_factor
network_id: BTCNetwork::Mainnet,
confirmation_number: 4,
reserved_block: 2100,
btc_withdrawal_fee: 500000,
max_withdrawal_count: 100,
}),
}
}
4 changes: 2 additions & 2 deletions xrml/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, prelude::*, result};

use frame_support::{
decl_error, decl_event, decl_module, decl_storage,
dispatch::{DispatchResult, DispatchError},
traits::{Imbalance, SignedImbalance, OnNewAccount},
dispatch::{DispatchError, DispatchResult},
traits::{Imbalance, OnNewAccount, SignedImbalance},
Parameter,
};
use frame_system::{self as system, ensure_root, ensure_signed};
Expand Down
2 changes: 1 addition & 1 deletion xrml/assets/src/pcx.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use sp_runtime::traits::{CheckedSub, Zero};
use sp_std::{cmp, result};

use frame_support::dispatch::{DispatchResult, DispatchError};
use frame_support::dispatch::{DispatchError, DispatchResult};
use frame_support::traits::{
BalanceStatus, Currency, ExistenceRequirement, Imbalance, ReservableCurrency, SignedImbalance,
WithdrawReason, WithdrawReasons,
Expand Down
4 changes: 2 additions & 2 deletions xrml/bridge/bitcoin/src/assets_records.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<T: Trait> Module<T> {
// current 4
// current 5
for confirmed in 1_u32..confirmations {
if let Some(info) = Module::<T>::block_header_for(current_hash) {
if let Some(info) = Module::<T>::btc_header_for(current_hash) {
// lookup withdrawal tx in current header
for txid in info.txid_list {
if let Some(tx_info) = Self::tx_for(&txid) {
Expand Down Expand Up @@ -116,7 +116,7 @@ impl<T: Trait> Module<T> {
// current 4
let mut current_hash = Self::best_index();
for index in 0..(confirmations - 1) {
if let Some(info) = Module::<T>::block_header_for(current_hash) {
if let Some(info) = Module::<T>::btc_header_for(current_hash) {
for txid in info.txid_list {
if let Some(tx_info) = Self::tx_for(&txid) {
if tx_info.tx_type == TxType::Deposit {
Expand Down
45 changes: 23 additions & 22 deletions xrml/bridge/bitcoin/src/header/header_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ use sp_std::{cmp, result};
use xrml_support::{debug, ensure_with_errorlog, error, info};

// light-bitcoin
use btc_chain::BlockHeader;
use btc_chain::BlockHeader as BTCHeader;
use btc_keys::Network;
use btc_primitives::{Compact, H256, U256};

use super::ChainErr;
use crate::types::Params;
use crate::types::BTCParams;
use crate::{Error, Module, Trait};

pub struct HeaderVerifier<'a> {
Expand All @@ -23,7 +24,7 @@ pub struct HeaderVerifier<'a> {
}

impl<'a> HeaderVerifier<'a> {
pub fn new<T: Trait>(header: &'a BlockHeader, height: u32) -> result::Result<Self, ChainErr> {
pub fn new<T: Trait>(header: &'a BTCHeader, height: u32) -> result::Result<Self, ChainErr> {
let now: T::Moment = pallet_timestamp::Module::<T>::now();
// bitcoin use u32 to log time, we think the timestamp would not more then u32
let current_time: u32 = now.saturated_into::<u32>();
Expand All @@ -36,9 +37,9 @@ impl<'a> HeaderVerifier<'a> {
}

pub fn check<T: Trait>(&self) -> DispatchResult {
let params: Params = Module::<T>::params_info();
let network_id: u32 = Module::<T>::network_id();
if network_id == 0 {
let params: BTCParams = Module::<T>::params_info();
let network_id: Network = Module::<T>::network_id();
if let Network::Mainnet = network_id {
self.work.check::<T>(&params)?;
}
self.proof_of_work.check::<T>(&params)?;
Expand All @@ -48,16 +49,16 @@ impl<'a> HeaderVerifier<'a> {
}

pub struct HeaderWork<'a> {
header: &'a BlockHeader,
header: &'a BTCHeader,
height: u32,
}

impl<'a> HeaderWork<'a> {
fn new(header: &'a BlockHeader, height: u32) -> Self {
fn new(header: &'a BTCHeader, height: u32) -> Self {
HeaderWork { header, height }
}

fn check<T: Trait>(&self, p: &Params) -> DispatchResult {
fn check<T: Trait>(&self, p: &BTCParams) -> DispatchResult {
let previous_header_hash = self.header.previous_header_hash.clone();
let work = work_required::<T>(previous_header_hash, self.height, p);
ensure_with_errorlog!(
Expand All @@ -72,13 +73,13 @@ impl<'a> HeaderWork<'a> {
}
}

pub fn work_required<T: Trait>(parent_hash: H256, height: u32, params: &Params) -> Compact {
pub fn work_required<T: Trait>(parent_hash: H256, height: u32, params: &BTCParams) -> Compact {
let max_bits = params.max_bits().into();
if height == 0 {
return max_bits;
}

let parent_header: BlockHeader = Module::<T>::block_header_for(&parent_hash).unwrap().header;
let parent_header: BTCHeader = Module::<T>::btc_header_for(&parent_hash).unwrap().header;

if is_retarget_height(height, params) {
let new_work = work_required_retarget::<T>(parent_header, height, params);
Expand All @@ -92,15 +93,15 @@ pub fn work_required<T: Trait>(parent_hash: H256, height: u32, params: &Params)
parent_header.bits
}

pub fn is_retarget_height(height: u32, p: &Params) -> bool {
pub fn is_retarget_height(height: u32, p: &BTCParams) -> bool {
height % p.retargeting_interval() == 0
}

/// Algorithm used for retargeting work every 2 weeks
pub fn work_required_retarget<T: Trait>(
parent_header: BlockHeader,
parent_header: BTCHeader,
height: u32,
params: &Params,
params: &BTCParams,
) -> Compact {
let retarget_num = height - params.retargeting_interval();

Expand All @@ -112,7 +113,7 @@ pub fn work_required_retarget<T: Trait>(
let hash_list = Module::<T>::block_hash_for(&retarget_num);
for h in hash_list {
// look up in main chain
if let Some(info) = Module::<T>::block_header_for(h) {
if let Some(info) = Module::<T>::btc_header_for(h) {
if info.confirmed == true {
retarget_header = info.header;
break;
Expand Down Expand Up @@ -152,7 +153,7 @@ pub fn work_required_retarget<T: Trait>(
}

/// Returns constrained number of seconds since last retarget
pub fn retarget_timespan(retarget_timestamp: u32, last_timestamp: u32, p: &Params) -> u32 {
pub fn retarget_timespan(retarget_timestamp: u32, last_timestamp: u32, p: &BTCParams) -> u32 {
// TODO i64??
// subtract unsigned 32 bit numbers in signed 64 bit space in
// order to prevent underflow before applying the range constraint.
Expand All @@ -169,15 +170,15 @@ fn range_constrain(value: i64, min: i64, max: i64) -> i64 {
}

pub struct HeaderProofOfWork<'a> {
header: &'a BlockHeader,
header: &'a BTCHeader,
}

impl<'a> HeaderProofOfWork<'a> {
fn new(header: &'a BlockHeader) -> Self {
fn new(header: &'a BTCHeader) -> Self {
HeaderProofOfWork { header }
}

fn check<T: Trait>(&self, p: &Params) -> DispatchResult {
fn check<T: Trait>(&self, p: &BTCParams) -> DispatchResult {
if is_valid_proof_of_work(p.max_bits(), self.header.bits, &self.header.hash()) {
Ok(())
} else {
Expand Down Expand Up @@ -209,19 +210,19 @@ pub fn is_valid_proof_of_work(max_work_bits: Compact, bits: Compact, hash: &H256
}

pub struct HeaderTimestamp<'a> {
header: &'a BlockHeader,
header: &'a BTCHeader,
current_time: u32,
}

impl<'a> HeaderTimestamp<'a> {
fn new(header: &'a BlockHeader, current_time: u32) -> Self {
fn new(header: &'a BTCHeader, current_time: u32) -> Self {
HeaderTimestamp {
header,
current_time,
}
}

fn check<T: Trait>(&self, p: &Params) -> DispatchResult {
fn check<T: Trait>(&self, p: &BTCParams) -> DispatchResult {
if self.header.time > self.current_time + p.block_max_future() {
error!("[HeaderTimestamp check]|Futuristic timestamp|header time{:}|current time:{:}|max_future{:?}", self.header.time, self.current_time, p.block_max_future());
Err(Error::<T>::HeaderFuturisticTimestamp)?
Expand Down
Loading

0 comments on commit 2c7fec4

Please sign in to comment.