//拼交易体 static Transaction makeTran(Dictionary <string, List <Utxo> > dir_utxos, string[] targetaddrs, ThinNeo.Hash256 assetid, decimal sendcount) { if (!dir_utxos.ContainsKey(assetid.ToString())) { throw new Exception("no enough money."); } List <Utxo> utxos = dir_utxos[assetid.ToString()]; var tran = new Transaction(); tran.type = TransactionType.ContractTransaction; tran.version = 0;//0 or 1 tran.extdata = null; tran.attributes = new ThinNeo.Attribute[0]; utxos.Sort((a, b) => { if (a.value > b.value) { return(1); } else if (a.value < b.value) { return(-1); } else { return(0); } }); //十进制小数 decimal count = decimal.Zero; string scraddr = ""; List <ThinNeo.TransactionInput> list_inputs = new List <ThinNeo.TransactionInput>(); for (var i = 0; i < utxos.Count; i++) { ThinNeo.TransactionInput input = new ThinNeo.TransactionInput(); input.hash = utxos[i].txid; input.index = (ushort)utxos[i].n; list_inputs.Add(input); count += utxos[i].value; scraddr = utxos[i].addr; if (count >= (sendcount)) { break; } } tran.inputs = list_inputs.ToArray(); if (count >= sendcount)//输入大于等于输出 { List <ThinNeo.TransactionOutput> list_outputs = new List <ThinNeo.TransactionOutput>(); //输出 if (sendcount > decimal.Zero && targetaddrs.Length > 0) { foreach (string targetaddr in targetaddrs) { ThinNeo.TransactionOutput output = new ThinNeo.TransactionOutput(); output.assetId = assetid; output.value = sendcount; output.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(targetaddr); list_outputs.Add(output); } } //找零 var change = count - sendcount; if (change > decimal.Zero) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(scraddr); outputchange.value = change; outputchange.assetId = assetid; list_outputs.Add(outputchange); } tran.outputs = list_outputs.ToArray(); } else { throw new Exception("no enough money."); } return(tran); }
public static ThinNeo.Transaction makeGasTran(ref List <Utxo> list_Gas, Dictionary <string, string> usedUtxoDic, Hash256 assetid, decimal gasfee) { var tran = new ThinNeo.Transaction(); tran.type = ThinNeo.TransactionType.ContractTransaction; tran.version = 0;//0 or 1 tran.attributes = new ThinNeo.Attribute[0]; var scraddr = ""; decimal count = decimal.Zero; List <ThinNeo.TransactionInput> list_inputs = new List <ThinNeo.TransactionInput>(); for (var i = list_Gas.Count - 1; i >= 0; i--) { if (usedUtxoDic.ContainsKey(list_Gas[i].txid.ToString() + list_Gas[i].n)) { continue; } ThinNeo.TransactionInput input = new ThinNeo.TransactionInput(); input.hash = list_Gas[i].txid; input.index = (ushort)list_Gas[i].n; list_inputs.Add(input); count += list_Gas[i].value; scraddr = list_Gas[i].addr; list_Gas.Remove(list_Gas[i]); if (count >= gasfee) { break; } } tran.inputs = list_inputs.ToArray(); if (count >= gasfee)//输入大于等于输出 { List <ThinNeo.TransactionOutput> list_outputs = new List <ThinNeo.TransactionOutput>(); //输出 //if (gasfee > decimal.Zero && targetaddr != null) //{ // ThinNeo.TransactionOutput output = new ThinNeo.TransactionOutput(); // output.assetId = assetid; // output.value = gasfee; // output.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(targetaddr); // list_outputs.Add(output); //} //找零 var change = count - gasfee; if (change > decimal.Zero) { decimal splitvalue = (decimal)0.01; int i = 0; while (change > splitvalue && list_Gas.Count - 10 < usedUtxoDic.Count) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(scraddr); outputchange.value = splitvalue; outputchange.assetId = assetid; list_outputs.Add(outputchange); change -= splitvalue; i += 1; if (i > 50) { break; } } if (change > 0) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(scraddr); outputchange.value = change; outputchange.assetId = assetid; list_outputs.Add(outputchange); } } tran.outputs = list_outputs.ToArray(); } else { throw new Exception("no enough money."); } return(tran); }
public void Deserialize(System.IO.Stream ms) { //参考源码来自 // https://github.com/neo-project/neo // Transaction.cs // 源码采用c#序列化技术 //参考源码2 // https://github.com/AntSharesSDK/antshares-ts // Transaction.ts // 采用typescript开发 this.type = (TransactionType)ms.ReadByte(); //读一个字节,交易类型 this.version = (byte)ms.ReadByte(); if (this.type == TransactionType.ContractTransaction) //每个交易类型有一些自己独特的处理 { //ContractTransaction 就是最常见的合约交易, //他没有自己的独特处理 extdata = null; } else if (this.type == TransactionType.InvocationTransaction) { extdata = new InvokeTransData(); } else { throw new Exception("未编写针对这个交易类型的代码"); } if (extdata != null) { extdata.Deserialize(this, ms); } //attributes var countAttributes = readVarInt(ms); this.attributes = new Attribute[countAttributes]; Console.WriteLine("countAttributes:" + countAttributes); for (UInt64 i = 0; i < countAttributes; i++) { //读取attributes byte[] attributeData; var Usage = (TransactionAttributeUsage)ms.ReadByte(); if (Usage == TransactionAttributeUsage.ContractHash || Usage == TransactionAttributeUsage.Vote || (Usage >= TransactionAttributeUsage.Hash1 && Usage <= TransactionAttributeUsage.Hash15)) { attributeData = new byte[32]; ms.Read(attributeData, 0, 32); } else if (Usage == TransactionAttributeUsage.ECDH02 || Usage == TransactionAttributeUsage.ECDH03) { attributeData = new byte[33]; attributeData[0] = (byte)Usage; ms.Read(attributeData, 1, 32); } else if (Usage == TransactionAttributeUsage.Script) { attributeData = new byte[20]; ms.Read(attributeData, 0, 20); } else if (Usage == TransactionAttributeUsage.DescriptionUrl) { var len = (byte)ms.ReadByte(); attributeData = new byte[len]; ms.Read(attributeData, 0, len); } else if (Usage == TransactionAttributeUsage.Description || Usage >= TransactionAttributeUsage.Remark) { var len = (int)readVarInt(ms, 65535); attributeData = new byte[len]; ms.Read(attributeData, 0, len); } else { throw new FormatException(); } } //inputs 输入表示基于哪些交易 var countInputs = readVarInt(ms); Console.WriteLine("countInputs:" + countInputs); this.inputs = new TransactionInput[countInputs]; for (UInt64 i = 0; i < countInputs; i++) { this.inputs[i] = new TransactionInput(); this.inputs[i].hash = new byte[32]; byte[] buf = new byte[2]; ms.Read(this.inputs[i].hash, 0, 32); ms.Read(buf, 0, 2); UInt16 index = (UInt16)(buf[1] * 256 + buf[0]); this.inputs[i].index = index; } //outputes 输出表示最后有哪几个地址得到多少钱,肯定有一个是自己的地址,因为每笔交易都会把之前交易的余额清空,刨除自己,就是要转给谁多少钱 //这个机制叫做UTXO var countOutputs = readVarInt(ms); Console.WriteLine("countOutputs:" + countOutputs); this.outputs = new TransactionOutput[countOutputs]; for (UInt64 i = 0; i < countOutputs; i++) { this.outputs[i] = new TransactionOutput(); TransactionOutput outp = this.outputs[i]; //资产种类 var assetid = new byte[32]; ms.Read(assetid, 0, 32); byte[] buf = new byte[8]; ms.Read(buf, 0, 8); var value = Fixed8.FromBytes(buf, 0); //资产数量 var scripthash = new byte[20]; ms.Read(scripthash, 0, 20); outp.assetId = assetid; outp.value = value; outp.toAddress = scripthash; this.outputs[i] = outp; } }
private static ThinNeo.Transaction makeTran(List <Utxo> utxos, string targetaddr, ThinNeo.Hash256 assetid, decimal sendcount, decimal extgas = 0, List <Utxo> utxos_ext = null, string extaddr = null) { var tran = new ThinNeo.Transaction(); tran.type = ThinNeo.TransactionType.ContractTransaction; if (extgas >= 1) { tran.version = 1;//0 or 1 } else { tran.version = 0;//0 or 1 } tran.extdata = null; tran.attributes = new ThinNeo.Attribute[0]; var scraddr = ""; utxos.Sort((a, b) => { if (a.value > b.value) { return(1); } else if (a.value < b.value) { return(-1); } else { return(0); } }); decimal count = decimal.Zero; List <ThinNeo.TransactionInput> list_inputs = new List <ThinNeo.TransactionInput>(); for (var i = 0; i < utxos.Count; i++) { ThinNeo.TransactionInput input = new ThinNeo.TransactionInput(); input.hash = utxos[i].txid; input.index = (ushort)utxos[i].n; list_inputs.Add(input); count += utxos[i].value; scraddr = utxos[i].addr; if (count >= sendcount) { break; } } decimal count_ext = decimal.Zero; if (utxos_ext != null) { //手续费 ThinNeo.TransactionInput input = new ThinNeo.TransactionInput(); input.hash = utxos_ext[0].txid; input.index = (ushort)utxos_ext[0].n; count_ext = utxos_ext[0].value; list_inputs.Add(input); } tran.inputs = list_inputs.ToArray(); if (count >= sendcount)//输入大于等于输出 { List <ThinNeo.TransactionOutput> list_outputs = new List <ThinNeo.TransactionOutput>(); //输出 if (sendcount > decimal.Zero && targetaddr != null) { ThinNeo.TransactionOutput output = new ThinNeo.TransactionOutput(); output.assetId = assetid; output.value = sendcount; output.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(targetaddr); list_outputs.Add(output); } var change = count - sendcount - extgas; decimal extchange = decimal.Zero; //找零 if (utxos_ext != null) { change = count - sendcount; extchange = count_ext - extgas; } else { change = count - sendcount - extgas; } if (change > decimal.Zero) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(scraddr); outputchange.value = change; outputchange.assetId = assetid; list_outputs.Add(outputchange); } if (extchange > decimal.Zero) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = ThinNeo.Helper.GetPublicKeyHashFromAddress(extaddr); outputchange.value = extchange; outputchange.assetId = assetid; list_outputs.Add(outputchange); } tran.outputs = list_outputs.ToArray(); } else { throw new Exception("no enough money."); } return(tran); }
private Transaction MakeTran_Hasfee(Transaction tran, decimal systemfee, decimal netfee) { string assetid = id_GAS; List <Utxo> utxos = GetUtxo(Address, assetid); tran.attributes = new ThinNeo.Attribute[0]; utxos.Sort((a, b) => { if (a.value > b.value) { return(1); } else if (a.value < b.value) { return(-1); } else { return(0); } }); decimal count = decimal.Zero; List <ThinNeo.TransactionInput> list_inputs = new List <ThinNeo.TransactionInput>(); for (var i = 0; i < utxos.Count; i++) { ThinNeo.TransactionInput input = new ThinNeo.TransactionInput(); input.hash = utxos[i].txid; input.index = (ushort)utxos[i].n; list_inputs.Add(input); count += utxos[i].value; if (count >= netfee + systemfee) { break; } } tran.inputs = list_inputs.ToArray(); if (count >= netfee + systemfee)//输入大于等于输出 { List <ThinNeo.TransactionOutput> list_outputs = new List <ThinNeo.TransactionOutput>(); //找零 decimal change = count - netfee - systemfee; if (change > decimal.Zero) { ThinNeo.TransactionOutput outputchange = new ThinNeo.TransactionOutput(); outputchange.toAddress = SciptHash; outputchange.value = change; outputchange.assetId = new Hash256(id_GAS); list_outputs.Add(outputchange); } tran.outputs = list_outputs.ToArray(); } else { throw new Exception("no enough money."); } return(tran); }
public static Transaction FromBytes(byte[] data) { Transaction tdata = null; //参考源码来自 // https://github.com/neo-project/neo // Transaction.cs // 源码采用c#序列化技术 //参考源码2 // https://github.com/AntSharesSDK/antshares-ts // Transaction.ts // 采用typescript开发 System.IO.MemoryStream ms = new System.IO.MemoryStream(data); tdata.type = (TransactionType)ms.ReadByte();//读一个字节,交易类型 Console.WriteLine("datatype:" + tdata.type); byte version = (byte)ms.ReadByte(); Console.WriteLine("dataver:" + version); if (tdata.type == TransactionType.ContractTransaction)//每个交易类型有一些自己独特的处理 { //ContractTransaction 就是最常见的合约交易, //他没有自己的独特处理 } else { throw new Exception("未编写针对这个交易类型的代码"); } //attributes var countAttributes = readVarInt(ms); Console.WriteLine("countAttributes:" + countAttributes); for (UInt64 i = 0; i < countAttributes; i++) { //读取attributes byte[] attributeData; var Usage = (TransactionAttributeUsage)ms.ReadByte(); if (Usage == TransactionAttributeUsage.ContractHash || Usage == TransactionAttributeUsage.Vote || (Usage >= TransactionAttributeUsage.Hash1 && Usage <= TransactionAttributeUsage.Hash15)) { attributeData = new byte[32]; ms.Read(attributeData, 0, 32); } else if (Usage == TransactionAttributeUsage.ECDH02 || Usage == TransactionAttributeUsage.ECDH03) { attributeData = new byte[33]; attributeData[0] = (byte)Usage; ms.Read(attributeData, 1, 32); } else if (Usage == TransactionAttributeUsage.Script) { attributeData = new byte[20]; ms.Read(attributeData, 0, 20); } else if (Usage == TransactionAttributeUsage.DescriptionUrl) { var len = (byte)ms.ReadByte(); attributeData = new byte[len]; ms.Read(attributeData, 0, len); } else if (Usage == TransactionAttributeUsage.Description || Usage >= TransactionAttributeUsage.Remark) { var len = (int)readVarInt(ms, 65535); attributeData = new byte[len]; ms.Read(attributeData, 0, len); } else { throw new FormatException(); } } //inputs 输入表示基于哪些交易 var countInputs = readVarInt(ms); Console.WriteLine("countInputs:" + countInputs); for (UInt64 i = 0; i < countInputs; i++) { byte[] hash = new byte[32]; byte[] buf = new byte[2]; ms.Read(hash, 0, 32); ms.Read(buf, 0, 2); UInt16 index = (UInt16)(buf[1] * 256 + buf[0]); hash = hash.Reverse().ToArray();//反转 var strhash = Helper.Bytes2HexString(hash); Console.WriteLine(" input:" + strhash + " index:" + index); } //outputes 输出表示最后有哪几个地址得到多少钱,肯定有一个是自己的地址,因为每笔交易都会把之前交易的余额清空,刨除自己,就是要转给谁多少钱 //这个机制叫做UTXO var countOutputs = readVarInt(ms); Console.WriteLine("countOutputs:" + countOutputs); tdata.outputs = new TransactionOutput[countOutputs]; for (UInt64 i = 0; i < countOutputs; i++) { TransactionOutput outp = new TransactionOutput(); //资产种类 var assetid = new byte[32]; ms.Read(assetid, 0, 32); assetid = assetid.Reverse().ToArray(); //反转 UInt64 value = 0; //钱的数字是一个定点数,乘以D Int64 D = 100000000; byte[] buf = new byte[8]; ms.Read(buf, 0, 8); value = BitConverter.ToUInt64(buf, 0); decimal number = ((decimal)value / (decimal)D); if (number <= 0) { throw new FormatException(); } //资产数量 var scripthash = new byte[20]; ms.Read(scripthash, 0, 20); var address = Helper.GetAddressFromScriptHash(scripthash); outp.assetId = assetid; //Helper.Bytes2HexString(assetid); outp.value = value; outp.toAddress = scripthash; tdata.outputs[i] = outp; Console.WriteLine(" output" + i + ":" + Helper.Bytes2HexString(assetid) + "=" + number); Console.WriteLine(" address:" + address); } return(tdata); }