Merge pull request #270 from ethcore/rpc_block_template

Rpc block template
This commit is contained in:
Marek Kotewicz 2016-12-09 14:22:45 +01:00 committed by GitHub
commit da80c69a80
3 changed files with 356 additions and 0 deletions

View File

@ -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,
});
}
}

View File

@ -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()),
});
}
}

View File

@ -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;