/// <summary> /// 根据block信息更新UTXO pool,同时返回该block生成的utxo list,用来提示该block收到了多少钱 /// </summary> /// <param name="block"></param> /// <returns>just for update key corresponding value</returns> public UTXOPool BlockData2UTXOPool(bool bCommitedPool, Block block) { LogHelper.WriteMethodLog(true); LogHelper.WriteInfoLog("bCommitedPool: " + bCommitedPool.ToString()); UTXOPool utxopoll = new UTXOPool(); if (bCommitedPool) { utxopoll = this.CommitedUtxoPool; } else { utxopoll = this.UnCommitedUtxoPool; } UTXOPool sigleBlockPool = new UTXOPool(); foreach (Transaction eTransaction in block.listTransactions) { foreach (Input eInput in eTransaction.listInputs) { UTXO utxo = this.input2UTXO(eInput); if (utxopoll.contains(utxo)) { utxopoll.removeUTXO(utxo); } else { // 初始化时由于leveldb 树形结构第一个可能创世块,所以先记下来在后面再remove if (utxo.getTxHash() != ConstHelper.BC_BaseCoinInputTxHash) { tempUTXOList.Add(utxo); } } } for (int i = 0; i < eTransaction.listOutputs.Count; i++) { // hash is transaction hash UTXO utxo1 = new UTXO(eTransaction.getHash(), (uint)i); utxopoll.addUTXO(utxo1, eTransaction.listOutputs[i]); sigleBlockPool.addUTXO(utxo1, eTransaction.listOutputs[i]); } } LogHelper.WriteMethodLog(false); return(sigleBlockPool); }
/** * @return true if: * (1) all outputs claimed by {@code tx} are in the current UTXO pool, * (2) the signatures on each input of {@code tx} are valid, * (3) no UTXO is claimed multiple times by {@code tx}, * (4) all of {@code tx}s output values are non-negative, and * (5) the sum of {@code tx}s input values is greater than or equal to the sum of its output * values; and false otherwise. */ public bool isValidTx(Transaction tx) { LogHelper.WriteMethodLog(true); if (tx.listInputs.Count == 0 || tx.listOutputs.Count == 0) { LogHelper.WriteInfoLog("empty input|output"); return(false); } // IMPLEMENT THIS double sumOut = 0; double sumIn = 0; Dictionary <string, UTXO> dicUsed = new Dictionary <string, UTXO>(); for (int i = 0; i < tx.numInputs(); i++) { Input input = tx.getInput(i); UTXO utxo = new UTXO(input.PreTxHash, (uint)input.OutputIndex); if (!CommitedUtxoPool.contains(utxo)) { LogHelper.WriteInfoLog(" utxoPool not contain utxo:"); return(false); //check (1),utox 包含该交易返回false } Output PreOutput = CommitedUtxoPool.getTxOutput(utxo); // the consume coin correspond prev output coin; sumIn += PreOutput.value; //(5) 计算input 指向的pre output 的value,最后保证输入的value等于该笔交易输出的 string strOriginalTxt = tx.getRawDataToSign(i); if (!Cryptor.VerifySignature(input.ScriptSig, PreOutput.scriptPubKey, strOriginalTxt)) { LogHelper.WriteInfoLog(" VerifySignature fail"); return(false);//check(2) } bool bIsContain = dicUsed.ContainsKey(utxo.utoxHashCode()); if (!bIsContain) // UTXO不会被重复添加 { dicUsed.Add(utxo.utoxHashCode(), utxo); } else { LogHelper.WriteInfoLog(" double spend :" + utxo.utoxHashCode()); return(false); } } foreach (Output output in tx.getOutputs()) { if (output.value < 0) { LogHelper.WriteInfoLog(" output.value < 0 "); return(false);//check(5) } sumOut += output.value; } if (sumIn < sumOut) { LogHelper.WriteInfoLog(" sumIn < sumOut "); return(false);//check(5); } LogHelper.WriteInfoLog("Valid Tx"); return(true); }