basic reorg protection

(cherry picked from commit e3696ed73c2012f20205b98099f397ad799fcff4)
This commit is contained in:
scilio
2024-04-02 19:46:46 -04:00
parent 389581d759
commit d1ae6863f8
4 changed files with 1422 additions and 1272 deletions
+26 -7
View File
@@ -4,13 +4,14 @@ use grin_api::json_rpc::{build_request, Request, Response};
use grin_api::{client, LocatedTxKernel};
use grin_api::{OutputPrintable, OutputType, Tip};
use grin_core::consensus::COINBASE_MATURITY;
use grin_core::core::{Input, OutputFeatures, Transaction};
use grin_core::core::{Committed, Input, OutputFeatures, Transaction};
use grin_util::ToHex;
use async_trait::async_trait;
use serde_json::json;
use std::net::SocketAddr;
use std::sync::Arc;
use grin_core::core::hash::Hash;
use thiserror::Error;
#[async_trait]
@@ -21,8 +22,8 @@ pub trait GrinNode: Send + Sync {
output_commit: &Commitment,
) -> Result<Option<OutputPrintable>, NodeError>;
/// Gets the height of the chain tip
async fn async_get_chain_height(&self) -> Result<u64, NodeError>;
/// Gets the height and hash of the chain tip
async fn async_get_chain_tip(&self) -> Result<(u64, Hash), NodeError>;
/// Posts a transaction to the grin node
async fn async_post_tx(&self, tx: &Transaction) -> Result<(), NodeError>;
@@ -108,6 +109,23 @@ pub async fn async_build_input(
Ok(None)
}
pub async fn async_is_tx_valid(node: &Arc<dyn GrinNode>, tx: &Transaction) -> Result<bool, NodeError> {
let next_block_height = node.async_get_chain_tip().await?.0 + 1;
for input_commit in &tx.inputs_committed() {
if !async_is_spendable(&node, &input_commit, next_block_height).await? {
return Ok(false);
}
}
for output_commit in &tx.outputs_committed() {
if async_is_unspent(&node, &output_commit).await? {
return Ok(false);
}
}
Ok(true)
}
/// HTTP (JSON-RPC) implementation of the 'GrinNode' trait
#[derive(Clone)]
pub struct HttpGrinNode {
@@ -176,7 +194,7 @@ impl GrinNode for HttpGrinNode {
Ok(Some(outputs[0].clone()))
}
async fn async_get_chain_height(&self) -> Result<u64, NodeError> {
async fn async_get_chain_tip(&self) -> Result<(u64, Hash), NodeError> {
let params = json!([]);
let tip_json = self
.async_send_request::<serde_json::Value>("get_tip", &params)
@@ -184,7 +202,7 @@ impl GrinNode for HttpGrinNode {
let tip =
serde_json::from_value::<Tip>(tip_json).map_err(NodeError::DecodeResponseError)?;
Ok(tip.height)
Ok((tip.height, Hash::from_hex(tip.last_block_pushed.as_str()).unwrap()))
}
async fn async_post_tx(&self, tx: &Transaction) -> Result<(), NodeError> {
@@ -226,6 +244,7 @@ pub mod mock {
use grin_onion::crypto::secp::Commitment;
use std::collections::HashMap;
use std::sync::RwLock;
use grin_core::core::hash::Hash;
/// Implementation of 'GrinNode' trait that mocks a grin node instance.
/// Use only for testing purposes.
@@ -299,8 +318,8 @@ pub mod mock {
Ok(None)
}
async fn async_get_chain_height(&self) -> Result<u64, NodeError> {
Ok(100)
async fn async_get_chain_tip(&self) -> Result<(u64, Hash), NodeError> {
Ok((100, Hash::default()))
}
async fn async_post_tx(&self, tx: &Transaction) -> Result<(), NodeError> {