示例#1
0
        /// <summary>
        /// Combine creates a network-specific transaction from an unsigned transaction and an array of provided signatures.
        /// The signed transaction returned from this method will be sent to the `/construction/submit` endpoint by the caller.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public JObject ConstructionCombine(ConstructionCombineRequest request)
        {
            NeoTransaction neoTx;

            try
            {
                byte[]          unsigned = request.UnsignedTransaction.HexToBytes();
                TransactionType type     = (TransactionType)unsigned[0];
                switch (type)
                {
                case TransactionType.ClaimTransaction:
                    neoTx = new ClaimTransaction();
                    break;

                case TransactionType.ContractTransaction:
                    neoTx = new ContractTransaction();
                    break;

                case TransactionType.StateTransaction:
                    neoTx = new StateTransaction();
                    break;

                case TransactionType.InvocationTransaction:
                    neoTx = new InvocationTransaction();
                    break;

                default:
                    throw new ArgumentException();
                }
                using (MemoryStream ms = new MemoryStream(unsigned, false))
                    using (BinaryReader br = new BinaryReader(ms, Encoding.UTF8))
                    {
                        (neoTx as IVerifiable).DeserializeUnsigned(br);
                    }
            }
            catch (Exception)
            {
                return(Error.TX_DESERIALIZE_ERROR.ToJson());
            }

            if (neoTx.Witnesses != null && neoTx.Witnesses.Length > 0)
            {
                return(Error.TX_ALREADY_SIGNED.ToJson());
            }

            if (request.Signatures.Length == 0)
            {
                return(Error.NO_SIGNATURE.ToJson());
            }

            Witness witness;

            if (request.Signatures.Length == 1) // single signed
            {
                witness = CreateSignatureWitness(request.Signatures[0]);
            }
            else
            {
                witness = CreateMultiSignatureWitness(request.Signatures);
            }

            if (witness is null)
            {
                return(Error.INVALID_SIGNATURES.ToJson());
            }

            neoTx.Witnesses = new Witness[] { witness };
            byte[] signed = neoTx.ToArray();
            ConstructionCombineResponse response = new ConstructionCombineResponse(signed.ToHexString());

            return(response.ToJson());
        }
示例#2
0
        /// <summary>
        /// Combine creates a network-specific transaction from an unsigned transaction and an array of provided signatures.
        /// The signed transaction returned from this method will be sent to the `/construction/submit` endpoint by the caller.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public JObject ConstructionCombine(ConstructionCombineRequest request)
        {
            if (request.NetworkIdentifier?.Blockchain?.ToLower() != "neo n3")
            {
                return(Error.NETWORK_IDENTIFIER_INVALID.ToJson());
            }
            if (request.NetworkIdentifier?.Network?.ToLower() != network)
            {
                return(Error.NETWORK_IDENTIFIER_INVALID.ToJson());
            }

            NeoTransaction neoTx;

            try
            {
                byte[] txRaw = Convert.FromBase64String(request.UnsignedTransaction); // use base64 string in N3
                neoTx = txRaw.AsSerializable <NeoTransaction>();
            }
            catch (Exception)
            {
                return(Error.TX_DESERIALIZE_ERROR.ToJson());
            }

            if (neoTx.Witnesses == null || neoTx.Witnesses.Length != neoTx.Signers.Length)
            {
                return(Error.TX_WITNESSES_INVALID.ToJson());
            }


            if (request.Signatures.Length == 0)
            {
                return(Error.NO_SIGNATURE.ToJson());
            }

            var signData = neoTx.GetSignData(system.Settings.Network);

            for (int i = 0; i < neoTx.Signers.Length; i++)
            {
                var witness = neoTx.Witnesses[i];
                if (witness.VerificationScript.IsSignatureContract())
                {
                    var sign = request.Signatures.First(s =>
                                                        s.PublicKey.AddressHash == neoTx.Signers[i].Account);
                    CreateSignatureWitness(witness, sign, signData);
                }
                else if (witness.VerificationScript.IsMultiSigContract(out var m, out ECPoint[] points))
                {
                    var pubKeys = points.OrderBy(p => p).Select(p => p.ToUInt160FromPublicKey()).ToList();
                    var signs   = new List <byte[]>();
                    var count   = 0;
                    foreach (var pubkeyhash in pubKeys)
                    {
                        if (count == m)
                        {
                            break;
                        }
                        var sign = request.Signatures.First(s => s.PublicKey.AddressHash == pubkeyhash);
                        signs.Add(sign.HexBytes.HexToBytes());
                        count++;
                    }
                    var mulWitness = new Witness();
                    using (ScriptBuilder sb = new ScriptBuilder())
                    {
                        signs.ForEach(p => sb.EmitPush(p));
                        witness.InvocationScript = sb.ToArray();
                    }
                }
            }

            byte[] signed = neoTx.ToArray();
            ConstructionCombineResponse response = new ConstructionCombineResponse(Convert.ToBase64String(signed));

            return(response.ToJson());
        }