public NoneCoinbaseTransactionBuilder Spend(BcBaseTransaction transaction, UInt32 index, IEnumerable <byte> signatureScript, uint sequence = 0xffffffff) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } if (index < 0) { // TODO : THROW } if (transaction.TransactionOut.Count() > index) { // TODO : THROW } if (signatureScript == null) { throw new ArgumentNullException(nameof(signatureScript)); } var txId = transaction.GetTxId(); return(Spend(txId, index, signatureScript, sequence)); }
public void WhenGetUnspentTransactionsTwoBlocks() { RemoveBlockChain(); var serviceProvider = BuildServiceProvider(); var blockChainFactory = serviceProvider.GetService <IBlockChainFactory>(); var blockChain = blockChainFactory.Build(_network); var genesisBlock = blockChain.GetCurrentBlock(); var firstTransaction = genesisBlock.Transactions.First() as BcBaseTransaction; var firstTransactionOut = firstTransaction.TransactionOut.First(); var genesisKey = KeyStore.GetGenesisKey(); var genesisAdr = new BlockChainAddress(_scriptTypes, _network, genesisKey); // Create block chain address. var destinationBlockChainAddress = GenerateBlockChainAddress(); var minerBlockChainAddress = GenerateBlockChainAddress(); var signature = genesisKey.GetSignature(); // Create the script. var scriptBuilder = new ScriptBuilder(); var genesisScript = scriptBuilder .New() .AddToStack(signature) .AddToStack(genesisKey.GetPublicKey()) .Build(); var destinationScript = Script.CreateP2PKHScript(destinationBlockChainAddress.PublicKeyHash); var minerScript = Script.CreateP2PKHScript(minerBlockChainAddress.PublicKeyHash); var genesisScriptDest = Script.CreateP2PKHScript(genesisKey.GetPublicKeyHashed()); var transactionBuilder = new TransactionBuilder(); var coinBaseTransaction = transactionBuilder // Add COIN-BASE TRANSACTION. .NewCoinbaseTransaction() .SetBlockNumber(1) .AddOutput(1, minerScript) .Build(); var noneCoinBaseTransaction = transactionBuilder // ADD GENESIS (10 BTC) => DESTINATION TRANSACTION. .NewNoneCoinbaseTransaction() .Spend(firstTransaction, 0, genesisScript.Serialize()) .AddOutput(10, destinationScript) .Build(); var otherCoinBaseTransaction = transactionBuilder .NewNoneCoinbaseTransaction() .Spend(firstTransaction, 0, genesisScript.Serialize()) .AddOutput(39, genesisScriptDest) .Build(); var nonce = NonceHelper.GetNonceUInt32(); // CREATE A BLOCK. var block = new Block(genesisBlock.GetHashHeader(), Constants.DEFAULT_NBITS, nonce); block.Transactions.Add(coinBaseTransaction); block.Transactions.Add(noneCoinBaseTransaction); block.Transactions.Add(otherCoinBaseTransaction); var a = noneCoinBaseTransaction.Serialize().ToArray(); var b = BcBaseTransaction.Deserialize(a); block.UpdateMerkleRoot(); blockChain.AddBlock(block); var unspentTransactions = blockChain.GetUnspentTransactions(); Assert.IsNotNull(unspentTransactions); Assert.IsTrue(unspentTransactions.Count() == 3); Assert.IsTrue(unspentTransactions.Sum(t => t.Value) == 50); }
public void Broadcast(BcBaseTransaction transaction) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } _p2pNetworkConnector.Broadcast(transaction); }
public void WhenBuildNoneCoinbaseTransaction() { var ba = BuildBlockChainAddress(); var builder = new TransactionBuilder(); var transaction = builder.NewNoneCoinbaseTransaction() .AddOutput(20, Script.CreateP2PKHScript(ba.PublicKeyHash)) .Build(); var serializedTransaction = transaction.Serialize(); var deserializedTransaction = BcBaseTransaction.Deserialize(serializedTransaction); }
public TransactionOut GetTransactionIn(BcBaseTransaction transaction, IEnumerable <BlockChainAddress> bcAddrs, Networks network) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } if (bcAddrs == null) { throw new ArgumentNullException(nameof(bcAddrs)); } var publicKeyHashes = bcAddrs.Select(bcAddr => bcAddr.PublicKeyHash); var blockChain = _blockChainStore.GetBlockChain(); var memPool = MemoryPool.Instance(); foreach (var txIn in transaction.TransactionIn) { var nCbtxIn = txIn as TransactionInNoneCoinbase; if (nCbtxIn == null || nCbtxIn.Outpoint == null) { continue; } var previousTx = blockChain.GetTransaction(nCbtxIn.Outpoint.Hash); TransactionOut previousTxOut = null; BcBaseTransaction monetaryTransaction = null; if (previousTx == null || (monetaryTransaction = (previousTx as BcBaseTransaction)) == null || monetaryTransaction.TransactionOut == null) { previousTxOut = memPool.GetUnspentTransaction(nCbtxIn.Outpoint.Hash, nCbtxIn.Outpoint.Index); if (previousTxOut == null || (monetaryTransaction = (previousTx as BcBaseTransaction)) == null) { continue; } } else { previousTxOut = monetaryTransaction.TransactionOut.ElementAtOrDefault((int)nCbtxIn.Outpoint.Index); } if (previousTxOut == null || previousTxOut.Script == null || publicKeyHashes.All(publicKeyHash => !previousTxOut.Script.ContainsPublicKeyHash(publicKeyHash))) { continue; } return(previousTxOut); } return(null); }
public MemoryPoolRecord GetUnspentMemoryRecord(IEnumerable <byte> txId, uint index) { if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index)); } var referencedTx = GetUnspentMemoryRecord(txId); BcBaseTransaction transaction = null; if (referencedTx == null || (transaction = referencedTx.Transaction as BcBaseTransaction) == null || index >= transaction.TransactionOut.Count()) { return(null); } return(referencedTx); }
public long CalculateBalance(BcBaseTransaction transaction, IEnumerable <BlockChainAddress> bcAddrs, Networks network) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } if (bcAddrs == null) { throw new ArgumentNullException(nameof(bcAddrs)); } var txIn = GetTransactionIn(transaction, bcAddrs, network) as TransactionOut; var publicKeyHashes = bcAddrs.Select(bcAddr => bcAddr.PublicKeyHash); TransactionOut txOut = null; foreach (var transactionOut in transaction.TransactionOut) { var script = transactionOut.Script; if (publicKeyHashes.Any(publicKeyHash => script.ContainsPublicKeyHash(publicKeyHash))) { txOut = transactionOut as TransactionOut; } } var noneCoinBaseTransaction = transaction as NoneCoinbaseTransaction; if (noneCoinBaseTransaction != null) { if (txOut == null) { return(0); } return(-(txIn.Value - txOut.Value)); } if (txOut == null) { return(0); } return(txOut.Value); }
public TransactionOut GetTransactionIn(BcBaseTransaction transaction, Networks network) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } var blockChain = _blockChainStore.GetBlockChain(); foreach (var txIn in transaction.TransactionIn) { var nCbtxIn = txIn as TransactionInNoneCoinbase; if (nCbtxIn == null || nCbtxIn.Outpoint == null) { continue; } var previousTx = blockChain.GetTransaction(nCbtxIn.Outpoint.Hash); TransactionOut previousTxOut = null; BcBaseTransaction monetaryTransaction = null; if (previousTx == null || (monetaryTransaction = (previousTx as BcBaseTransaction)) == null || monetaryTransaction.TransactionOut == null) { previousTxOut = MemoryPool.Instance().GetUnspentTransaction(nCbtxIn.Outpoint.Hash, nCbtxIn.Outpoint.Index); if (previousTxOut == null || (monetaryTransaction = (previousTx as BcBaseTransaction)) == null) { continue; } } else { previousTxOut = monetaryTransaction.TransactionOut.ElementAtOrDefault((int)nCbtxIn.Outpoint.Index); if (previousTxOut == null || previousTxOut.Script == null) { continue; } } return(previousTxOut); } return(null); }
public long GetFee(BcBaseTransaction transaction, Networks network) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } var outputValue = transaction.TransactionOut.Where(t => t is TransactionOut).Sum(t => (t as TransactionOut).Value); // TRANSACTION FEE + REWARD. long inputValue = 0; var txIn = GetTransactionIn(transaction, network) as TransactionOut; if (txIn != null) { inputValue = txIn.Value; } var leftValue = inputValue - outputValue; var reward = GetReward(transaction); var result = reward + leftValue; return(result); }
public void Check(BcBaseTransaction transaction) { if (transaction == null) { throw new ArgumentNullException(nameof(transaction)); } var blockChain = _blockChainStore.GetBlockChain(); var memoryPool = MemoryPool.Instance(); var isCoinBaseTransaction = transaction is CoinbaseTransaction; // https://bitcoin.org/en/developer-guide#block-chain-overview if (!isCoinBaseTransaction && (transaction.TransactionIn == null || !transaction.TransactionIn.Any())) { throw new ValidationException(ErrorCodes.NoTransactionIn); } if (!isCoinBaseTransaction) { long totalOutput = 0; foreach (var txIn in transaction.TransactionIn) { var noneCoinBaseTxIn = txIn as TransactionInNoneCoinbase; // Check TRANSACTION EXISTS IN BLOCK CHAIN & MEMORY POOL. var previousTxId = noneCoinBaseTxIn.Outpoint.Hash; var previousIndex = noneCoinBaseTxIn.Outpoint.Index; /* * if (memoryPool.ContainsTransactions(previousTxId, previousIndex)) * { * throw new ValidationException(ErrorCodes.AlreadySpentInMemoryPool); * } */ var previousTxOut = blockChain.GetUnspentTransaction(previousTxId, previousIndex); if (previousTxOut == null) { var r = memoryPool.GetUnspentTransaction(previousTxId, previousIndex) as TransactionOut; if (r == null) { throw new ValidationException(ErrorCodes.ReferencedTransactionNotValid); } previousTxOut = new UTXO { Index = (int)previousIndex, Script = r.Script, TxId = transaction.GetTxId(), Value = r.Value }; } var sigScript = Script.Deserialize(noneCoinBaseTxIn.SignatureScript); // Check SCRIPT. var pkScript = previousTxOut.Script; if (!_scriptInterpreter.Check(sigScript, pkScript)) { throw new ValidationException(ErrorCodes.TransactionSignatureNotCorrect); } totalOutput += previousTxOut.Value; } var sumOutput = transaction.TransactionOut.Where(t => t is TransactionOut).Sum(t => ((TransactionOut)t).Value); if (sumOutput > totalOutput) { throw new ValidationException(ErrorCodes.TransactionOutputExceedInput); } } }
public TransactionBuilder(BcBaseTransaction transaction) { Transaction = transaction; }