liquid: Add preliminary conditional support for Elements data structures

This makes the code properly compile with the "liquid" feature flag enabled,
but it is still broken in all sorts of ways and missing some functionality.
This commit is contained in:
Nadav Ivgi 2019-01-24 10:17:15 +02:00
parent dbceb53634
commit b455f5c026
5 changed files with 133 additions and 32 deletions

View File

@ -624,8 +624,8 @@ impl Daemon {
let header = self
.getblockheader(&blockhash)
.chain_err(|| format!("failed to get {} header", blockhash))?;
new_headers.push(header);
blockhash = header.prev_blockhash;
new_headers.push(header);
}
trace!("downloaded {} block headers", new_headers.len());
new_headers.reverse(); // so the tip is the last vector entry

View File

@ -123,14 +123,25 @@ impl Mempool {
}
match entry {
#[cfg(not(feature="liquid"))]
TxHistoryInfo::Funding(info) => {
stats.funded_txo_count += 1;
stats.funded_txo_sum += info.value;
}
#[cfg(feature="liquid")]
TxHistoryInfo::Funding(_) => {
stats.funded_txo_count += 1;
}
#[cfg(not(feature="liquid"))]
TxHistoryInfo::Spending(info) => {
stats.spent_txo_count += 1;
stats.spent_txo_sum += info.value;
}
#[cfg(feature="liquid")]
TxHistoryInfo::Spending(_) => {
stats.spent_txo_count += 1;
}
};
}

View File

