Merge pull request #270 from ethcore/rpc_block_template
Rpc block template
This commit is contained in:
commit
da80c69a80
|
@ -0,0 +1,274 @@
|
|||
// TODO: remove after implementing getblocktmplate RPC
|
||||
#![warn(dead_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use super::hash::H256;
|
||||
use super::raw_transaction::RawTransaction;
|
||||
|
||||
/// Block template as described in:
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki
|
||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
pub struct BlockTemplate {
|
||||
/// The preferred block version
|
||||
pub version: u32,
|
||||
/// Specific block rules that are to be enforced
|
||||
pub rules: Option<Vec<String>>,
|
||||
/// Set of pending, supported versionbit (BIP 9) softfork deployments
|
||||
/// Keys: named softfork rules
|
||||
/// Values: identifies the bit number as indicating acceptance and readiness for given key
|
||||
pub vbavailable: Option<HashMap<String, u32>>,
|
||||
/// Bit mask of versionbits the server requires set in submissions
|
||||
pub vbrequired: Option<u32>,
|
||||
/// The hash of previous (best known) block
|
||||
pub previousblockhash: H256,
|
||||
/// Contents of non-coinbase transactions that should be included in the next block
|
||||
pub transactions: Vec<BlockTemplateTransaction>,
|
||||
/// Data that should be included in the coinbase's scriptSig content
|
||||
/// Keys: ignored
|
||||
/// Values: value to be included in scriptSig
|
||||
pub coinbaseaux: Option<HashMap<String, String>>,
|
||||
/// Maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)
|
||||
pub coinbasevalue: Option<u64>,
|
||||
/// information for coinbase transaction
|
||||
pub coinbasetxn: Option<BlockTemplateTransaction>,
|
||||
/// The hash target
|
||||
pub target: H256,
|
||||
/// The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)
|
||||
pub mintime: Option<i64>,
|
||||
/// List of ways the block template may be changed, e.g. 'time', 'transactions', 'prevblock'
|
||||
pub mutable: Option<Vec<String>>,
|
||||
/// A range of valid nonces (constant 00000000ffffffff)
|
||||
pub noncerange: Option<String>,
|
||||
/// Limit of sigops in blocks
|
||||
pub sigoplimit: Option<i64>,
|
||||
/// Limit of block size
|
||||
pub sizelimit: Option<u32>,
|
||||
/// Limit of block weight
|
||||
pub weightlimit: Option<u32>,
|
||||
/// Current timestamp in seconds since epoch (Jan 1 1970 GMT)
|
||||
pub curtime: i64,
|
||||
/// Compressed target of next block
|
||||
pub bits: u32,
|
||||
/// The height of the next block
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
/// Transaction data as included in `BlockTemplate`
|
||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
pub struct BlockTemplateTransaction {
|
||||
/// Transaction data encoded in hexadecimal
|
||||
pub data: RawTransaction,
|
||||
/// Transaction id encoded in little-endian hexadecimal
|
||||
pub txid: Option<H256>,
|
||||
/// Hash encoded in little-endian hexadecimal (including witness data)
|
||||
pub hash: Option<H256>,
|
||||
/// Transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is
|
||||
pub depends: Option<Vec<u64>>,
|
||||
/// Difference in value between transaction inputs and outputs (in Satoshis).
|
||||
/// For coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy).
|
||||
/// If key is not present, fee is unknown and clients MUST NOT assume there isn't one
|
||||
pub fee: Option<i64>,
|
||||
/// Total SigOps cost, as counted for purposes of block limits.
|
||||
/// If key is not present, sigop cost is unknown and clients MUST NOT assume it is zero.
|
||||
pub sigops: Option<i64>,
|
||||
/// Total transaction weight, as counted for purposes of block limits.
|
||||
pub weight: Option<i64>,
|
||||
/// If provided and true, this transaction must be in the final block
|
||||
pub required: bool,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::super::hash::H256;
|
||||
use super::super::bytes::Bytes;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn block_template_transaction_serialize() {
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: None,
|
||||
hash: None,
|
||||
depends: None,
|
||||
fee: None,
|
||||
sigops: None,
|
||||
weight: None,
|
||||
required: false,
|
||||
}).unwrap(), r#"{"data":"00010203","txid":null,"hash":null,"depends":null,"fee":null,"sigops":null,"weight":null,"required":false}"#);
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: Some(H256::from(1)),
|
||||
hash: Some(H256::from(2)),
|
||||
depends: Some(vec![1, 2]),
|
||||
fee: Some(100),
|
||||
sigops: Some(200),
|
||||
weight: Some(300),
|
||||
required: true,
|
||||
}).unwrap(), r#"{"data":"00010203","txid":"0100000000000000000000000000000000000000000000000000000000000000","hash":"0200000000000000000000000000000000000000000000000000000000000000","depends":[1,2],"fee":100,"sigops":200,"weight":300,"required":true}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_transaction_deserialize() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplateTransaction>(r#"{"data":"00010203","txid":null,"hash":null,"depends":null,"fee":null,"sigops":null,"weight":null,"required":false}"#).unwrap(),
|
||||
BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: None,
|
||||
hash: None,
|
||||
depends: None,
|
||||
fee: None,
|
||||
sigops: None,
|
||||
weight: None,
|
||||
required: false,
|
||||
});
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplateTransaction>(r#"{"data":"00010203","txid":"0100000000000000000000000000000000000000000000000000000000000000","hash":"0200000000000000000000000000000000000000000000000000000000000000","depends":[1,2],"fee":100,"sigops":200,"weight":300,"required":true}"#).unwrap(),
|
||||
BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: Some(H256::from(1)),
|
||||
hash: Some(H256::from(2)),
|
||||
depends: Some(vec![1, 2]),
|
||||
fee: Some(100),
|
||||
sigops: Some(200),
|
||||
weight: Some(300),
|
||||
required: true,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_serialize() {
|
||||
assert_eq!(serde_json::to_string(&BlockTemplate {
|
||||
version: 0,
|
||||
rules: None,
|
||||
vbavailable: None,
|
||||
vbrequired: None,
|
||||
previousblockhash: H256::default(),
|
||||
transactions: vec![],
|
||||
coinbaseaux: None,
|
||||
coinbasevalue: None,
|
||||
coinbasetxn: None,
|
||||
target: H256::default(),
|
||||
mintime: None,
|
||||
mutable: None,
|
||||
noncerange: None,
|
||||
sigoplimit: None,
|
||||
sizelimit: None,
|
||||
weightlimit: None,
|
||||
curtime: 100,
|
||||
bits: 200,
|
||||
height: 300,
|
||||
}).unwrap(), r#"{"version":0,"rules":null,"vbavailable":null,"vbrequired":null,"previousblockhash":"0000000000000000000000000000000000000000000000000000000000000000","transactions":[],"coinbaseaux":null,"coinbasevalue":null,"coinbasetxn":null,"target":"0000000000000000000000000000000000000000000000000000000000000000","mintime":null,"mutable":null,"noncerange":null,"sigoplimit":null,"sizelimit":null,"weightlimit":null,"curtime":100,"bits":200,"height":300}"#);
|
||||
assert_eq!(serde_json::to_string(&BlockTemplate {
|
||||
version: 0,
|
||||
rules: Some(vec!["a".to_owned()]),
|
||||
vbavailable: Some(vec![("b".to_owned(), 5)].into_iter().collect()),
|
||||
vbrequired: Some(10),
|
||||
previousblockhash: H256::from(10),
|
||||
transactions: vec![BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: None,
|
||||
hash: None,
|
||||
depends: None,
|
||||
fee: None,
|
||||
sigops: None,
|
||||
weight: None,
|
||||
required: false,
|
||||
}],
|
||||
coinbaseaux: Some(vec![("c".to_owned(), "d".to_owned())].into_iter().collect()),
|
||||
coinbasevalue: Some(30),
|
||||
coinbasetxn: Some(BlockTemplateTransaction {
|
||||
data: Bytes("555555".from_hex().unwrap()),
|
||||
txid: Some(H256::from(44)),
|
||||
hash: Some(H256::from(55)),
|
||||
depends: Some(vec![1]),
|
||||
fee: Some(300),
|
||||
sigops: Some(400),
|
||||
weight: Some(500),
|
||||
required: true,
|
||||
}),
|
||||
target: H256::from(100),
|
||||
mintime: Some(7),
|
||||
mutable: Some(vec!["afg".to_owned()]),
|
||||
noncerange: Some("00000000ffffffff".to_owned()),
|
||||
sigoplimit: Some(45),
|
||||
sizelimit: Some(449),
|
||||
weightlimit: Some(523),
|
||||
curtime: 100,
|
||||
bits: 200,
|
||||
height: 300,
|
||||
}).unwrap(), r#"{"version":0,"rules":["a"],"vbavailable":{"b":5},"vbrequired":10,"previousblockhash":"0a00000000000000000000000000000000000000000000000000000000000000","transactions":[{"data":"00010203","txid":null,"hash":null,"depends":null,"fee":null,"sigops":null,"weight":null,"required":false}],"coinbaseaux":{"c":"d"},"coinbasevalue":30,"coinbasetxn":{"data":"555555","txid":"2c00000000000000000000000000000000000000000000000000000000000000","hash":"3700000000000000000000000000000000000000000000000000000000000000","depends":[1],"fee":300,"sigops":400,"weight":500,"required":true},"target":"6400000000000000000000000000000000000000000000000000000000000000","mintime":7,"mutable":["afg"],"noncerange":"00000000ffffffff","sigoplimit":45,"sizelimit":449,"weightlimit":523,"curtime":100,"bits":200,"height":300}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_deserialize() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplate>(r#"{"version":0,"rules":null,"vbavailable":null,"vbrequired":null,"previousblockhash":"0000000000000000000000000000000000000000000000000000000000000000","transactions":[],"coinbaseaux":null,"coinbasevalue":null,"coinbasetxn":null,"target":"0000000000000000000000000000000000000000000000000000000000000000","mintime":null,"mutable":null,"noncerange":null,"sigoplimit":null,"sizelimit":null,"weightlimit":null,"curtime":100,"bits":200,"height":300}"#).unwrap(),
|
||||
BlockTemplate {
|
||||
version: 0,
|
||||
rules: None,
|
||||
vbavailable: None,
|
||||
vbrequired: None,
|
||||
previousblockhash: H256::default(),
|
||||
transactions: vec![],
|
||||
coinbaseaux: None,
|
||||
coinbasevalue: None,
|
||||
coinbasetxn: None,
|
||||
target: H256::default(),
|
||||
mintime: None,
|
||||
mutable: None,
|
||||
noncerange: None,
|
||||
sigoplimit: None,
|
||||
sizelimit: None,
|
||||
weightlimit: None,
|
||||
curtime: 100,
|
||||
bits: 200,
|
||||
height: 300,
|
||||
});
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplate>(r#"{"version":0,"rules":["a"],"vbavailable":{"b":5},"vbrequired":10,"previousblockhash":"0a00000000000000000000000000000000000000000000000000000000000000","transactions":[{"data":"00010203","txid":null,"hash":null,"depends":null,"fee":null,"sigops":null,"weight":null,"required":false}],"coinbaseaux":{"c":"d"},"coinbasevalue":30,"coinbasetxn":{"data":"555555","txid":"2c00000000000000000000000000000000000000000000000000000000000000","hash":"3700000000000000000000000000000000000000000000000000000000000000","depends":[1],"fee":300,"sigops":400,"weight":500,"required":true},"target":"6400000000000000000000000000000000000000000000000000000000000000","mintime":7,"mutable":["afg"],"noncerange":"00000000ffffffff","sigoplimit":45,"sizelimit":449,"weightlimit":523,"curtime":100,"bits":200,"height":300}"#).unwrap(),
|
||||
BlockTemplate {
|
||||
version: 0,
|
||||
rules: Some(vec!["a".to_owned()]),
|
||||
vbavailable: Some(vec![("b".to_owned(), 5)].into_iter().collect()),
|
||||
vbrequired: Some(10),
|
||||
previousblockhash: H256::from(10),
|
||||
transactions: vec![BlockTemplateTransaction {
|
||||
data: Bytes("00010203".from_hex().unwrap()),
|
||||
txid: None,
|
||||
hash: None,
|
||||
depends: None,
|
||||
fee: None,
|
||||
sigops: None,
|
||||
weight: None,
|
||||
required: false,
|
||||
}],
|
||||
coinbaseaux: Some(vec![("c".to_owned(), "d".to_owned())].into_iter().collect()),
|
||||
coinbasevalue: Some(30),
|
||||
coinbasetxn: Some(BlockTemplateTransaction {
|
||||
data: Bytes("555555".from_hex().unwrap()),
|
||||
txid: Some(H256::from(44)),
|
||||
hash: Some(H256::from(55)),
|
||||
depends: Some(vec![1]),
|
||||
fee: Some(300),
|
||||
sigops: Some(400),
|
||||
weight: Some(500),
|
||||
required: true,
|
||||
}),
|
||||
target: H256::from(100),
|
||||
mintime: Some(7),
|
||||
mutable: Some(vec!["afg".to_owned()]),
|
||||
noncerange: Some("00000000ffffffff".to_owned()),
|
||||
sigoplimit: Some(45),
|
||||
sizelimit: Some(449),
|
||||
weightlimit: Some(523),
|
||||
curtime: 100,
|
||||
bits: 200,
|
||||
height: 300,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// TODO: remove after implementing getblocktmplate RPC
|
||||
#![warn(dead_code)]
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// Block template request mode
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum BlockTemplateRequestMode {
|
||||
/// Work as described in BIP0022:
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki
|
||||
#[serde(rename="template")]
|
||||
Template,
|
||||
/// Work as described in BIP0023:
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki
|
||||
#[serde(rename="proposal")]
|
||||
Proposal,
|
||||
}
|
||||
|
||||
/// Block template request parameters as described in:
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes
|
||||
/// https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki
|
||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
pub struct BlockTemplateRequest {
|
||||
/// Request mode
|
||||
pub mode: Option<BlockTemplateRequestMode>,
|
||||
/// Capabilities, supported by client
|
||||
pub capabilities: Option<HashSet<String>>,
|
||||
/// Softfork deployments, supported by client
|
||||
pub rules: Option<HashSet<String>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn block_template_request_mode_serialize() {
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateRequestMode::Template).unwrap(), r#""template""#);
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateRequestMode::Proposal).unwrap(), r#""proposal""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_request_mode_deserialize() {
|
||||
assert_eq!(serde_json::from_str::<BlockTemplateRequestMode>(r#""template""#).unwrap(), BlockTemplateRequestMode::Template);
|
||||
assert_eq!(serde_json::from_str::<BlockTemplateRequestMode>(r#""proposal""#).unwrap(), BlockTemplateRequestMode::Proposal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_request_serialize() {
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateRequest::default()).unwrap(), r#"{"mode":null,"capabilities":null,"rules":null}"#);
|
||||
assert_eq!(serde_json::to_string(&BlockTemplateRequest {
|
||||
mode: Some(BlockTemplateRequestMode::Template),
|
||||
capabilities: Some(vec!["a".to_owned()].into_iter().collect()),
|
||||
rules: Some(vec!["b".to_owned()].into_iter().collect()),
|
||||
}).unwrap(), r#"{"mode":"template","capabilities":["a"],"rules":["b"]}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_template_request_deserialize() {
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplateRequest>(r#"{"mode":null,"capabilities":null,"rules":null}"#).unwrap(),
|
||||
BlockTemplateRequest {
|
||||
mode: None,
|
||||
capabilities: None,
|
||||
rules: None,
|
||||
});
|
||||
assert_eq!(
|
||||
serde_json::from_str::<BlockTemplateRequest>(r#"{"mode":"template","capabilities":["a"],"rules":["b"]}"#).unwrap(),
|
||||
BlockTemplateRequest {
|
||||
mode: Some(BlockTemplateRequestMode::Template),
|
||||
capabilities: Some(vec!["a".to_owned()].into_iter().collect()),
|
||||
rules: Some(vec!["b".to_owned()].into_iter().collect()),
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
mod block_template;
|
||||
mod block_template_request;
|
||||
mod bytes;
|
||||
mod hash;
|
||||
mod raw_transaction;
|
||||
|
||||
pub use self::block_template::{BlockTemplate, BlockTemplateTransaction};
|
||||
pub use self::block_template_request::{BlockTemplateRequest, BlockTemplateRequestMode};
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::hash::H256;
|
||||
pub use self::raw_transaction::RawTransaction;
|
||||
|
|
Loading…
Reference in New Issue