예제 #1
0
        //拼交易体
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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;
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }