Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: segregated witness #368

Merged
merged 2 commits into from
Apr 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 37 additions & 19 deletions core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,38 @@ impl Block {

ids.into_iter().collect()
}

pub fn cal_witnesses_root(&self) -> H256 {
// The witness hash of cellbase transaction is assumed to be zero 0x0000....0000
let mut witnesses = vec![H256::zero()];
witnesses.extend(
self.commit_transactions()
.iter()
.skip(1)
.map(|tx| tx.witness_hash()),
);
merkle_root(&witnesses[..])
}

pub fn cal_txs_commit_root(&self) -> H256 {
merkle_root(
&self
.commit_transactions
.iter()
.map(|t| t.hash())
.collect::<Vec<_>>(),
)
}

pub fn cal_txs_proposal_root(&self) -> H256 {
merkle_root(
&self
.proposal_transactions
.iter()
.map(|t| t.hash())
.collect::<Vec<_>>(),
)
}
}

impl ::std::hash::Hash for Block {
Expand Down Expand Up @@ -133,29 +165,15 @@ impl BlockBuilder {
}

pub fn with_header_builder(mut self, header_builder: HeaderBuilder) -> Block {
let txs_commit = merkle_root(
&self
.inner
.commit_transactions
.iter()
.map(|t| t.hash())
.collect::<Vec<_>>(),
);

let txs_proposal = merkle_root(
&self
.inner
.proposal_transactions
.iter()
.map(|t| t.hash())
.collect::<Vec<_>>(),
);

let uncles_hash = uncles_hash(&self.inner.uncles);
let txs_commit = self.inner.cal_txs_commit_root();
let witnesses_root = self.inner.cal_witnesses_root();
let txs_proposal = self.inner.cal_txs_proposal_root();
let uncles_hash = self.inner.cal_uncles_hash();

self.inner.header = header_builder
.txs_commit(txs_commit)
.txs_proposal(txs_proposal)
.witnesses_root(witnesses_root)
.uncles_hash(uncles_hash)
.uncles_count(self.inner.uncles.len() as u32)
.build();
Expand Down
15 changes: 15 additions & 0 deletions core/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct RawHeader {
txs_commit: H256,
/// Transactions proposal merkle root.
txs_proposal: H256,
/// Witness hash commitment.
witnesses_root: H256,
/// Block difficulty.
difficulty: U256,
/// Hash of the cellbase
Expand Down Expand Up @@ -112,6 +114,10 @@ impl fmt::Debug for Header {
"txs_proposal",
&format_args!("{:#x}", self.raw.txs_proposal),
)
.field(
"witnesses_root",
&format_args!("{:#x}", self.raw.witnesses_root),
)
.field("difficulty", &format_args!("{:#x}", self.raw.difficulty))
.field("cellbase_id", &format_args!("{:#x}", self.raw.cellbase_id))
.field("uncles_hash", &format_args!("{:#x}", self.raw.uncles_hash))
Expand Down Expand Up @@ -174,6 +180,10 @@ impl Header {
&self.raw.txs_proposal
}

pub fn witnesses_root(&self) -> &H256 {
&self.raw.witnesses_root
}

pub fn cellbase_id(&self) -> &H256 {
&self.raw.cellbase_id
}
Expand Down Expand Up @@ -268,6 +278,11 @@ impl HeaderBuilder {
self
}

pub fn witnesses_root(mut self, hash: H256) -> Self {
self.inner.raw.witnesses_root = hash;
self
}

pub fn cellbase_id(mut self, hash: H256) -> Self {
self.inner.raw.cellbase_id = hash;
self
Expand Down
214 changes: 143 additions & 71 deletions core/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,91 +141,35 @@ impl CellOutput {
}
}

pub type Witness = Vec<Vec<u8>>;

#[derive(Clone, Serialize, Deserialize, Eq, Debug, Default, OccupiedCapacity)]
pub struct Transaction {
version: Version,
deps: Vec<OutPoint>,
inputs: Vec<CellInput>,
outputs: Vec<CellOutput>,
//Segregated Witness to provide protection from transaction malleability.
witnesses: Vec<Witness>,
}

#[derive(Serialize)]
struct RawTransaction<'a> {
version: Version,
deps: &'a [OutPoint],
inputs: &'a [CellInput],
outputs: &'a [CellOutput],
}

impl Hash for Transaction {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(self.hash().as_fixed_bytes())
state.write(self.witness_hash().as_fixed_bytes())
}
}

impl PartialEq for Transaction {
fn eq(&self, other: &Transaction) -> bool {
self.hash() == other.hash()
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct IndexTransaction {
pub index: usize,
pub transaction: Transaction,
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Default, Hash)]
pub struct ProposalShortId([u8; 10]);

impl Deref for ProposalShortId {
type Target = [u8; 10];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl fmt::Debug for ProposalShortId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ProposalShortId(0x{})",
hex_string(&self.0).expect("hex proposal short id")
)
}
}

