Skip to content

DNM: NITX Feature #47

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

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions api/src/handlers/blocks_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl HeaderHandler {
)
}
};
match w(&self.chain)?.get_header_for_output(oid.commitment()) {
match w(&self.chain)?.get_header_for_output(oid.id()) {
Ok(header) => Ok(BlockHeaderPrintable::from_header(&header)),
Err(e) => Err(ErrorKind::NotFound(format!(
"Header for output {}, {}",
Expand Down Expand Up @@ -114,7 +114,7 @@ impl HeaderHandler {
return Err(ErrorKind::NotFound(format!("Output {} not found", commit)).into())
}
};
match w(&self.chain)?.get_header_for_output(oid.commitment()) {
match w(&self.chain)?.get_header_for_output(oid.id()) {
Ok(header) => return Ok(header.hash()),
Err(e) => {
return Err(ErrorKind::NotFound(format!(
Expand Down Expand Up @@ -230,7 +230,7 @@ impl BlockHandler {
Some((_, o)) => o,
None => return Err(ErrorKind::NotFound(format!("Output {}", commit)).into()),
};
match w(&self.chain)?.get_header_for_output(oid.commitment()) {
match w(&self.chain)?.get_header_for_output(oid.id()) {
Ok(header) => return Ok(header.hash()),
Err(e) => {
return Err(ErrorKind::NotFound(format!(
Expand Down
19 changes: 11 additions & 8 deletions api/src/handlers/transactions_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use super::utils::w;
use crate::chain;
use crate::core::core::hash::Hashed;
use crate::rest::*;
use crate::router::{Handler, ResponseFuture};
use crate::types::*;
Expand Down Expand Up @@ -132,20 +133,22 @@ impl TxHashSetHandler {
fn get_merkle_proof_for_output(&self, id: &str) -> Result<OutputPrintable, Error> {
let c = util::from_hex(id)
.map_err(|e| ErrorKind::Argument(format!("Not a valid commitment {}, {}", id, e)))?;
let commit = Commitment::from_vec(c);
let commit = Commitment::from_vec(c); // todo: switch to output ID
let output_id = commit.hash();
let chain = w(&self.chain)?;
let output_pos = chain.get_output_pos(&commit).map_err(|e| {
let output_pos = chain.get_output_pos(&output_id).map_err(|e| {
ErrorKind::NotFound(format!(
"Unable to get a MMR position for commit {}, {}",
id, e
))
})?;
let merkle_proof = chain::Chain::get_merkle_proof_for_pos(&chain, commit).map_err(|e| {
ErrorKind::NotFound(format!(
"Unable to get a merkle proof for commit {}, {}",
id, e
))
})?;
let merkle_proof =
chain::Chain::get_merkle_proof_for_pos(&chain, output_id).map_err(|e| {
ErrorKind::NotFound(format!(
"Unable to get a merkle proof for commit {}, {}",
id, e
))
})?;
Ok(OutputPrintable {
output_type: OutputType::Coinbase,
commit: Commitment::from_vec(vec![]),
Expand Down
5 changes: 3 additions & 2 deletions api/src/handlers/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use crate::chain;
use crate::chain::types::CommitPos;
use crate::core::core::hash::Hashed;
use crate::core::core::OutputIdentifier;
use crate::rest::*;
use crate::types::*;
Expand All @@ -36,8 +37,8 @@ fn get_unspent(
) -> Result<Option<(OutputIdentifier, CommitPos)>, Error> {
let c = util::from_hex(id)
.map_err(|_| ErrorKind::Argument(format!("Not a valid commitment: {}", id)))?;
let commit = Commitment::from_vec(c);
let res = chain.get_unspent(commit)?;
let commit = Commitment::from_vec(c); // todo: switch to output ID
let res = chain.get_unspent(commit.hash())?;
Ok(res)
}

Expand Down
4 changes: 2 additions & 2 deletions api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl OutputPrintable {
OutputType::Transaction
};

let pos = chain.get_unspent(output.commitment())?;
let pos = chain.get_unspent(output.id())?;

let spent = pos.is_none();

Expand Down Expand Up @@ -551,7 +551,7 @@ impl TxKernelPrintable {
fee,
lock_height,
excess: k.excess.to_hex(),
excess_sig: (&k.excess_sig.to_raw_data()[..]).to_hex(),
excess_sig: (&k.excess_sig().to_raw_data()[..]).to_hex(),
}
}
}
Expand Down
41 changes: 30 additions & 11 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ impl Chain {
// DB migrations to be run prior to the chain being used.
// Migrate full blocks to protocol version v3.
Chain::migrate_db_v2_v3(&store)?;
// Migrate output positions from commitment-based to ID-based.
Chain::migrate_db_outputs(&store)?;

// open the txhashset, creating a new one if necessary
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?;
Expand Down Expand Up @@ -711,9 +713,9 @@ impl Chain {
/// Returns Err if something went wrong beyond not finding the output.
pub fn get_unspent(
&self,
commit: Commitment,
output_id: Hash,
) -> Result<Option<(OutputIdentifier, CommitPos)>, Error> {
self.txhashset.read().get_unspent(commit)
self.txhashset.read().get_unspent(output_id)
}

/// Retrieves an unspent output using its PMMR position
Expand Down Expand Up @@ -920,9 +922,9 @@ impl Chain {

/// Return a merkle proof valid for the current output pmmr state at the
/// given pos
pub fn get_merkle_proof_for_pos(&self, commit: Commitment) -> Result<MerkleProof, Error> {
pub fn get_merkle_proof_for_pos(&self, output_id: Hash) -> Result<MerkleProof, Error> {
let mut txhashset = self.txhashset.write();
txhashset.merkle_proof(commit)
txhashset.merkle_proof(output_id)
}

/// Provides a reading view into the current txhashset state as well as
Expand Down Expand Up @@ -1412,8 +1414,8 @@ impl Chain {
}

/// Return Commit's MMR position
pub fn get_output_pos(&self, commit: &Commitment) -> Result<u64, Error> {
Ok(self.txhashset.read().get_output_pos(commit)?)
pub fn get_output_pos(&self, output_id: &Hash) -> Result<u64, Error> {
Ok(self.txhashset.read().get_output_pos(&output_id)?)
}

/// outputs by insertion index
Expand All @@ -1439,7 +1441,7 @@ impl Chain {
}
let mut output_vec: Vec<Output> = vec![];
for (ref x, &y) in outputs.1.iter().zip(rangeproofs.1.iter()) {
output_vec.push(Output::new(x.features, x.commitment(), y));
output_vec.push(Output::new_interactive(x.features, x.commitment(), y));
}
Ok((outputs.0, last_index, output_vec))
}
Expand Down Expand Up @@ -1550,16 +1552,33 @@ impl Chain {
Ok(())
}

/// Migrate our local db output position and spent entries from commitment-based to ID-based.
fn migrate_db_outputs(store: &ChainStore) -> Result<(), Error> {
let batch = store.batch()?;
let migrated_positions = batch.migrate_output_positions()?;
debug!(
"migrate_db_outputs: migrated {} output position entries",
migrated_positions
);
let migrated_spent = batch.migrate_spent_commitments()?;
debug!(
"migrate_db_outputs: migrated {} spent commitment entries",
migrated_spent
);
batch.commit()?;
Ok(())
}

/// Gets the block header in which a given output appears in the txhashset.
pub fn get_header_for_output(&self, commit: Commitment) -> Result<BlockHeader, Error> {
pub fn get_header_for_output(&self, output_id: Hash) -> Result<BlockHeader, Error> {
let header_pmmr = self.header_pmmr.read();
let txhashset = self.txhashset.read();
let (_, pos) = match txhashset.get_unspent(commit)? {
let (_, pos) = match txhashset.get_unspent(output_id)? {
Some(o) => o,
None => {
return Err(ErrorKind::OutputNotFound(format!(
"Not found commit {}",
commit.to_hex()
"Not found output {}",
output_id.to_hex()
))
.into())
}
Expand Down
10 changes: 5 additions & 5 deletions chain/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
// limitations under the License.

//! Error types for chain
use crate::core::core::hash::Hash;
use crate::core::core::{block, committed, transaction};
use crate::core::ser;
use crate::keychain;
use crate::util::secp;
use crate::util::secp::pedersen::Commitment;
use failure::{Backtrace, Context, Fail};
use grin_store as store;
use std::fmt::{self, Display};
Expand Down Expand Up @@ -82,10 +82,10 @@ pub enum ErrorKind {
Secp(secp::Error),
/// One of the inputs in the block has already been spent
#[fail(display = "Already Spent: {:?}", _0)]
AlreadySpent(Commitment),
/// An output with that commitment already exists (should be unique)
#[fail(display = "Duplicate Commitment: {:?}", _0)]
DuplicateCommitment(Commitment),
AlreadySpent(Hash),
/// An output with that ID already exists (should be unique)
#[fail(display = "Duplicate Output ID: {:?}", _0)]
DuplicateOutputId(Hash),
/// Attempt to spend a coinbase output before it sufficiently matures.
#[fail(display = "Attempt to spend immature coinbase")]
ImmatureCoinbase,
Expand Down
18 changes: 6 additions & 12 deletions chain/src/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,22 @@ pub fn check_against_spent_output(
header_extension: &txhashset::HeaderExtension<'_>,
batch: &store::Batch<'_>,
) -> Result<(), Error> {
let output_commits = tx.outputs.iter().map(|output| output.identifier.commit);
let output_ids = tx.outputs.iter().map(|output| output.id());
let tip = batch.head().unwrap();
let fork_height = fork_point_height.unwrap_or(tip.height);
//convert the list of local branch bocks header hashes to a hash set for quick search
let local_branch_blocks_list = local_branch_blocks.unwrap_or(Vec::new());
let local_branch_blocks_set = HashSet::<&Hash>::from_iter(local_branch_blocks_list.iter());

for commit in output_commits {
let commit_hash = batch.get_spent_commitments(&commit)?; // check to see if this commitment is in the spent records in db
if let Some(c_hash) = commit_hash {
for id in output_ids {
let id_hash = batch.get_spent_ids(&id)?; // check to see if this output id is in the spent records in db
if let Some(c_hash) = id_hash {
for hash_val in c_hash {
//first check the local branch.
if hash_val.height > fork_height && local_branch_blocks_set.contains(&hash_val.hash)
{
//first check the local branch.
error!(
"output contains spent commtiment:{:?} from local branch",
commit
);
error!("output contains spent id:{:?} from local branch", id);
return Err(ErrorKind::Other(
"output invalid, could be a replay attack".to_string(),
)
Expand All @@ -117,10 +114,7 @@ pub fn check_against_spent_output(
warn!("the height data is messed up in the lmdb");
}
if header_extension.is_on_current_chain(&header, batch).is_ok() {
error!(
"output contains spent commtiment:{:?} from the main chain",
commit
);
error!("output contains spent id:{:?} from the main chain", id);
return Err(ErrorKind::Other(
"output invalid, could be a replay attack".to_string(),
)
Expand Down
Loading