public string CreatPrimitiveTx(List <Input> lstInput, double dValue, string strPay2Hash, ref Transaction PrimitiveTx) { LogHelper.WriteMethodLog(true); double inputValue = 0; foreach (var item in lstInput) { UTXO utxo = new UTXO(item.PreTxHash, (uint)item.OutputIndex); Output tempoutput = this.CommitedUtxoPool.getTxOutput(utxo); inputValue += tempoutput.value; } if (inputValue != dValue) { LogHelper.WriteErrorLog(string.Format("Input Utxo's value not equal with output value, inputV:{0}, outputV:{1}", inputValue, dValue)); return("Input Utxo's value not equal with output value"); } PrimitiveTx.listInputs = lstInput; string Pay2Script = string.Format("OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG", strPay2Hash); Output output = new Output(dValue, Pay2Script); PrimitiveTx.addOutput(output); LogHelper.WriteInfoLog("MultiSign TX: " + JsonHelper.Serializer <Transaction>(PrimitiveTx)); LogHelper.WriteMethodLog(false); return(ConstHelper.BC_OK); }
// // @return the transaction output corresponding to UTXO {@code utxo}, or null if {@code utxo} is // not in the pool. public Output getTxOutput(UTXO ut) { Output optemp = new Output(); if (dicUtxoPool.TryGetValue(ut, out optemp)) { return(optemp); } return(null); }
public void AddBaseCoin2UTxoPool(Transaction basetx) { try { UTXO utxo = new UTXO(basetx.getHash(), 0); CommitedUtxoPool.addUTXO(utxo, basetx.getOutput((int)0)); } catch (Exception ex) { LogHelper.WriteErrorLog(ex.Message); } }
public void removeInput(UTXO ut) { for (int i = 0; i < listInputs.Count(); i++) { Input inEnty = listInputs[i]; UTXO u = new UTXO(inEnty.PreTxHash, (uint)inEnty.OutputIndex); if (u.Equals(ut)) { listInputs.RemoveAt(i); return; } } }
/// <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); }
/** * Handles each epoch by receiving an unordered array of proposed transactions, checking each * transaction for correctness, returning a mutually valid array of accepted transactions, and * updating the current UTXO pool as appropriate. */ public Transaction[] handleTxs(List <Transaction> possibleTxs) { // IMPLEMENT THIS HashSet <Transaction> txVis = new HashSet <Transaction>(); //fixed point algorithm,iter untill no new transaction is valid while (true) { bool updated = false; foreach (Transaction tx in possibleTxs) { if (txVis.Contains(tx)) { continue; } if (isValidTx(tx)) { txVis.Add(tx); updated = true; //add unspent coin for (uint i = 0; i < tx.numOutputs(); ++i) { UTXO utxo = new UTXO(tx.getHash(), i); CommitedUtxoPool.addUTXO(utxo, tx.getOutput((int)i)); } //delete spent coin for (int i = 0; i < tx.numInputs(); ++i) { Input input = tx.getInput(i); UTXO utxo = new UTXO(input.PreTxHash, (uint)input.OutputIndex); CommitedUtxoPool.removeUTXO(utxo); } } } if (!updated) { break; } } ; Transaction[] ret = new Transaction[txVis.Count()]; int idx = 0; foreach (Transaction tx in txVis) { ret[idx++] = tx; } return(ret); }
// Adds a mapping from UTXO {@code utxo} to transaction output @code{txOut} to the pool public void addUTXO(UTXO utxo, Output txOut) { try { if (!dicUtxoPool.ContainsKey(utxo)) { dicUtxoPool.Add(utxo, txOut); } } catch (Exception ex) { string str = JsonHelper.Serializer <UTXO>(utxo); LogHelper.WriteErrorLog(str); LogHelper.WriteErrorLog(ex.Message); } }
//Compares this UTXO to the one specified by {@code other}, considering them equal if they have // {@code txHash} arrays with equal contents and equal {@code index} values public override bool Equals(Object other) { if (other == null) { return(false); } UTXO otherUtxo = (UTXO)other; // 直接对比hash是否一致 if (this.utoxHashCode() != otherUtxo.utoxHashCode()) { return(false); } else { return(true); } }
public Transaction CreatTransaction(string strPreHash, uint iIndex, double dValue, string strPaytoPKHash, string myPriKeyPath, string myPubkeyPath) { LogHelper.WriteMethodLog(true); string strPubKeyValuem = FileIOHelper.ReadFromText(myPubkeyPath); string strKeyHash = Cryptor.SHA256(strPubKeyValuem, strPubKeyValuem.Length); string myPubScript = string.Format("OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG", strKeyHash); UTXO utxo = new UTXO(strPreHash, iIndex); if (!this.CommitedUtxoPool.contains(utxo)) { LogHelper.WriteErrorLog("not in utxo"); return(null); } Transaction spendTrans = new Transaction(); spendTrans.addInput(strPreHash, (int)iIndex); spendTrans.addOutput(dValue, strPaytoPKHash); Output preOutput = this.CommitedUtxoPool.getTxOutput(utxo); if (dValue < preOutput.value) { Output ctOutput = new Output(); ctOutput.value = preOutput.value - dValue; ctOutput.scriptPubKey = myPubScript; spendTrans.addOutput(ctOutput); } spendTrans.signTrans(myPriKeyPath, strPubKeyValuem); spendTrans.FinalSetTrans(); LogHelper.WriteInfoLog("CreatTransaction: " + spendTrans.TxHash); return(spendTrans); }
/// <summary> /// /// </summary> /// <param name="signedPrimitiveTx"></param> /// <returns>0:succ, -1:not multiSign, -2:sign not enough -3: signature more than M </returns> public int CheckMultiSignCount(Transaction signedPrimitiveTx, ref string errorMsg) { int i = 0; foreach (var item in signedPrimitiveTx.listInputs) { UTXO utxo1 = new UTXO(item.PreTxHash, (uint)item.OutputIndex); Output output1 = this.CommitedUtxoPool.getTxOutput(utxo1); var lstScript = output1.scriptPubKey.Split(' ').ToList <string>(); if (lstScript.Last() != "OP_CHECKMULTISIG") { LogHelper.WriteErrorLog("input isn't MultiSign Tx "); errorMsg = "one of inputs isn't MultiSign Tx"; return(-1); } string OP_N = lstScript.First(); string OP_M = lstScript[lstScript.Count - 2]; int N = int.Parse(OP_N.Substring(3)); int M = int.Parse(OP_M.Substring(3)); if (item.lstScriptSig.Count < N) { LogHelper.WriteErrorLog(string.Format("input[{0}] signature count not meet mini request", i)); errorMsg = string.Format("input:[{0}]\r\n is a {1}/{2} Tx.\r\nThe number of signatures({3}) did not meet the minimum requirements", item.PreTxHash, N, M, item.lstScriptSig.Count); return(-2); } else if (item.lstScriptSig.Count > M) { LogHelper.WriteErrorLog(string.Format("input[{0}] signature more than M", i)); errorMsg = "The number of signatures more than M"; return(-3); } i++; } return(0); }
public string handleTxs(Transaction tx) { try { string sRet = ConstHelper.BC_OK; if (isValidTx(tx)) { //add unspent coin for (uint i = 0; i < tx.numOutputs(); ++i) { UTXO utxo = new UTXO(tx.getHash(), i); UnCommitedUtxoPool.addUTXO(utxo, tx.getOutput((int)i)); LogHelper.WriteInfoLog(string.Format("Add utxo to uncommited pool, utxoHash:{0}", utxo.utoxHashCode())); } //delete spent coin for (int i = 0; i < tx.numInputs(); ++i) { Input input = tx.getInput(i); UTXO utxo = new UTXO(input.PreTxHash, (uint)input.OutputIndex); CommitedUtxoPool.removeUTXO(utxo); LogHelper.WriteInfoLog(string.Format("Remove utxo from commited pool, utxoHash:{0}", utxo.utoxHashCode())); } } else { sRet = "invalid transaction"; } LogHelper.WriteInfoLog("handleTxs result:" + sRet); return(sRet); } catch (Exception ex) { LogHelper.WriteErrorLog(ex.Message); return("HandleTxs catch an exception "); } }
//暂时不用 public bool SignPrimitiveTx(Dictionary <UTXO, keyPair> dicUTXO, ref Transaction PrimitiveTx) { int iInputCount = PrimitiveTx.listInputs.Count; for (int i = 0; i < iInputCount; i++) { if (PrimitiveTx.listInputs[i].ScriptSig == null) { UTXO utxo = new UTXO(PrimitiveTx.listInputs[i].PreTxHash, (uint)PrimitiveTx.listInputs[i].OutputIndex); if (dicUTXO.ContainsKey(utxo)) { keyPair kp = new keyPair(); dicUTXO.TryGetValue(utxo, out kp); string strPriKPath = Path.Combine(AppSettings.XXPKeysFolder, kp.PriKeyNmae); string strPubKPath = Path.Combine(AppSettings.XXPKeysFolder, kp.PubKeyNmae); string strPubValue = FileIOHelper.ReadFromText(strPubKPath); PrimitiveTx.signTrans(strPriKPath, strPubValue, i); } } } return(true); }
// @return true if UTXO {@code utxo} is in the pool and false otherwise public bool contains(UTXO utxo) { return(dicUtxoPool.ContainsKey(utxo)); }
public string SignPrimitiveTx(Dictionary <string, keyPair> KeyHashKeypair, ref Transaction PrimitiveTx) { LogHelper.WriteMethodLog(true); bool bHaveSigned = true; foreach (var item in PrimitiveTx.listInputs) { // 只要input有一个没有签名list,就认为没有签名 if (item.lstScriptSig == null) { bHaveSigned = false; break; } else { // 有签名list后 判断自己是否已经签名, bHaveSigned = false; foreach (var item1 in item.lstScriptSig) { string strKeyHash = Cryptor.SHA256(item1.PubKey, item1.PubKey.Length); if (KeyHashKeypair.ContainsKey(strKeyHash)) { bHaveSigned = true; } } } } if (bHaveSigned) { return("Current Primitive Tx'inputs Have signed"); } int iInputCount = PrimitiveTx.listInputs.Count; for (int i = 0; i < iInputCount; i++) { UTXO utxo = new UTXO(PrimitiveTx.listInputs[i].PreTxHash, (uint)PrimitiveTx.listInputs[i].OutputIndex); if (!CommitedUtxoPool.contains(utxo)) { LogHelper.WriteInfoLog(" utxoPool not contain utxo:"); return("Invalid utxo"); //check (1),utox 包含该交易返回false } Output output = CommitedUtxoPool.getTxOutput(utxo); List <string> lstScript = output.scriptPubKey.Split(' ').ToList <string>(); var lstPKHash = (from x in lstScript where x.Substring(0, 3) != "OP_" select x).ToList(); foreach (var item in lstPKHash) { if (KeyHashKeypair.ContainsKey(item)) { keyPair kp = new keyPair(); KeyHashKeypair.TryGetValue(item, out kp); string strPriKPath = Path.Combine(AppSettings.XXPKeysFolder, kp.PriKeyNmae); string strPubKPath = Path.Combine(AppSettings.XXPKeysFolder, kp.PubKeyNmae); string strPubValue = FileIOHelper.ReadFromText(strPubKPath); PrimitiveTx.MultiSignTrans(strPriKPath, strPubValue, i); } } } LogHelper.WriteMethodLog(false); return(ConstHelper.BC_OK); }
/** * @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); }
public UTXO input2UTXO(Input einput) { UTXO utxo = new UTXO(einput.PreTxHash, (uint)einput.OutputIndex); return(utxo); }
// Removes the UTXO {@code utxo} from the pool public void removeUTXO(UTXO utxo) { dicUtxoPool.Remove(utxo); }