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); }
internal NodeLauncher(Networks network, ServiceFlags serviceFlag, IRpcNodeFactory rpcNodeFactory, IBlockChainStore blockChainStore, IMessageCoordinator messageCoordinator, ISmartContractStore smartContractStore) { _network = network; _serviceFlag = serviceFlag; _p2pNetworkConnector = new P2PNetworkConnector(messageCoordinator); _p2pNetworkConnector.ConnectEvent += P2PConnectEvent; _p2pNetworkConnector.DisconnectEvent += P2PDisconnectEvent; _p2pNode = new P2PNode(_network, _serviceFlag, _p2pNetworkConnector, messageCoordinator); _rpcNode = rpcNodeFactory.Build(_network); blockChainStore.Switch(network); smartContractStore.Switch(network); _blockChain = blockChainStore.GetBlockChain(); }
public void Check(Block block) { if (block == null) { throw new ArgumentNullException(nameof(block)); } var merkleRoot = block.BlockHeader.MerkleRoot; // Check MERKLE-ROOT. var calculatedMerkleRoot = block.GetMerkleRoot(); if (!merkleRoot.SequenceEqual(calculatedMerkleRoot)) { throw new ValidationException(ErrorCodes.InvalidMerkleRoot); } var blockChain = _blockChainStore.GetBlockChain(); // Check PREVIOUS BLOCK. var currentBlock = blockChain.GetCurrentBlock(); if (!currentBlock.GetHashHeader().SequenceEqual(block.BlockHeader.PreviousBlockHeader)) { throw new ValidationException(ErrorCodes.InvalidPreviousHashHeader); } var hash = currentBlock.GetHashHeader(); var currentNBits = Constants.DEFAULT_NBITS; // TODO : CALCULATE THE DEFAULT NBITS : https://bitcoin.org/en/developer-guide#proof-of-work var target = TargetHelper.GetTarget(currentNBits); if (!TargetHelper.IsValid(hash, target)) { throw new ValidationException(ErrorCodes.NotEnoughDifficult); } foreach (var transaction in block.Transactions) // Check ALL TRANSACTIONS. { _transactionValidator.Check(transaction); } }
private JObject GetBlockTemplate(JObject response) { var transactions = MemoryPool.Instance().GetTransactions(); var blockChain = _blockChainStore.GetBlockChain(); if (transactions == null || !transactions.Any()) { response["result"] = null; return(response); } var currentBlock = blockChain.GetCurrentBlock(); var height = blockChain.GetCurrentBlockHeight(); var previousBlockHash = currentBlock.GetHashHeader().ToHexString(); var transactionBuilder = new TransactionBuilder(); var nonce = BitConverter.GetBytes(NonceHelper.GetNonceUInt64()); var value = transactions.Sum(t => _transactionHelper.GetFee(t.Transaction, _network)); var coinBaseTransaction = transactionBuilder.NewCoinbaseTransaction() .SetInput((uint)height + 1, nonce) .AddOutput(value, Script.CreateCorrectScript()) .Build(); var result = new JObject(); var jTransactions = new JArray(); foreach (var transaction in transactions) { jTransactions.Add(transaction.Transaction.Serialize().ToHexString()); } var currentTime = DateTime.UtcNow.ToUnixTimeUInt32(); var coinBaseTxnObj = new JObject(); coinBaseTxnObj.Add("data", coinBaseTransaction.Serialize().ToHexString()); result.Add("coinbasetxn", coinBaseTxnObj); result.Add("expires", "120"); result.Add("longpollid", ""); result.Add("height", blockChain.GetCurrentBlockHeight() + 1); result.Add("curtime", currentTime); result.Add("previousblockhash", previousBlockHash); result.Add("transactions", jTransactions); result.Add("version", BlockHeader.CURRENT_VERSION); result.Add("target", TargetHelper.GetTarget(Constants.DEFAULT_NBITS).ToHexString()); result.Add("bits", Constants.DEFAULT_NBITS); response["result"] = result; return(response); }
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 Message Receive(Message message, PeerConnector peer, P2PNetworkConnector p2pNetworkConnector) { var blockChain = _blockChainStore.GetBlockChain(); var smartContract = _smartContractStore.GetSmartContracts(); if (message.GetCommandName() == Constants.MessageNames.Version) // RETURNS VERSION. { var msg = message as VersionMessage; var instance = PeersStore.Instance(); var transmittingNode = instance.GetMyIpAddress(); var receivingNode = msg.TransmittingNode; return(new VersionMessage(transmittingNode, receivingNode, msg.Nonce, msg.UserAgent, msg.StartHeight, msg.Relay, msg.MessageHeader.Network)); } if (message.GetCommandName() == Constants.MessageNames.Ping) // RETURNS PONG. { var msg = message as PingMessage; var pong = new PongMessage(msg.Nonce, msg.MessageHeader.Network); return(pong); } if (message.GetCommandName() == Constants.MessageNames.Verack) // RETURNS VERACK MESSAGE. { var msg = message as VerackMessage; return(new VerackMessage(msg.MessageHeader.Network)); } if (message.GetCommandName() == Constants.MessageNames.Addr) // RETURNS THE ADDRS. { var msg = message as AddrMessage; if (msg.IpAddresses != null) { foreach (var ipAddress in msg.IpAddresses) { PeerEventStore.Instance().NewPeer(ipAddress); } } return(null); } if (message.GetCommandName() == Constants.MessageNames.GetAddr) // RETURNS THE ADDRS. { var msg = message as GetAddressMessage; var ipAdrLst = _peersStorage.GetAll(); var response = new AddrMessage(new CompactSize { Size = (ulong)ipAdrLst.Count() }, msg.MessageHeader.Network); foreach (var ipAdr in ipAdrLst) { response.IpAddresses.Add(ipAdr); } return(response); } if (message.GetCommandName() == Constants.MessageNames.MemPool) // RETURNS THE INVENTORY. { var msg = message as MemPoolMessage; var memoryPool = MemoryPool.Instance(); var txIds = memoryPool.GetTransactions().Select(t => t.Transaction.GetTxId()); var inventories = new List <Inventory>(); foreach (var txId in txIds) { inventories.Add(new Inventory(InventoryTypes.MSG_TX, txId)); } return(new InventoryMessage(inventories, msg.MessageHeader.Network)); } if (message.GetCommandName() == Constants.MessageNames.GetData) // RETURNS ALL THE DATA TO THE PEER. { var msg = message as GetDataMessage; var messages = Execute(msg); if (messages != null) { foreach (var m in messages) { peer.Execute(m.Serialize()); } } return(null); } if (message.GetCommandName() == Constants.MessageNames.Transaction) // ADD TRANSACTION INTO MEMORY POOL & BROADCAST IT. { var msg = message as TransactionMessage; AddTransaction(msg.Transaction); MemoryPool.Instance().Remove(msg.Transaction); p2pNetworkConnector.Broadcast(msg.Transaction, msg.MessageHeader.Ipv6); return(null); } if (message.GetCommandName() == Constants.MessageNames.Block) // ADD THE BLOCK. { var msg = message as BlockMessage; _blockValidator.Check(msg.Block); if (msg.Block.Transactions != null) { MemoryPool.Instance().Remove(msg.Block.Transactions.Select(tx => tx.GetTxId())); } smartContract.AddBlock(msg.Block); smartContract.Commit(); blockChain.AddBlock(msg.Block); } if (message.GetCommandName() == Constants.MessageNames.NotFound) // SOME INVENTORIES ARE NOT FOUND. { return(null); } if (message.GetCommandName() == Constants.MessageNames.GetBlocks) // RETURN THE BLOCKS : https://bitcoin.org/en/developer-reference#getblocks { var msg = message as GetBlocksMessage; int lastBlockHeight = -1; foreach (var blockHash in msg.BlockHashes) { lastBlockHeight = blockChain.GetBlockHeight(blockHash); if (lastBlockHeight != -1) { goto Found; } } Found: var currentBlockHeight = blockChain.GetCurrentBlockHeight(); if (currentBlockHeight == lastBlockHeight) { return(new InventoryMessage(new List <Inventory>(), msg.MessageHeader.Network)); } var nbBlocks = currentBlockHeight - lastBlockHeight; if (lastBlockHeight == -1) { nbBlocks = currentBlockHeight - 1; } if (nbBlocks > Constants.DEFAULT_MAX_GET_INVENTORIES) { nbBlocks = Constants.DEFAULT_MAX_GET_INVENTORIES; } var blocks = blockChain.GetLastBlocks(nbBlocks); var inventories = new List <Inventory>(); foreach (var block in blocks) { inventories.Add(new Inventory(InventoryTypes.MSG_BLOCK, block.GetHashHeader())); } return(new InventoryMessage(inventories, msg.MessageHeader.Network)); } return(null); }