From: CryptoManiac Date: Sun, 6 Sep 2015 10:58:28 +0000 (+0300) Subject: FetchInputs X-Git-Url: https://git.novaco.in/?p=NovacoinLibrary.git;a=commitdiff_plain;h=66dee00aa8671fa2676cefdba7c28ba6bded6ba4 FetchInputs --- diff --git a/Novacoin/CBlockStore.cs b/Novacoin/CBlockStore.cs index c636121..e6d5fce 100644 --- a/Novacoin/CBlockStore.cs +++ b/Novacoin/CBlockStore.cs @@ -873,14 +873,24 @@ namespace Novacoin return false; } - public bool FetchInputs(ref CTransaction tx, ref Dictionary queued, out TxOutItem[] inputs, bool IsBlock, out bool Invalid) + interface InputsJoin : ITxOutItem { - Invalid = true; - inputs = null; + byte[] TransactionHash { get; set; } + } + + public bool FetchInputs(ref CTransaction tx, ref Dictionary queued, ref Dictionary inputs, bool IsBlock, out bool Invalid) + { + Invalid = false; + + if (tx.IsCoinBase) + { + // Coinbase transactions have no inputs to fetch. + return true; + } StringBuilder queryBuilder = new StringBuilder(); - queryBuilder.Append("select o.* from [Outputs] o left join [MerkleNodes] m on (m.[nMerkleNodeID] = o.[nMerkleNodeID]) where "); + queryBuilder.Append("select o.*, m.[TransactionHash] from [Outputs] o left join [MerkleNodes] m on (m.[nMerkleNodeID] = o.[nMerkleNodeID]) where "); for (var i = 0; i < tx.vin.Length; i++) { @@ -890,27 +900,71 @@ namespace Novacoin )); } - var queryResults = dbConn.Query(queryBuilder.ToString()); + var queryResults = dbConn.Query(queryBuilder.ToString()); - if (queryResults.Count < tx.vin.Length) + foreach (var item in queryResults) { - // It seems than some transactions are being spent in the same block. + if (item.IsSpent) + { + return false; // Already spent + } + + var inputsKey = new COutPoint(item.TransactionHash, item.nOut); + // Add output data to dictionary + inputs[inputsKey] = new CTxOut(item.nValue, item.scriptPubKey); + } + + if (queryResults.Count < tx.vin.Length) + { if (IsBlock) { - + // It seems that some transactions are being spent in the same block. + + foreach (var txin in tx.vin) + { + var outPoint = txin.prevout; + + if (!queued.ContainsKey(outPoint)) + { + return false; // No such transaction + } + + // Add output data to dictionary + inputs[outPoint] = queued[outPoint]; + + // And remove it from queued data + queued.Remove(outPoint); + } } else { - // TODO: use mapUnconfirmed + // Unconfirmed transaction + + foreach (var txin in tx.vin) + { + var outPoint = txin.prevout; + CTransaction txPrev; + + if (!mapUnconfirmedTx.TryGetValue(outPoint.hash, out txPrev)) + { + return false; // No such transaction + } + + if (outPoint.n > txPrev.vout.Length) + { + Invalid = true; + + return false; // nOut is out of range + } + + inputs[outPoint] = txPrev.vout[outPoint.n]; + } return false; } } - inputs = queryResults.ToArray(); - Invalid = false; - return true; } diff --git a/Novacoin/DatabaseInterfaces.cs b/Novacoin/DatabaseInterfaces.cs new file mode 100644 index 0000000..7405b0d --- /dev/null +++ b/Novacoin/DatabaseInterfaces.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using SQLite.Net; +using SQLite.Net.Attributes; +using SQLite.Net.Interop; +using SQLite.Net.Platform.Generic; +using SQLiteNetExtensions.Attributes; +using System.Collections.Generic; +using System.Diagnostics.Contracts; + +namespace Novacoin +{ + /// + /// Block headers table + /// + public interface IBlockStorageItem + { + /// + /// Item ID in the database + /// + long ItemID { get; set; } + + /// + /// PBKDF2+Salsa20 of block hash + /// + byte[] Hash { get; set; } + + /// + /// Version of block schema + /// + uint nVersion { get; set; } + + /// + /// Previous block hash. + /// + byte[] prevHash { get; set; } + + /// + /// Merkle root hash. + /// + byte[] merkleRoot { get; set; } + + /// + /// Block timestamp. + /// + uint nTime { get; set; } + + /// + /// Compressed difficulty representation. + /// + uint nBits { get; set; } + + /// + /// Nonce counter. + /// + uint nNonce { get; set; } + + /// + /// Next block hash. + /// + byte[] nextHash { get; set; } + + /// + /// Block type flags + /// + BlockType BlockTypeFlag { get; set; } + + /// + /// Stake modifier + /// + long nStakeModifier { get; set; } + + /// + /// Proof-of-Stake hash + /// + byte[] hashProofOfStake { get; set; } + + /// + /// Stake generation outpoint. + /// + byte[] prevoutStake { get; set; } + + /// + /// Stake generation time. + /// + uint nStakeTime { get; set; } + + /// + /// Block height + /// + byte[] Height { get; set; } + + /// + /// Block position in file + /// + byte[] BlockPos { get; set; } + + /// + /// Block size in bytes + /// + byte[] BlockSize { get; set; } + }; + + public interface IMerkleNode + { + /// + /// Node identifier + /// + long nMerkleNodeID { get; set; } + + /// + /// Reference to parent block database item. + /// + long nParentBlockID { get; set; } + + /// + /// Transaction type flag + /// + TxFlags TransactionFlags { get; set; } + + /// + /// Transaction hash + /// + byte[] TransactionHash { get; set; } + + /// + /// Transaction offset from the beginning of block header, encoded in VarInt format. + /// + byte[] TxOffset { get; set; } + + /// + /// Transaction size, encoded in VarInt format. + /// + byte[] TxSize { get; set; } + } + + public interface ITxOutItem + { + /// + /// Reference to transaction item. + /// + long nMerkleNodeID { get; set; } + + /// + /// Output flags + /// + OutputFlags outputFlags { get; set; } + + /// + /// Output number in VarInt format. + /// + byte[] OutputNumber { get; set; } + + /// + /// Output value in VarInt format. + /// + byte[] OutputValue { get; set; } + + /// + /// Second half of script which contains spending instructions. + /// + byte[] scriptPubKey { get; set; } + + /// + /// Getter for output number. + /// + uint nOut { get; } + + /// + /// Getter for output value. + /// + ulong nValue { get; } + + /// + /// Getter ans setter for IsSpent flag. + /// + bool IsSpent { get; set; } + } + +}