@ -7,6 +7,9 @@ use crypto::sha2::Sha256;
use itertools::Itertools;
use rayon::prelude::*;
#[cfg(feature="liquid")]
use elements::confidential::Value;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::path::Path;
use std::sync::{Arc, RwLock};
@ -16,7 +19,7 @@ use crate::daemon::Daemon;
use crate::errors::*;
use crate::metrics::{HistogramOpts, HistogramTimer, HistogramVec, Metrics};
use crate::util::{
full_hash, BlockHeaderMeta, BlockMeta, BlockStatus, Bytes, HeaderEntry, HeaderList,
is_coinbase, full_hash, BlockHeaderMeta, BlockMeta, BlockStatus, Bytes, HeaderEntry, HeaderList,
};
use crate::new_index::db::{DBFlush, DBRow, ScanIterator, DB};
@ -77,8 +80,11 @@ impl From<&HeaderEntry> for BlockId {
pub struct Utxo {
pub txid: Sha256dHash,
pub vout: u32,
pub value: u64,
pub confirmed: Option<BlockId>,
#[cfg(not(feature="liquid"))]
pub value: u64,
#[cfg(feature="liquid")]
pub value: Value,
}
impl From<&Utxo> for OutPoint {
@ -98,8 +104,10 @@ pub struct SpendingInput {
pub struct ScriptStats {
pub tx_count: usize,
pub funded_txo_count: usize,
pub funded_txo_sum: u64,
pub spent_txo_count: usize,
#[cfg(not(feature="liquid"))]
pub funded_txo_sum: u64,
#[cfg(not(feature="liquid"))]
pub spent_txo_sum: u64,
}
@ -108,8 +116,10 @@ impl ScriptStats {
ScriptStats {
tx_count: 0,
funded_txo_count: 0,
funded_txo_sum: 0,
spent_txo_count: 0,
#[cfg(not(feature="liquid"))]
funded_txo_sum: 0,
#[cfg(not(feature="liquid"))]
spent_txo_sum: 0,
}
}
@ -427,14 +437,25 @@ impl ChainQuery {
}
match history.key.txinfo {
#[cfg(not(feature="liquid"))]
TxHistoryInfo::Funding(ref info) => {
stats.funded_txo_count += 1;
stats.funded_txo_sum += info.value;
}
#[cfg(feature="liquid")]
TxHistoryInfo::Funding(_) => {
stats.funded_txo_count += 1;
}
#[cfg(not(feature="liquid"))]
TxHistoryInfo::Spending(ref info) => {
stats.spent_txo_count += 1;
stats.spent_txo_sum += info.value;
}
#[cfg(feature="liquid")]
TxHistoryInfo::Spending(_) => {
stats.spent_txo_count += 1;
}
};
lastblock = Some(blockid.hash);
@ -636,7 +657,7 @@ fn get_previous_txos(block_entries: &[BlockEntry]) -> BTreeSet<OutPoint> {
.flat_map(|b| {
b.block.txdata.iter().flat_map(|tx| {
tx.input.iter().filter_map(|txin| {
if txin.previous_output.is_null() {
if is_coinbase(txin) {
None
} else {
Some(txin.previous_output)
@ -718,7 +739,7 @@ fn index_transaction(
}
}
for (txi_index, txi) in tx.input.iter().enumerate() {
if txi.previous_output.is_null() {
if is_coinbase(txi) {
continue;
}
let prev_txo = previous_txos_map
@ -955,7 +976,10 @@ impl BlockRow {
pub struct FundingInfo {
pub txid: FullHash, // funding transaction
pub vout: u16,
#[cfg(not(feature="liquid"))]
pub value: u64,
#[cfg(feature="liquid")]
pub value: Value,
}
#[derive(Serialize, Deserialize)]
@ -964,7 +988,10 @@ pub struct SpendingInfo {
pub vin: u16,
pub prev_txid: FullHash, // funding transaction
pub prev_vout: u16,
#[cfg(not(feature="liquid"))]
pub value: u64,
#[cfg(feature="liquid")]
pub value: Value,
}
#[derive(Serialize, Deserialize)]

View File

@ -3,7 +3,7 @@ use crate::config::Config;
use crate::errors;
use crate::new_index::{compute_script_hash, BlockId, Query, SpendingInput, Utxo};
use crate::util::{
full_hash, get_script_asm, script_to_address, BlockHeaderMeta, FullHash, TransactionStatus,
is_coinbase, full_hash, get_script_asm, script_to_address, BlockHeaderMeta, FullHash, TransactionStatus,
};
use bitcoin::consensus::encode::{self, serialize};
@ -17,6 +17,9 @@ use hyper::rt::{self, Future};
use hyper::service::service_fn_ok;
use hyper::{Body, Method, Request, Response, Server, StatusCode};
#[cfg(feature="liquid")]
use elements::confidential::Value;
use serde::Serialize;
use serde_json;
use std::collections::BTreeMap;
@ -39,13 +42,15 @@ struct BlockValue {
height: u32,
version: u32,
timestamp: u32,
bits: u32,
nonce: u32,
tx_count: u32,
size: u32,
weight: u32,
merkle_root: String,
previousblockhash: Option<String>,
#[cfg(not(feature="liquid"))]
nonce: u32,
#[cfg(not(feature="liquid"))]
bits: u32,
}
impl From<BlockHeaderMeta> for BlockValue {
@ -56,8 +61,6 @@ impl From<BlockHeaderMeta> for BlockValue {
height: blockhm.header_entry.height() as u32,
version: header.version,
timestamp: header.time,
bits: header.bits,
nonce: header.nonce,
tx_count: blockhm.meta.tx_count,
size: blockhm.meta.size,
weight: blockhm.meta.weight,
@ -67,6 +70,11 @@ impl From<BlockHeaderMeta> for BlockValue {
} else {
None
},
#[cfg(not(feature="liquid"))]
bits: header.bits,
#[cfg(not(feature="liquid"))]
nonce: header.nonce,
}
}
}
@ -134,12 +142,17 @@ struct TxInValue {
impl From<TxIn> for TxInValue {
fn from(txin: TxIn) -> Self {
let script = txin.script_sig;
#[cfg(not(feature="liquid"))]
let witness = if txin.witness.len() > 0 {
Some(txin.witness.iter().map(|w| hex::encode(w)).collect())
} else {
None
};
#[cfg(feature="liquid")]
let witness = None; // @TODO
let is_coinbase = is_coinbase(&txin);
let script = txin.script_sig;
TxInValue {
txid: txin.previous_output.txid,
@ -147,8 +160,8 @@ impl From<TxIn> for TxInValue {
prevout: None, // added later
scriptsig_asm: get_script_asm(&script),
scriptsig: script,
witness: witness,
is_coinbase: txin.previous_output.is_null(),
witness,
is_coinbase,
sequence: txin.sequence,
}
}
@ -158,14 +171,33 @@ impl From<TxIn> for TxInValue {
struct TxOutValue {
scriptpubkey: Script,
scriptpubkey_asm: String,
value: u64,
scriptpubkey_address: Option<String>,
scriptpubkey_type: String,
#[cfg(not(feature="liquid"))]
value: u64,
#[cfg(feature="liquid")]
value: Option<u64>,
#[cfg(feature="liquid")]
valuecommitment: Option<String>,
}
impl From<TxOut> for TxOutValue {
fn from(txout: TxOut) -> Self {
#[cfg(not(feature="liquid"))]
let value = txout.value;
#[cfg(feature="liquid")]
let value = match txout.value {
Value::Explicit(value) => Some(value),
_ => None,
};
#[cfg(feature="liquid")]
let valuecommitment = match txout.value {
Value::Confidential(..) => Some(hex::encode(serialize(&txout.value))),
_ => None,
};
let script = txout.script_pubkey;
let script_asm = get_script_asm(&script);
@ -195,6 +227,8 @@ impl From<TxOut> for TxOutValue {
scriptpubkey_address: None, // added later
scriptpubkey_type: script_type.to_string(),
value,
#[cfg(feature="liquid")]
valuecommitment,
}
}
}
@ -203,17 +237,37 @@ impl From<TxOut> for TxOutValue {
struct UtxoValue {
txid: Sha256dHash,
vout: u32,
value: u64,
status: TransactionStatus,
#[cfg(not(feature="liquid"))]
value: u64,
#[cfg(feature="liquid")]
value: Option<u64>,
#[cfg(feature="liquid")]
valuecommitment: Option<String>,
}
impl From<Utxo> for UtxoValue {
fn from(utxo: Utxo) -> Self {
#[cfg(not(feature="liquid"))]
let value = utxo.value;
#[cfg(feature="liquid")]
let value = match utxo.value {
Value::Explicit(value) => Some(value),
_ => None,
};
#[cfg(feature="liquid")]
let valuecommitment = match utxo.value {
Value::Confidential(..) => Some(hex::encode(serialize(&utxo.value))),
_ => None,
};
UtxoValue {
txid: utxo.txid,
vout: utxo.vout,
value: utxo.value,
value,
status: TransactionStatus::from(utxo.confirmed),
// utxo.script is also available but is unused here
#[cfg(feature="liquid")]
valuecommitment,
}
}
}
@ -307,19 +361,21 @@ fn attach_txs_data(txs: &mut Vec<TransactionValue>, config: &Config, query: &Que
}
// attach tx fee
if config.prevout_enabled {
for mut tx in txs.iter_mut() {
if tx.vin.iter().any(|vin| vin.prevout.is_none()) {
continue;
}
#[cfg(not(feature="liquid"))] {
if config.prevout_enabled {
for mut tx in txs.iter_mut() {
if tx.vin.iter().any(|vin| vin.prevout.is_none()) {
continue;
}
let total_in: u64 = tx
.vin
.iter()
.map(|vin| vin.clone().prevout.unwrap().value)
.sum();
let total_out: u64 = tx.vout.iter().map(|vout| vout.value).sum();
tx.fee = Some(total_in - total_out);
let total_in: u64 = tx
.vin
.iter()
.map(|vin| vin.clone().prevout.unwrap().value)
.sum();
let total_out: u64 = tx.vout.iter().map(|vout| vout.value).sum();
tx.fee = Some(total_in - total_out);
}
}
}
}

View File

@ -1,4 +1,4 @@
use crate::chain::{Block, BlockHeader};
use crate::chain::{Block, BlockHeader, TxIn};
use crate::errors::*;
use crate::new_index::{BlockEntry, BlockId};
@ -433,3 +433,10 @@ pub fn get_script_asm(script: &Script) -> String {
let asm = format!("{:?}", script);
(&asm[7..asm.len() - 1]).to_string()
}
pub fn is_coinbase(txin: &TxIn) -> bool {
#[cfg(not(feature="liquid"))]
return txin.previous_output.is_null();
#[cfg(feature="liquid")]
return txin.is_coinbase();
}