impl DerefMut for ProposalShortId {
fn deref_mut(&mut self) -> &mut [u8; 10] {
&mut self.0
}
}

impl ProposalShortId {
pub fn new(inner: [u8; 10]) -> Self {
ProposalShortId(inner)
}

pub fn from_slice(slice: &[u8]) -> Option<Self> {
if slice.len() == 10usize {
let mut id = [0u8; 10];
id.copy_from_slice(slice);
Some(ProposalShortId(id))
} else {
None
}
}

pub fn from_h256(h: &H256) -> Self {
let v = h.to_vec();
let mut inner = [0u8; 10];
inner.copy_from_slice(&v[..10]);
ProposalShortId(inner)
}

pub fn hash(&self) -> H256 {
blake2b_256(serialize(self).expect("ProposalShortId serialize should not fail")).into()
}

pub fn zero() -> Self {
ProposalShortId([0; 10])
}

pub fn into_inner(self) -> [u8; 10] {
self.0
self.witness_hash() == other.witness_hash()
}
}

Expand All @@ -246,11 +190,25 @@ impl Transaction {
&self.outputs
}

pub fn witnesses(&self) -> &[Witness] {
&self.witnesses
}

pub fn is_cellbase(&self) -> bool {
self.inputs.len() == 1 && self.inputs[0].previous_output.is_null()
}

pub fn hash(&self) -> H256 {
let raw = RawTransaction {
version: self.version,
deps: &self.deps,
inputs: &self.inputs,
outputs: &self.outputs,
};
blake2b_256(serialize(&raw).expect("Transaction serialize should not fail")).into()
}

pub fn witness_hash(&self) -> H256 {
blake2b_256(serialize(&self).expect("Transaction serialize should not fail")).into()
}

Expand Down Expand Up @@ -284,8 +242,9 @@ impl Transaction {
self.inputs.is_empty() || self.outputs.is_empty()
}

// proposal_short_id
pub fn proposal_short_id(&self) -> ProposalShortId {
ProposalShortId::from_h256(&self.hash())
ProposalShortId::from_tx_hash(&self.hash())
}

pub fn get_output(&self, i: usize) -> Option<CellOutput> {
Expand Down Expand Up @@ -364,7 +323,120 @@ impl TransactionBuilder {
self
}

pub fn witness(mut self, witness: Witness) -> Self {
self.inner.witnesses.push(witness);
self
}

pub fn witnesses(mut self, witness: Vec<Witness>) -> Self {
self.inner.witnesses.extend(witness);
self
}

pub fn witnesses_clear(mut self) -> Self {
self.inner.witnesses.clear();
self
}

pub fn build(self) -> Transaction {
self.inner
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct IndexTransaction {
pub index: usize,
pub transaction: Transaction,
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Default, Hash)]
pub struct ProposalShortId([u8; 10]);

impl Deref for ProposalShortId {
type Target = [u8; 10];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl fmt::Debug for ProposalShortId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ProposalShortId(0x{})",
hex_string(&self.0).expect("hex proposal short id")
)
}
}

impl DerefMut for ProposalShortId {
fn deref_mut(&mut self) -> &mut [u8; 10] {
&mut self.0
}
}

impl ProposalShortId {
pub fn new(inner: [u8; 10]) -> Self {
ProposalShortId(inner)
}

pub fn from_slice(slice: &[u8]) -> Option<Self> {
if slice.len() == 10usize {
let mut id = [0u8; 10];
id.copy_from_slice(slice);
Some(ProposalShortId(id))
} else {
None
}
}

pub fn from_tx_hash(h: &H256) -> Self {
let v = h.to_vec();
let mut inner = [0u8; 10];
inner.copy_from_slice(&v[..10]);
ProposalShortId(inner)
}

pub fn hash(&self) -> H256 {
blake2b_256(serialize(self).expect("ProposalShortId serialize should not fail")).into()
}

pub fn zero() -> Self {
ProposalShortId([0; 10])
}

pub fn into_inner(self) -> [u8; 10] {
self.0
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_tx_hash() {
let tx = TransactionBuilder::default()
.output(CellOutput::new(
5000,
vec![1, 2, 3],
Script::default(),
None,
))
.input(CellInput::new(OutPoint::new(H256::zero(), 0), vec![]))
.witness(vec![vec![7, 8, 9]])
.build();

assert_eq!(
tx.hash(),
H256::from_hex_str("7e1e256d6882809b7dfb55d002e54c5b4fbdbbbe8ce906aa6eae1b429de4d3d8")
.unwrap()
);
assert_eq!(
tx.witness_hash(),
H256::from_hex_str("93d363096f3901651b718d093751aa78ce7b56274850841a3e4134fe14ffb120")
.unwrap()
);
}
}
Loading