subcoin_runtime_primitives/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::multiple_bound_locations)]
4
5extern crate alloc;
6
7use alloc::vec::Vec;
8use bitcoin::consensus::Encodable;
9use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
10use scale_info::TypeInfo;
11use sp_core::H256;
12use sp_runtime::ConsensusEngineId;
13
14pub const NAKAMOTO_HASH_ENGINE_ID: ConsensusEngineId = *b"hash";
16
17pub const NAKAMOTO_HEADER_ENGINE_ID: ConsensusEngineId = *b"hedr";
19
20const COIN: u64 = 100_000_000;
22
23const INITIAL_SUBSIDY: u64 = 50 * COIN;
25
26const HALVING_INTERVAL: u32 = 210_000;
27
28const MAX_SCRIPT_SIZE: usize = 10_000;
29
30#[derive(Debug, Clone, PartialEq, Eq, TypeInfo, Encode, Decode)]
32#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
33pub struct Coin {
34 pub is_coinbase: bool,
36 pub amount: u64,
38 pub height: u32,
40 pub script_pubkey: Vec<u8>,
42}
43
44impl MaxEncodedLen for Coin {
45 fn max_encoded_len() -> usize {
46 bool::max_encoded_len() + u64::max_encoded_len() + MAX_SCRIPT_SIZE
47 }
48}
49
50#[derive(
52 Debug,
53 Clone,
54 Copy,
55 TypeInfo,
56 Encode,
57 Decode,
58 DecodeWithMemTracking,
59 MaxEncodedLen,
60 PartialEq,
61 Eq,
62)]
63pub struct Txid(H256);
64
65impl From<bitcoin::Txid> for Txid {
66 fn from(txid: bitcoin::Txid) -> Self {
67 let mut bytes = Vec::with_capacity(32);
68 txid.consensus_encode(&mut bytes)
69 .expect("txid must be encoded correctly; qed");
70
71 bytes.reverse();
72
73 let bytes: [u8; 32] = bytes
74 .try_into()
75 .expect("Bitcoin txid is sha256 hash which must fit into [u8; 32]; qed");
76
77 Self(H256::from(bytes))
78 }
79}
80
81impl From<Txid> for bitcoin::Txid {
82 fn from(txid: Txid) -> Self {
83 let mut bytes = txid.encode();
84 bytes.reverse();
85 bitcoin::consensus::Decodable::consensus_decode(&mut bytes.as_slice())
86 .expect("Decode must succeed as txid was guaranteed to be encoded correctly; qed")
87 }
88}
89
90#[derive(
92 Debug, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq, MaxEncodedLen,
93)]
94pub struct OutPoint {
95 pub txid: Txid,
97 pub vout: u32,
99}
100
101impl From<bitcoin::OutPoint> for OutPoint {
102 fn from(out_point: bitcoin::OutPoint) -> Self {
103 Self {
104 txid: out_point.txid.into(),
105 vout: out_point.vout,
106 }
107 }
108}
109
110impl From<OutPoint> for bitcoin::OutPoint {
111 fn from(val: OutPoint) -> Self {
112 bitcoin::OutPoint {
113 txid: val.txid.into(),
114 vout: val.vout,
115 }
116 }
117}
118
119pub fn bitcoin_block_subsidy(height: u32) -> u64 {
121 block_subsidy(height, HALVING_INTERVAL)
122}
123
124fn block_subsidy(height: u32, subsidy_halving_interval: u32) -> u64 {
126 let halvings = height / subsidy_halving_interval;
127 if halvings >= 64 {
129 return 0;
130 }
131
132 let mut subsidy = INITIAL_SUBSIDY;
133
134 subsidy >>= halvings;
137
138 subsidy
139}
140
141sp_api::decl_runtime_apis! {
142 pub trait SubcoinApi {
144 fn execute_block_without_state_root_check(block: Block);
147
148 fn finalize_block_without_checks(header: Block::Header);
150
151 fn coins_count() -> u64;
153
154 fn get_utxos(outpoints: Vec<OutPoint>) -> Vec<Option<Coin>>;
159 }
160}