private void CheckSignatures()
 {
     if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p)))
     {
         Contract         contract = Contract.CreateMultiSigContract(context.Miners[context.MinerIndex].EncodePoint(true).ToScriptHash(), context.M, context.Miners);
         Block            block    = context.MakeHeader();
         SignatureContext sc       = new SignatureContext(block);
         for (int i = 0, j = 0; i < context.Miners.Length && j < context.M; i++)
         {
             if (context.Signatures[i] != null)
             {
                 sc.AddSignature(contract, context.Miners[i], context.Signatures[i]);
                 j++;
             }
         }
         sc.Signable.Scripts = sc.GetScripts();
         block.Transactions  = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray();
         Log($"relay block: {block.Hash}");
         if (!localNode.Relay(block))
         {
             Log($"reject block: {block.Hash}");
         }
         context.State |= ConsensusState.BlockSent;
     }
 }
Exemple #2
0
        private void CheckSignatures()
        {
            ReportNeoBlockchain reportObj = new ReportNeoBlockchain("[NeoConsensusService-CheckSignatures]");

            if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p)))
            {
                Contract contract            = Contract.CreateMultiSigContract(context.M, context.Validators);
                Block    block               = context.MakeHeader();
                ContractParametersContext sc = new ContractParametersContext(block);
                for (int i = 0, j = 0; i < context.Validators.Length && j < context.M; i++)
                {
                    if (context.Signatures[i] != null)
                    {
                        sc.AddSignature(contract, context.Validators[i], context.Signatures[i]);
                        j++;
                    }
                }
                sc.Verifiable.Scripts = sc.GetScripts();
                block.Transactions    = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray();
                Log($"relay block: {block.Hash}");
                if (!localNode.Relay(block))
                {
                    Log($"reject block: {block.Hash}");
                }
                context.State |= ConsensusState.BlockSent;
            }

            reportObj.appendElapsedTime();
        }
Exemple #3
0
        private static bool SignAndShowInformation(Wallet wallet, LocalNode node, Transaction tx)
        {
            if (tx == null)
            {
                MessageBox.Show("Insufficient funds", "Error!");
                return(false);
            }
            ContractParametersContext context;

            try
            {
                context = new ContractParametersContext(tx);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("Unsynchronized block", "Error!");
                return(false);
            }
            wallet.Sign(context);
            if (!context.Completed)
            {
                MessageBox.Show("Incompleted signature", "Error!");
                return(false);
            }
            context.Verifiable.Scripts = context.GetScripts();
            wallet.ApplyTransaction(tx);
            node.Relay(tx);
            MessageBox.Show("Transaction send succeed with id: " + tx.Hash.ToString() + ", wait a few seconds for confirmation");
            return(true);
        }
Exemple #4
0
 private void CheckSignatures()
 {
     if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p)))
     {
         Program.Log($"{nameof(CheckSignatures)} {context.Signatures.Count(p => p != null)}/{context.M}");
         Contract         contract = Contract.CreateMultiSigContract(context.Miners[context.MinerIndex].EncodePoint(true).ToScriptHash(), context.M, context.Miners);
         Block            block    = context.MakeHeader();
         SignatureContext sc       = new SignatureContext(block);
         for (int i = 0; i < context.Miners.Length; i++)
         {
             if (context.Signatures[i] != null)
             {
                 sc.Add(contract, context.Miners[i], context.Signatures[i]);
             }
         }
         sc.Signable.Scripts = sc.GetScripts();
         block.Transactions  = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray();
         Program.Log($"RelayBlock hash:{block.Hash}");
         if (!LocalNode.Relay(block))
         {
             Program.Log($"failed hash:{block.Hash}");
         }
         context.State |= ConsensusState.BlockSent;
     }
 }
Exemple #5
0
 /// <summary>
 /// 验证共识协商结果
 /// </summary>
 private void CheckSignatures()
 {
     // 验证当前已进行的协商的共识节点数是否合法
     if (context.Signatures.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p)))
     {
         // 建立合约
         Contract contract = Contract.CreateMultiSigContract(context.M, context.Validators);
         // 创建新的区块
         Block block = context.MakeHeader();
         // 设置区块参数
         ContractParametersContext sc = new ContractParametersContext(block);
         for (int i = 0, j = 0; i < context.Validators.Length && j < context.M; i++)
         {
             if (context.Signatures[i] != null)
             {
                 sc.AddSignature(contract, context.Validators[i], context.Signatures[i]);
                 j++;
             }
         }
         // 获取用于验证区块的脚本
         sc.Verifiable.Scripts = sc.GetScripts();
         block.Transactions    = context.TransactionHashes.Select(p => context.Transactions[p]).ToArray();
         Log($"relay block: {block.Hash}");
         // 广播新区块
         if (!localNode.Relay(block))
         {
             Log($"reject block: {block.Hash}");
         }
         // 设置当前共识状态为新区块广播
         context.State |= ConsensusState.BlockSent;
     }
 }
Exemple #6
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            SignatureContext sc = new SignatureContext(payload);

            wallet.Sign(sc);
            sc.Signable.Scripts = sc.GetScripts();
            LocalNode.Relay(payload);
        }
        public void PerformFundTransfer(Fixed8 amountToTransfer, UInt160 destinationScriptHash, IInventory assetId, UInt160 fromAddress)
        {
            //  public UInt160 ChangeAddress => Wallet.ToScriptHash((string)comboBox1.SelectedItem);

            var tx        = new ContractTransaction();
            var neoOutput = new TransactionOutput();

            neoOutput.AssetId    = assetId.Hash;
            neoOutput.Value      = amountToTransfer;
            neoOutput.ScriptHash = destinationScriptHash;
            tx.Outputs           = new[] { neoOutput };

            var walletTx = NeoWallet.MakeTransaction(tx, fromAddress);

            if (walletTx == null)
            {
                throw new ApplicationException("Wallet TX was null. Possibly insufficient funds");
            }

            ContractParametersContext context;

            try
            {
                context = new ContractParametersContext(walletTx);
            }
            catch (InvalidOperationException)
            {
                throw new ApplicationException("unsynchronized block");
            }

            var sign = NeoWallet.Sign(context);

            if (context.Completed)
            {
                context.Verifiable.Scripts = context.GetScripts();
                NeoWallet.ApplyTransaction(walletTx); //changes with different versions of NEO
                var relay = _node.Relay(walletTx);

                //TODO: make this use our transaction watcher
                var originalHeight = Blockchain.Default.Height; //store the height we sent at then wait for the next block
                //possibly check if sign/relay/save has actually worked?

                while (Blockchain.Default.Height <= originalHeight + 1)
                {
                    Thread.Sleep(1000);                                                     //wait for next block
                }
            }
            else
            {
                throw new ApplicationException("Incompleted Signature");
            }
        }
Exemple #8
0
        private JObject InternalCall(string method, JArray _params)
        {
            switch (method)
            {
            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

            case "getblock":
            {
                UInt256 hash  = UInt256.Parse(_params[0].AsString());
                Block   block = Blockchain.Default.GetBlock(hash);
                if (block == null)
                {
                    throw new RpcException(-100, "Unknown block");
                }
                return(block.ToJson());
            }

            case "getblockcount":
                return(Blockchain.Default.Height + 1);

            case "getblockhash":
            {
                uint height = (uint)_params[0].AsNumber();
                return(Blockchain.Default.GetBlockHash(height).ToString());
            }

            case "getrawtransaction":
            {
                UInt256     hash = UInt256.Parse(_params[0].AsString());
                Transaction tx   = Blockchain.Default.GetTransaction(hash);
                if (tx == null)
                {
                    throw new RpcException(-101, "Unknown transaction");
                }
                return(tx.ToJson());
            }

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                return(localNode.Relay(tx));
            }

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Exemple #9
0
        private void SignAndRelay(ConsensusPayload payload)
        {
            SignatureContext sc;

            try
            {
                sc = new SignatureContext(payload);
            }
            catch (InvalidOperationException)
            {
                return;
            }
            wallet.Sign(sc);
            sc.Signable.Scripts = sc.GetScripts();
            LocalNode.Relay(payload);
        }
Exemple #10
0
        private Transaction SignTransaction(Transaction tx)
        {
            TR.Enter();
            if (tx == null)
            {
                Console.WriteLine($"no transaction specified");
                return(TR.Exit((Transaction)null));
            }
            ContractParametersContext context;

            try
            {
                context = new ContractParametersContext(tx);
            }
            catch (InvalidOperationException)
            {
                Console.WriteLine($"unsynchronized block");

                return(TR.Exit((Transaction)null));
            }

            current_wallet.Sign(context);

            if (context.Completed)
            {
                context.Verifiable.Scripts = context.GetScripts();
                current_wallet.ApplyTransaction(tx);

                bool relay_result = local_node.Relay(tx);

                if (relay_result)
                {
                    return(TR.Exit(tx));
                }
                else
                {
                    Console.WriteLine($"Local Node could not relay transaction: {tx.Hash.ToString()}");
                }
            }
            else
            {
                Console.WriteLine($"Incomplete Signature: {context.ToString()}");
            }

            return(TR.Exit((Transaction)null));
        }
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getapplicationlog":
            case "getbalance":
            case "listaddress":
            case "sendfrom":
            case "sendtoaddress":
            case "sendmany":
            case "getnewaddress":
            case "dumpprivkey":
                throw new RpcException(-400, "Access denied.");

            case "invoke":
            case "invokefunction":
            case "invokescript":
                JObject result = base.Process(method, _params);
                return(result);

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                if (LocalNode.Relay(tx))
                {
                    JObject json = new JObject();
                    json["txid"] = tx.Hash.ToString();
                    return(json);
                }
                else
                {
                    throw new RpcException(-400, "Invalid Transaction");
                }
            }

            default:
                throw new RpcException(-400, "Access denied.");
            }
        }
Exemple #12
0
        private JObject InternalCall(string method, JArray _params)
        {
            switch (method)
            {
            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

            case "getblock":
            {
                Block block;
                if (_params[0] is JNumber)
                {
                    uint index = (uint)_params[0].AsNumber();
                    block = Blockchain.Default.GetBlock(index);
                }
                else
                {
                    UInt256 hash = UInt256.Parse(_params[0].AsString());
                    block = Blockchain.Default.GetBlock(hash);
                }
                if (block == null)
                {
                    throw new RpcException(-100, "Unknown block");
                }
                bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                if (verbose)
                {
                    return(block.ToJson());
                }
                else
                {
                    return(block.ToArray().ToHexString());
                }
            }

            case "getblockcount":
                return(Blockchain.Default.Height + 1);

            case "getblockhash":
            {
                uint height = (uint)_params[0].AsNumber();
                return(Blockchain.Default.GetBlockHash(height).ToString());
            }

            case "getconnectioncount":
                return(localNode.RemoteNodeCount);

            case "getrawmempool":
                return(new JArray(LocalNode.GetMemoryPool().Select(p => (JObject)p.Hash.ToString())));

            case "getrawtransaction":
            {
                UInt256     hash    = UInt256.Parse(_params[0].AsString());
                bool        verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                Transaction tx      = Blockchain.Default.GetTransaction(hash);
                if (tx == null)
                {
                    throw new RpcException(-101, "Unknown transaction");
                }
                if (verbose)
                {
                    return(tx.ToJson());
                }
                else
                {
                    return(tx.ToArray().ToHexString());
                }
            }

            case "gettxout":
            {
                UInt256 hash  = UInt256.Parse(_params[0].AsString());
                ushort  index = (ushort)_params[1].AsNumber();
                return(Blockchain.Default.GetUnspent(hash, index)?.ToJson(index));
            }

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                return(localNode.Relay(tx));
            }

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Exemple #13
0
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "":
            case "getapplicationlog":
            {
                UInt256 hash = UInt256.Parse(_params[0].AsString());
                string  path = Path.Combine(Settings.Default.Paths.ApplicationLogs, $"{hash}.json");
                return(File.Exists(path)
                            ? JObject.Parse(File.ReadAllText(path))
                            : throw new RpcException(-100, "Unknown transaction"));
            }

            case "balance":     // 使用address查询余额 AddCode
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    JObject json = new JObject();
                    if (_params.Count() == 1)
                    {
                        // 查询NEO和GAS资产
                        string address = _params[0].AsString();
                        try
                        {
                            Wallet.ToScriptHash(address);
                        } catch
                        {
                            json["code"]    = -1;
                            json["message"] = "NEO地址错误";
                            return(json);
                        }
                        IEnumerable <Coin> coins = Program.Wallet.GetCoins(address);
                        // NEO
                        var neoCoins = coins.Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(UInt256.Parse(Settings.Default.Asset.NEOAsset)));
                        json["balance"]   = neoCoins.Sum(p => p.Output.Value).ToString();
                        json["confirmed"] = neoCoins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                        // GAS
                        var gasCoins = coins.Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(UInt256.Parse(Settings.Default.Asset.GASAsset)));
                        json["gasbalance"]   = gasCoins.Sum(p => p.Output.Value).ToString();
                        json["gasconfirmed"] = gasCoins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                        return(json);
                    }
                    else     // 查询指定资产余额
                    {
                        string address = _params[1].AsString();

                        switch (UIntBase.Parse(_params[0].AsString()))
                        {
                        case UInt160 asset_id_160:         //NEP-5 balance
                            json["balance"] = Program.Wallet.GetAvailable(asset_id_160, address).ToString();
                            break;

                        case UInt256 asset_id_256:         //Global Assets balance
                            IEnumerable <Coin> coins = Program.Wallet.GetCoins(address).Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256));
                            json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                            json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                            break;
                        }
                        return(json);
                    }
                }

            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    JObject json = new JObject();
                    switch (UIntBase.Parse(_params[0].AsString()))
                    {
                    case UInt160 asset_id_160:         //NEP-5 balance
                        json["balance"] = Program.Wallet.GetAvailable(asset_id_160).ToString();
                        break;

                    case UInt256 asset_id_256:         //Global Assets balance
                        IEnumerable <Coin> coins = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256));
                        json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                        json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                        break;
                    }
                    return(json);
                }

            case "listaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    return(Program.Wallet.GetAccounts().Select(p =>
                    {
                        JObject account = new JObject();
                        account["address"] = p.Address;
                        account["haskey"] = p.HasKey;
                        account["label"] = p.Label;
                        account["watchonly"] = p.WatchOnly;
                        return account;
                    }).ToArray());
                }

            case "sendfrom":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         from       = Wallet.ToScriptHash(_params[1].AsString());
                    UInt160         to         = Wallet.ToScriptHash(_params[2].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 6 ? Wallet.ToScriptHash(_params[5].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = to
                        }
                    }, from: from, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendfromto":     // 从指定账号向指定账号转账 AddCode
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    // 参数顺序  资产类型  输出账号  输入账号  输出金额  输出账号私钥  手续费    找零地址
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         from       = Wallet.ToScriptHash(_params[1].AsString());
                    UInt160         to         = Wallet.ToScriptHash(_params[2].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals);
                    string          privatekey = _params[4].AsString();
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 6 ? Fixed8.Parse(_params[5].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 7 && !string.IsNullOrEmpty(_params[6].AsString()) ? Wallet.ToScriptHash(_params[6].AsString()) : from;// 找零地址
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = to
                        }
                    }, from: from, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    //File.AppendAllText("wallet.log", context.ScriptHashes.Count().ToString());
                    //Program.Wallet.Sign(context);
                    Program.Wallet.Sign(context, privatekey);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 5 ? Wallet.ToScriptHash(_params[4].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = scriptHash
                        }
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendmany":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    JArray to = (JArray)_params[0];
                    if (to.Count == 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    TransferOutput[] outputs = new TransferOutput[to.Count];
                    for (int i = 0; i < to.Count; i++)
                    {
                        UIntBase        asset_id   = UIntBase.Parse(to[i]["asset"].AsString());
                        AssetDescriptor descriptor = new AssetDescriptor(asset_id);
                        outputs[i] = new TransferOutput
                        {
                            AssetId    = asset_id,
                            Value      = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals),
                            ScriptHash = Wallet.ToScriptHash(to[i]["address"].AsString())
                        };
                        if (outputs[i].Value.Sign <= 0)
                        {
                            throw new RpcException(-32602, "Invalid params");
                        }
                    }
                    Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 3 ? Wallet.ToScriptHash(_params[2].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "getnewaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    WalletAccount account = Program.Wallet.CreateAccount();
                    if (Program.Wallet is NEP6Wallet wallet)
                    {
                        wallet.Save();
                    }
                    return(account.Address);
                }

            case "newaddress":    // 创建一个账号 AddCode
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    WalletAccount account = Program.Wallet.CreateAccount();
                    if (Program.Wallet is NEP6Wallet wallet)
                    {
                        wallet.Save();
                    }
                    return(account.OutputJson());
                }

            case "dumpprivkey":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt160       scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                    WalletAccount account    = Program.Wallet.GetAccount(scriptHash);
                    return(account.GetKey().Export());
                }

            case "invoke":    // 使用给定的参数以散列值调用智能合约
            case "invokefunction":
            case "invokescript":
                JObject result = base.Process(method, _params);
                if (Program.Wallet != null)
                {
                    InvocationTransaction tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = result["script"].AsString().HexToBytes(),
                        Gas     = Fixed8.Parse(result["gas_consumed"].AsString())
                    };
                    tx.Gas -= Fixed8.FromDecimal(10);
                    if (tx.Gas < Fixed8.Zero)
                    {
                        tx.Gas = Fixed8.Zero;
                    }
                    tx.Gas = tx.Gas.Ceiling();
                    tx     = Program.Wallet.MakeTransaction(tx);
                    if (tx != null)
                    {
                        ContractParametersContext context = new ContractParametersContext(tx);
                        Program.Wallet.Sign(context);
                        if (context.Completed)
                        {
                            tx.Scripts = context.GetScripts();
                        }
                        else
                        {
                            tx = null;
                        }
                    }
                    result["tx"] = tx?.ToArray().ToHexString();
                }
                return(result);

            default:
                return(base.Process(method, _params));
            }
        }
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    UInt256            assetId = UInt256.Parse(_params[0].AsString());
                    IEnumerable <Coin> coins   = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(assetId));
                    JObject            json    = new JObject();
                    json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                    json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                    return(json);
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt256 assetId    = UInt256.Parse(_params[0].AsString());
                    UInt160 scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    Fixed8  value      = Fixed8.Parse(_params[2].AsString());
                    if (value <= Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (value < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160             change_address = _params.Count >= 5 ? Wallet.ToScriptHash(_params[4].AsString()) : null;
                    ContractTransaction tx             = Program.Wallet.MakeTransaction(new ContractTransaction
                    {
                        Outputs = new[]
                        {
                            new TransactionOutput
                            {
                                AssetId    = assetId,
                                Value      = value,
                                ScriptHash = scriptHash
                            }
                        }
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    SignatureContext context = new SignatureContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.SaveTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendmany":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    JArray to = (JArray)_params[0];
                    if (to.Count == 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    TransactionOutput[] outputs = new TransactionOutput[to.Count];
                    for (int i = 0; i < to.Count; i++)
                    {
                        outputs[i] = new TransactionOutput
                        {
                            AssetId    = UInt256.Parse(to[i]["asset"].AsString()),
                            Value      = Fixed8.Parse(to[i]["value"].AsString()),
                            ScriptHash = Wallet.ToScriptHash(to[i]["address"].AsString())
                        };
                        if (outputs[i].Value <= Fixed8.Zero)
                        {
                            throw new RpcException(-32602, "Invalid params");
                        }
                    }
                    Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160             change_address = _params.Count >= 3 ? Wallet.ToScriptHash(_params[2].AsString()) : null;
                    ContractTransaction tx             = Program.Wallet.MakeTransaction(new ContractTransaction
                    {
                        Outputs = outputs
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    SignatureContext context = new SignatureContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.SaveTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "getnewaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    KeyPair  key      = Program.Wallet.CreateKey();
                    Contract contract = Program.Wallet.GetContracts(key.PublicKeyHash).First(p => p.IsStandard);
                    return(contract.Address);
                }

            case "dumpprivkey":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt160 scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                    KeyPair key        = Program.Wallet.GetKeyByScriptHash(scriptHash);
                    return(key.Export());
                }

            default:
                return(base.Process(method, _params));
            }
        }
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    UInt256            assetId = UInt256.Parse(_params[0].AsString());
                    IEnumerable <Coin> coins   = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(assetId));
                    JObject            json    = new JObject();
                    json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                    json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                    return(json);
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt256 assetId    = UInt256.Parse(_params[0].AsString());
                    UInt160 scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    Fixed8  value      = Fixed8.Parse(_params[2].AsString());
                    Fixed8  fee        = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (value <= Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    ContractTransaction tx = Program.Wallet.MakeTransaction(new ContractTransaction
                    {
                        Outputs = new[]
                        {
                            new TransactionOutput
                            {
                                AssetId    = assetId,
                                Value      = value,
                                ScriptHash = scriptHash
                            }
                        }
                    }, fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    SignatureContext context = new SignatureContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.SaveTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            default:
                return(base.Process(method, _params));
            }
        }
Exemple #16
0
        public bool InvokeTransactionOnBlockchain(InvocationTransaction tx, UInt160 contractHash, InvokeOptions options)
        {
            Blockchain.PersistCompleted += Blockchain_PersistCompleted;
            if (options.AttachedNeo > Fixed8.Zero)
            {
                var neoOutput = new TransactionOutput();
                neoOutput.AssetId    = Blockchain.GoverningToken.Hash;
                neoOutput.Value      = options.AttachedNeo;
                neoOutput.ScriptHash = contractHash;
                var transactionOutputs = tx.Outputs.ToList();
                transactionOutputs.Add(neoOutput);
                tx.Outputs = transactionOutputs.ToArray();
            }

            if (options.AttachedGas > Fixed8.Zero)
            {
                var neoOutput = new TransactionOutput();
                neoOutput.AssetId    = Blockchain.UtilityToken.Hash;
                neoOutput.Value      = options.AttachedGas;
                neoOutput.ScriptHash = contractHash;
                var transactionOutputs = tx.Outputs.ToList();
                transactionOutputs.Add(neoOutput);
                tx.Outputs = transactionOutputs.ToArray();
            }

//            if (Client.CurrentWallet.WalletHeight > Blockchain.Default.HeaderHeight)
//            {
//                throw new ApplicationException("Wallet height is ahead of the blockchain height! It may need a rebuild");
//            }

            var walletSyncAttempts = 0;

            while (Client.CurrentWallet.NeoWallet.WalletHeight < Blockchain.Default.HeaderHeight)
            {
                walletSyncAttempts++;
                Thread.Sleep(1000); //get the wallet in sync or else MakeTransaction will fail
                if (walletSyncAttempts >= 30)
                {
                    throw new WalletException("could not get the wallet in sync after 30 attempts");
                }
            }


            var walletTx = Client.CurrentWallet.NeoWallet.MakeTransaction(new InvocationTransaction
            {
                Version    = tx.Version,
                Script     = tx.Script,
                Gas        = tx.Gas,
                Attributes = tx.Attributes,
                Inputs     = tx.Inputs,
                Outputs    = tx.Outputs
            }, fee: options.Fee); //include a small fee

            if (walletTx == null)
            {
                throw new NeoTransactionBuildException("Wallet TX was null. Possibly insufficient funds. If not wallet may need a rebuild");
            }

            var context = new ContractParametersContext(walletTx);
            var sign    = Client.CurrentWallet.NeoWallet.Sign(context); //fail here with index out of bounds

            if (context.Completed)
            {
                context.Verifiable.Scripts = context.GetScripts();
                Client.CurrentWallet.NeoWallet.ApplyTransaction(walletTx); //changes with different versions of NEO
                //Wallet.ApplyTransaction(walletTx);

                var relay = _node.Relay(walletTx);

                //var originalHeight = Blockchain.Default.Height; //store the height we sent at then wait for the next block
                //possibly check if sign/relay/save has actually worked?

                //while (Blockchain.Default.Height <= originalHeight + 2) Thread.Sleep(1000); //wait for next block
                //while (this._wallet.WalletHeight <= originalHeight + 2) Thread.Sleep(1000); //wait for wallet to sync too!

                TxFound    = false;
                WatchForTx = walletTx.Hash;

                Console.WriteLine(walletTx.Hash);
                //Console.WriteLine(tx.Hash);

                var count = 0;
                while (TxFound == false) //wait until the transaction is confirmed
                {
                    Thread.Sleep(1000);
                    count++;
                    if (count > 30)
                    {
                        Blockchain.PersistCompleted -= Blockchain_PersistCompleted;
                        return(false);
                    }
                }

//                while(Client.CurrentWallet.WalletHeight < TxFoundInBlock && WalletIndexer.IndexHeight < TxFoundInBlock) //make sure the wallet gets this block
//                {
//                    Thread.Sleep(1000);
//                }

                //ensure we have an unspent coin back to use?
                //seems like the WalletIndexer is running on a background thread so the block may not be fully processed
                //e.g. the unconfirmed array in the wallet may not be updated in real time. The only event we have is that BlockChain.PersistCompleted was done which means we have the block stored to disk locally, this does not mean
                //that the wallet has completed updating based on the new block!
                while (Client.CurrentWallet.NeoWallet.FindUnspentCoins(Blockchain.UtilityToken.Hash, walletTx.NetworkFee, new UInt160[] { Client.CurrentWallet.GetAddresses().First() }) == null)
                {
                    Thread.Sleep(500);
                }
            }
            else
            {
                Blockchain.PersistCompleted -= Blockchain_PersistCompleted;
                throw new ApplicationException("Incompleted Signature");
            }

            Blockchain.PersistCompleted -= Blockchain_PersistCompleted;
            return(true);
        }
Exemple #17
0
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getapplicationlog":
            {
                UInt256 hash = UInt256.Parse(_params[0].AsString());
                string  path = Path.Combine(Settings.Default.Paths.ApplicationLogs, $"{hash}.json");
                return(File.Exists(path)
                            ? JObject.Parse(File.ReadAllText(path))
                            : throw new RpcException(-100, "Unknown transaction"));
            }

            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    JObject json = new JObject();
                    switch (UIntBase.Parse(_params[0].AsString()))
                    {
                    case UInt160 asset_id_160:         //NEP-5 balance
                        json["balance"] = Program.Wallet.GetAvailable(asset_id_160).ToString();
                        break;

                    case UInt256 asset_id_256:         //Global Assets balance
                        IEnumerable <Coin> coins = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256));
                        json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                        json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                        break;
                    }
                    return(json);
                }

            case "listaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    return(Program.Wallet.GetAccounts().Select(p =>
                    {
                        JObject account = new JObject();
                        account["address"] = p.Address;
                        account["haskey"] = p.HasKey;
                        account["label"] = p.Label;
                        account["watchonly"] = p.WatchOnly;
                        return account;
                    }).ToArray());
                }

            case "sendfrom":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         from       = Wallet.ToScriptHash(_params[1].AsString());
                    UInt160         to         = Wallet.ToScriptHash(_params[2].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 6 ? Wallet.ToScriptHash(_params[5].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = to
                        }
                    }, from: from, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 5 ? Wallet.ToScriptHash(_params[4].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = scriptHash
                        }
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendmany":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    JArray to = (JArray)_params[0];
                    if (to.Count == 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    TransferOutput[] outputs = new TransferOutput[to.Count];
                    for (int i = 0; i < to.Count; i++)
                    {
                        UIntBase        asset_id   = UIntBase.Parse(to[i]["asset"].AsString());
                        AssetDescriptor descriptor = new AssetDescriptor(asset_id);
                        outputs[i] = new TransferOutput
                        {
                            AssetId    = asset_id,
                            Value      = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals),
                            ScriptHash = Wallet.ToScriptHash(to[i]["address"].AsString())
                        };
                        if (outputs[i].Value.Sign <= 0)
                        {
                            throw new RpcException(-32602, "Invalid params");
                        }
                    }
                    Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 3 ? Wallet.ToScriptHash(_params[2].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "getnewaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    WalletAccount account = Program.Wallet.CreateAccount();
                    if (Program.Wallet is NEP6Wallet wallet)
                    {
                        wallet.Save();
                    }
                    return(account.Address);
                }

            case "dumpprivkey":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt160       scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                    WalletAccount account    = Program.Wallet.GetAccount(scriptHash);
                    return(account.GetKey().Export());
                }

            case "invoke":
            case "invokefunction":
            case "invokescript":
                JObject result = base.Process(method, _params);
                if (Program.Wallet != null)
                {
                    InvocationTransaction tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = result["script"].AsString().HexToBytes(),
                        Gas     = Fixed8.Parse(result["gas_consumed"].AsString())
                    };
                    tx.Gas -= Fixed8.FromDecimal(10);
                    if (tx.Gas < Fixed8.Zero)
                    {
                        tx.Gas = Fixed8.Zero;
                    }
                    tx.Gas = tx.Gas.Ceiling();
                    tx     = Program.Wallet.MakeTransaction(tx);
                    if (tx != null)
                    {
                        ContractParametersContext context = new ContractParametersContext(tx);
                        Program.Wallet.Sign(context);
                        if (context.Completed)
                        {
                            tx.Scripts = context.GetScripts();
                        }
                        else
                        {
                            tx = null;
                        }
                    }
                    result["tx"] = tx?.ToArray().ToHexString();
                }
                return(result);

            case "getunclaimedgas":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    JObject json   = new JObject();
                    uint    height = Blockchain.Default.Height + 1;
                    Fixed8  unavailable;
                    try
                    {
                        unavailable = Blockchain.CalculateBonus(Program.Wallet.FindUnspentCoins().Where(p => p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).Select(p => p.Reference), height);
                    }
                    catch (Exception)
                    {
                        unavailable = Fixed8.Zero;
                    }
                    json["unavailable"] = unavailable.ToString();
                    Fixed8 available = Blockchain.CalculateBonus(Program.Wallet.GetUnclaimedCoins().Select(p => p.Reference));
                    json["available"] = available.ToString();
                    return(json);
                }

            case "claimgas":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    Fixed8 availableBonus = Blockchain.CalculateBonus(Program.Wallet.GetUnclaimedCoins().Select(p => p.Reference));
                    if (availableBonus == Fixed8.Zero)
                    {
                        // no gas to claim
                        return(null);
                    }

                    CoinReference[] claims = Program.Wallet.GetUnclaimedCoins().Select(p => p.Reference).ToArray();
                    if (claims.Length == 0)
                    {
                        return(null);
                    }

                    ClaimTransaction tx = new ClaimTransaction
                    {
                        Claims     = claims,
                        Attributes = new TransactionAttribute[0],
                        Inputs     = new CoinReference[0],
                        Outputs    = new[]
                        {
                            new TransactionOutput
                            {
                                AssetId    = Blockchain.UtilityToken.Hash,
                                Value      = Blockchain.CalculateBonus(claims),
                                ScriptHash = Program.Wallet.GetChangeAddress()
                            }
                        }
                    };

                    ContractParametersContext context;
                    try
                    {
                        context = new ContractParametersContext(tx);
                    }
                    catch (InvalidOperationException)
                    {
                        // unsynchronized block
                        return(null);
                    }
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        context.Verifiable.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        bool relay_result = LocalNode.Relay(tx);

                        if (relay_result)
                        {
                            return(tx.ToJson());
                        }
                        else
                        {
                            throw new RpcException(-401, "Could not relay transaction");
                        }
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            default:
                return(base.Process(method, _params));
            }
        }
Exemple #18
0
        private JObject InternalCall(string method, JArray _params)
        {
            switch (method)
            {
            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    UInt256            assetId = UInt256.Parse(_params[0].AsString());
                    IEnumerable <Coin> coins   = Program.Wallet.FindCoins().Where(p => p.AssetId.Equals(assetId));
                    JObject            json    = new JObject();
                    json["balance"]   = coins.Where(p => p.State == CoinState.Unspent || p.State == CoinState.Unconfirmed).Sum(p => p.Value).ToString();
                    json["confirmed"] = coins.Where(p => p.State == CoinState.Unspent).Sum(p => p.Value).ToString();
                    return(json);
                }

            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

            case "getblock":
            {
                Block block;
                if (_params[0] is JNumber)
                {
                    uint index = (uint)_params[0].AsNumber();
                    block = Blockchain.Default.GetBlock(index);
                }
                else
                {
                    UInt256 hash = UInt256.Parse(_params[0].AsString());
                    block = Blockchain.Default.GetBlock(hash);
                }
                if (block == null)
                {
                    throw new RpcException(-100, "Unknown block");
                }
                bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                if (verbose)
                {
                    JObject json = block.ToJson();
                    json["confirmations"] = Blockchain.Default.Height - block.Height + 1;
                    UInt256 hash = Blockchain.Default.GetNextBlockHash(block.Hash);
                    if (hash != null)
                    {
                        json["nextblockhash"] = hash.ToString();
                    }
                    return(json);
                }
                else
                {
                    return(block.ToArray().ToHexString());
                }
            }

            case "getblockcount":
                return(Blockchain.Default.Height + 1);

            case "getblockhash":
            {
                uint height = (uint)_params[0].AsNumber();
                return(Blockchain.Default.GetBlockHash(height).ToString());
            }

            case "getconnectioncount":
                return(localNode.RemoteNodeCount);

            case "getrawmempool":
                return(new JArray(LocalNode.GetMemoryPool().Select(p => (JObject)p.Hash.ToString())));

            case "getrawtransaction":
            {
                UInt256     hash    = UInt256.Parse(_params[0].AsString());
                bool        verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                int         height  = -1;
                Transaction tx      = LocalNode.GetTransaction(hash);
                if (tx == null)
                {
                    tx = Blockchain.Default.GetTransaction(hash, out height);
                }
                if (tx == null)
                {
                    throw new RpcException(-101, "Unknown transaction");
                }
                if (verbose)
                {
                    JObject json = tx.ToJson();
                    if (height >= 0)
                    {
                        Header header = Blockchain.Default.GetHeader((uint)height);
                        json["blockhash"]     = header.Hash.ToString();
                        json["confirmations"] = Blockchain.Default.Height - header.Height + 1;
                        json["blocktime"]     = header.Timestamp;
                    }
                    return(json);
                }
                else
                {
                    return(tx.ToArray().ToHexString());
                }
            }

            case "gettxout":
            {
                UInt256 hash  = UInt256.Parse(_params[0].AsString());
                ushort  index = (ushort)_params[1].AsNumber();
                return(Blockchain.Default.GetUnspent(hash, index)?.ToJson(index));
            }

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                return(localNode.Relay(tx));
            }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt256 assetId    = UInt256.Parse(_params[0].AsString());
                    UInt160 scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    Fixed8  value      = Fixed8.Parse(_params[2].AsString());
                    Fixed8  fee        = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (value <= Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    ContractTransaction tx = Program.Wallet.MakeTransaction(new ContractTransaction
                    {
                        Outputs = new[]
                        {
                            new TransactionOutput
                            {
                                AssetId    = assetId,
                                Value      = value,
                                ScriptHash = scriptHash
                            }
                        }
                    }, fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    SignatureContext context = new SignatureContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.SaveTransaction(tx);
                        localNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "submitblock":
            {
                Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>();
                return(localNode.Relay(block));
            }

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getapplicationlog":
            {
                UInt256 hash = UInt256.Parse(_params[0].AsString());
                string  path = Path.Combine(Settings.Default.Paths.ApplicationLogs, $"{hash}.json");
                return(File.Exists(path)
                            ? JObject.Parse(File.ReadAllText(path))
                            : throw new RpcException(-100, "Unknown transaction"));
            }

            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    UInt256            assetId = UInt256.Parse(_params[0].AsString());
                    IEnumerable <Coin> coins   = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(assetId));
                    JObject            json    = new JObject();
                    json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                    json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                    return(json);
                }

            case "listaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    return(Program.Wallet.GetAccounts().Select(p =>
                    {
                        JObject account = new JObject();
                        account["address"] = p.Address;
                        account["haskey"] = p.HasKey;
                        account["label"] = p.Label;
                        account["watchonly"] = p.WatchOnly;
                        return account;
                    }).ToArray());
                }

            case "sendfrom":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         from       = Wallet.ToScriptHash(_params[1].AsString());
                    UInt160         to         = Wallet.ToScriptHash(_params[2].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 6 ? Wallet.ToScriptHash(_params[5].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = to
                        }
                    }, from: from, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 5 ? Wallet.ToScriptHash(_params[4].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = scriptHash
                        }
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendmany":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    JArray to = (JArray)_params[0];
                    if (to.Count == 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    TransferOutput[] outputs = new TransferOutput[to.Count];
                    for (int i = 0; i < to.Count; i++)
                    {
                        UIntBase        asset_id   = UIntBase.Parse(to[i]["asset"].AsString());
                        AssetDescriptor descriptor = new AssetDescriptor(asset_id);
                        outputs[i] = new TransferOutput
                        {
                            AssetId    = asset_id,
                            Value      = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals),
                            ScriptHash = Wallet.ToScriptHash(to[i]["address"].AsString())
                        };
                        if (outputs[i].Value.Sign <= 0)
                        {
                            throw new RpcException(-32602, "Invalid params");
                        }
                    }
                    Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 3 ? Wallet.ToScriptHash(_params[2].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "getnewaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    WalletAccount account = Program.Wallet.CreateAccount();
                    if (Program.Wallet is NEP6Wallet wallet)
                    {
                        wallet.Save();
                    }
                    return(account.Address);
                }

            case "dumpprivkey":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt160       scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                    WalletAccount account    = Program.Wallet.GetAccount(scriptHash);
                    return(account.GetKey().Export());
                }

            case "invoke":
            case "invokefunction":
            case "invokescript":
                JObject result = base.Process(method, _params);
                if (Program.Wallet != null)
                {
                    InvocationTransaction tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = result["script"].AsString().HexToBytes(),
                        Gas     = Fixed8.Parse(result["gas_consumed"].AsString())
                    };
                    tx.Gas -= Fixed8.FromDecimal(10);
                    if (tx.Gas < Fixed8.Zero)
                    {
                        tx.Gas = Fixed8.Zero;
                    }
                    tx.Gas = tx.Gas.Ceiling();
                    tx     = Program.Wallet.MakeTransaction(tx);
                    if (tx != null)
                    {
                        ContractParametersContext context = new ContractParametersContext(tx);
                        Program.Wallet.Sign(context);
                        if (context.Completed)
                        {
                            tx.Scripts = context.GetScripts();
                        }
                        else
                        {
                            tx = null;
                        }
                    }
                    result["tx"] = tx?.ToArray().ToHexString();
                }
                return(result);

            default:
                return(base.Process(method, _params));
            }
        }
Exemple #20
0
        protected override JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            //{"name":null,"version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AHGVqc2L3vbxG8N6t76oxg8ihdyxcqePB1","label":null,"isDefault":false,"lock":false,"key":"6PYMhaNsXjhGALn3XfEqwFLr3VsbCmgfr1WHMjaNgS5C9677L4KNoih46G","contract":{"script":"210331cef9faf71d85c4dd19911dd7d53815dc69056322f1db62a66df264e5f8ba8cac","parameters":[{"name":"signature","type":"Signature"}],"deployed":false},"extra":null},{"address":"ARBFVamaqvmyVjyN6P8V3tGeoZZJBZ7drP","label":null,"isDefault":false,"lock":false,"key":"6PYSMmydUaZCiYa6B8AgGJYDsXXfTmr1PdG27uWPkjtsdv4n3K2tbQ8WM1","contract":{"script":"2102ca41146dba006ef61e328e0735bdb46e76ee12f8feb94eec0f5cfb1bcf57ee17ac","parameters":[{"name":"signature","type":"Signature"}],"deployed":false},"extra":null},{"address":"AJ3uJEYBudv5ZFo2Eg6MFP1ZzimefzD8vZ","label":null,"isDefault":false,"lock":false,"key":"6PYWzN8pz45xxQu4wkQtn8GwvbfUhDS9iRBDgdLt5Vwd1RgkU6SAtuApuR","contract":{"script":"2103f4ca1a9ab97e8cdcd6349b72ff0914f5b70774a2c6927d4c0db1b2d733c696bcac","parameters":[{"name":"signature","type":"Signature"}],"deployed":false},"extra":null}],"extra":null}
            //将整个钱包的json作为一个串放进param
            // "{'jsonrpc': '2.0', 'method': 'openwallet', 'params': ["walllet-base64-json","password"],  'id': 1}"


            case "openwallet":
            {
                string oStr = Base64Decode(_params[0].AsString());
                //System.Console.WriteLine(_params[0].AsString());
                //System.Console.WriteLine(oStr);
                //JObject walletJson = _params[0];
                string password = Base64Decode(_params[1].AsString());

                string path = Directory.GetCurrentDirectory() + "\\" + "tmp.json";

                FileStream F = new FileStream("tmp.json", FileMode.OpenOrCreate, FileAccess.ReadWrite);
                F.SetLength(0);
                StreamWriter sw = new StreamWriter(F);
                //sw.Write(walletJson.AsString());
                sw.Write(oStr);
                sw.Flush();
                sw.Close();

                JObject json = new JObject();

                NEP6Wallet nep6wallet = new NEP6Wallet(path);
                try
                {
                    nep6wallet.Unlock(password);
                }
                catch (CryptographicException)
                {
                    System.Console.WriteLine($"failed to open wallet \"{path}\"");
                    File.Delete(path);
                    throw new RpcException(-400, "Access denied");
                }

                Program.Wallet = nep6wallet;

                File.Delete(path);         //打开后删除钱包文件
                return("0");
            }

            case "closewallet":
            {
                //对当前打开的钱包做校验
                // if(Program.Wallet != null)
                // {
                //     Base64Encode
                // }



                Program.Wallet = null;
                return("0");
            }

            case "getapplicationlog":
            {
                UInt256 hash = UInt256.Parse(_params[0].AsString());
                string  path = Path.Combine(Settings.Default.Paths.ApplicationLogs, $"{hash}.json");
                return(File.Exists(path)
                            ? JObject.Parse(File.ReadAllText(path))
                            : throw new RpcException(-100, "Unknown transaction"));
            }

            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    JObject json = new JObject();
                    switch (UIntBase.Parse(_params[0].AsString()))
                    {
                    case UInt160 asset_id_160:         //NEP-5 balance
                        json["balance"] = Program.Wallet.GetAvailable(asset_id_160).ToString();
                        break;

                    case UInt256 asset_id_256:         //Global Assets balance
                        IEnumerable <Coin> coins = Program.Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256));
                        json["balance"]   = coins.Sum(p => p.Output.Value).ToString();
                        json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString();
                        break;
                    }
                    return(json);
                }

            case "listaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    return(Program.Wallet.GetAccounts().Select(p =>
                    {
                        JObject account = new JObject();
                        account["address"] = p.Address;
                        account["haskey"] = p.HasKey;
                        account["label"] = p.Label;
                        account["watchonly"] = p.WatchOnly;
                        return account;
                    }).ToArray());
                }

            case "sendfrom":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         from       = Wallet.ToScriptHash(_params[1].AsString());
                    UInt160         to         = Wallet.ToScriptHash(_params[2].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 6 ? Wallet.ToScriptHash(_params[5].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = to
                        }
                    }, from: from, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendtoaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UIntBase        assetId    = UIntBase.Parse(_params[0].AsString());
                    AssetDescriptor descriptor = new AssetDescriptor(assetId);
                    UInt160         scriptHash = Wallet.ToScriptHash(_params[1].AsString());
                    BigDecimal      value      = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals);
                    if (value.Sign <= 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 5 ? Wallet.ToScriptHash(_params[4].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, new[]
                    {
                        new TransferOutput
                        {
                            AssetId    = assetId,
                            Value      = value,
                            ScriptHash = scriptHash
                        }
                    }, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "sendmany":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    JArray to = (JArray)_params[0];
                    if (to.Count == 0)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    TransferOutput[] outputs = new TransferOutput[to.Count];
                    for (int i = 0; i < to.Count; i++)
                    {
                        UIntBase        asset_id   = UIntBase.Parse(to[i]["asset"].AsString());
                        AssetDescriptor descriptor = new AssetDescriptor(asset_id);
                        outputs[i] = new TransferOutput
                        {
                            AssetId    = asset_id,
                            Value      = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals),
                            ScriptHash = Wallet.ToScriptHash(to[i]["address"].AsString())
                        };
                        if (outputs[i].Value.Sign <= 0)
                        {
                            throw new RpcException(-32602, "Invalid params");
                        }
                    }
                    Fixed8 fee = _params.Count >= 2 ? Fixed8.Parse(_params[1].AsString()) : Fixed8.Zero;
                    if (fee < Fixed8.Zero)
                    {
                        throw new RpcException(-32602, "Invalid params");
                    }
                    UInt160     change_address = _params.Count >= 3 ? Wallet.ToScriptHash(_params[2].AsString()) : null;
                    Transaction tx             = Program.Wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee);
                    if (tx == null)
                    {
                        throw new RpcException(-300, "Insufficient funds");
                    }
                    ContractParametersContext context = new ContractParametersContext(tx);
                    Program.Wallet.Sign(context);
                    if (context.Completed)
                    {
                        tx.Scripts = context.GetScripts();
                        Program.Wallet.ApplyTransaction(tx);
                        LocalNode.Relay(tx);
                        return(tx.ToJson());
                    }
                    else
                    {
                        return(context.ToJson());
                    }
                }

            case "getnewaddress":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    WalletAccount account = Program.Wallet.CreateAccount();
                    if (Program.Wallet is NEP6Wallet wallet)
                    {
                        wallet.Save();
                    }
                    return(account.Address);
                }

            case "dumpprivkey":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied");
                }
                else
                {
                    UInt160       scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                    WalletAccount account    = Program.Wallet.GetAccount(scriptHash);
                    return(account.GetKey().Export());
                }

            case "invoke":
            case "invokefunction":
            case "invokescript":
                JObject result = base.Process(method, _params);
                if (Program.Wallet != null)
                {
                    InvocationTransaction tx = new InvocationTransaction
                    {
                        Version = 1,
                        Script  = result["script"].AsString().HexToBytes(),
                        Gas     = Fixed8.Parse(result["gas_consumed"].AsString())
                    };
                    tx.Gas -= Fixed8.FromDecimal(10);
                    if (tx.Gas < Fixed8.Zero)
                    {
                        tx.Gas = Fixed8.Zero;
                    }
                    tx.Gas = tx.Gas.Ceiling();
                    tx     = Program.Wallet.MakeTransaction(tx);
                    if (tx != null)
                    {
                        ContractParametersContext context = new ContractParametersContext(tx);
                        Program.Wallet.Sign(context);
                        if (context.Completed)
                        {
                            tx.Scripts = context.GetScripts();
                        }
                        else
                        {
                            tx = null;
                        }
                    }
                    result["tx"] = tx?.ToArray().ToHexString();
                }
                return(result);

            default:
                return(base.Process(method, _params));
            }
        }
Exemple #21
0
        protected virtual JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getaccountstate":
            {
                UInt160      script_hash = Wallet.ToScriptHash(_params[0].AsString());
                AccountState account     = Blockchain.Default.GetAccountState(script_hash) ?? new AccountState(script_hash);
                return(account.ToJson());
            }

            case "getassetstate":
            {
                UInt256    asset_id = UInt256.Parse(_params[0].AsString());
                AssetState asset    = Blockchain.Default.GetAssetState(asset_id);
                return(asset?.ToJson() ?? throw new RpcException(-100, "Unknown asset"));
            }

            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

            case "getblock":
            {
                Block block;
                if (_params[0] is JNumber)
                {
                    uint index = (uint)_params[0].AsNumber();
                    block = Blockchain.Default.GetBlock(index);
                }
                else
                {
                    UInt256 hash = UInt256.Parse(_params[0].AsString());
                    block = Blockchain.Default.GetBlock(hash);
                }
                if (block == null)
                {
                    throw new RpcException(-100, "Unknown block");
                }
                bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                if (verbose)
                {
                    JObject json = block.ToJson();
                    json["confirmations"] = Blockchain.Default.Height - block.Index + 1;
                    UInt256 hash = Blockchain.Default.GetNextBlockHash(block.Hash);
                    if (hash != null)
                    {
                        json["nextblockhash"] = hash.ToString();
                    }
                    return(json);
                }
                else
                {
                    return(block.ToArray().ToHexString());
                }
            }

            case "getblockcount":
                return(Blockchain.Default.Height + 1);

            case "getblockhash":
            {
                uint height = (uint)_params[0].AsNumber();
                if (height >= 0 && height <= Blockchain.Default.Height)
                {
                    return(Blockchain.Default.GetBlockHash(height).ToString());
                }
                else
                {
                    throw new RpcException(-100, "Invalid Height");
                }
            }

            case "getblocksysfee":
            {
                uint height = (uint)_params[0].AsNumber();
                if (height >= 0 && height <= Blockchain.Default.Height)
                {
                    return(Blockchain.Default.GetSysFeeAmount(height).ToString());
                }
                else
                {
                    throw new RpcException(-100, "Invalid Height");
                }
            }

            case "getconnectioncount":
                return(LocalNode.RemoteNodeCount);

            case "getcontractstate":
            {
                UInt160       script_hash = UInt160.Parse(_params[0].AsString());
                ContractState contract    = Blockchain.Default.GetContract(script_hash);
                return(contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract"));
            }

            case "getrawmempool":
                return(new JArray(LocalNode.GetMemoryPool().Select(p => (JObject)p.Hash.ToString())));

            case "getrawtransaction":
            {
                UInt256     hash    = UInt256.Parse(_params[0].AsString());
                bool        verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                int         height  = -1;
                Transaction tx      = LocalNode.GetTransaction(hash);
                if (tx == null)
                {
                    tx = Blockchain.Default.GetTransaction(hash, out height);
                }
                if (tx == null)
                {
                    throw new RpcException(-100, "Unknown transaction");
                }
                if (verbose)
                {
                    JObject json = tx.ToJson();
                    if (height >= 0)
                    {
                        Header header = Blockchain.Default.GetHeader((uint)height);
                        json["blockhash"]     = header.Hash.ToString();
                        json["confirmations"] = Blockchain.Default.Height - header.Index + 1;
                        json["blocktime"]     = header.Timestamp;
                    }
                    return(json);
                }
                else
                {
                    return(tx.ToArray().ToHexString());
                }
            }

            case "getstorage":
            {
                UInt160     script_hash = UInt160.Parse(_params[0].AsString());
                byte[]      key         = _params[1].AsString().HexToBytes();
                StorageItem item        = Blockchain.Default.GetStorageItem(new StorageKey
                    {
                        ScriptHash = script_hash,
                        Key        = key
                    }) ?? new StorageItem();
                return(item.Value?.ToHexString());
            }

            case "gettxout":
            {
                UInt256 hash  = UInt256.Parse(_params[0].AsString());
                ushort  index = (ushort)_params[1].AsNumber();
                return(Blockchain.Default.GetUnspent(hash, index)?.ToJson(index));
            }

            case "invoke":
            {
                UInt160             script_hash = UInt160.Parse(_params[0].AsString());
                ContractParameter[] parameters  = ((JArray)_params[1]).Select(p => ContractParameter.FromJson(p)).ToArray();
                byte[] script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    script = sb.EmitAppCall(script_hash, parameters).ToArray();
                }
                return(GetInvokeResult(script));
            }

            case "invokefunction":
            {
                UInt160             script_hash = UInt160.Parse(_params[0].AsString());
                string              operation   = _params[1].AsString();
                ContractParameter[] args        = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0];
                byte[]              script;
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    script = sb.EmitAppCall(script_hash, operation, args).ToArray();
                }
                return(GetInvokeResult(script));
            }

            case "invokescript":
            {
                byte[] script = _params[0].AsString().HexToBytes();
                return(GetInvokeResult(script));
            }

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                return(LocalNode.Relay(tx));
            }

            case "submitblock":
            {
                Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>();
                return(LocalNode.Relay(block));
            }

            case "validateaddress":
            {
                JObject json = new JObject();
                UInt160 scriptHash;
                try
                {
                    scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                }
                catch
                {
                    scriptHash = null;
                }
                json["address"] = _params[0];
                json["isvalid"] = scriptHash != null;
                return(json);
            }

            case "getpeers":
            {
                JObject json = new JObject();

                {
                    JArray unconnectedPeers = new JArray();
                    foreach (IPEndPoint peer in LocalNode.GetUnconnectedPeers())
                    {
                        JObject peerJson = new JObject();
                        peerJson["address"] = peer.Address.ToString();
                        peerJson["port"]    = peer.Port;
                        unconnectedPeers.Add(peerJson);
                    }
                    json["unconnected"] = unconnectedPeers;
                }

                {
                    JArray badPeers = new JArray();
                    foreach (IPEndPoint peer in LocalNode.GetBadPeers())
                    {
                        JObject peerJson = new JObject();
                        peerJson["address"] = peer.Address.ToString();
                        peerJson["port"]    = peer.Port;
                        badPeers.Add(peerJson);
                    }
                    json["bad"] = badPeers;
                }

                {
                    JArray connectedPeers = new JArray();
                    foreach (RemoteNode node in LocalNode.GetRemoteNodes())
                    {
                        JObject peerJson = new JObject();
                        peerJson["address"] = node.RemoteEndpoint.Address.ToString();
                        peerJson["port"]    = node.ListenerEndpoint?.Port ?? 0;
                        connectedPeers.Add(peerJson);
                    }
                    json["connected"] = connectedPeers;
                }

                return(json);
            }

            case "getversion":
            {
                JObject json = new JObject();
                json["port"]      = LocalNode.Port;
                json["nonce"]     = LocalNode.Nonce;
                json["useragent"] = LocalNode.UserAgent;
                return(json);
            }

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Exemple #22
0
        protected virtual JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

            case "getblock":
            {
                Block block;
                if (_params[0] is JNumber)
                {
                    uint index = (uint)_params[0].AsNumber();
                    block = Blockchain.Default.GetBlock(index);
                }
                else
                {
                    UInt256 hash = UInt256.Parse(_params[0].AsString());
                    block = Blockchain.Default.GetBlock(hash);
                }
                if (block == null)
                {
                    throw new RpcException(-100, "Unknown block");
                }
                bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                if (verbose)
                {
                    JObject json = block.ToJson();
                    json["confirmations"] = Blockchain.Default.Height - block.Index + 1;
                    UInt256 hash = Blockchain.Default.GetNextBlockHash(block.Hash);
                    if (hash != null)
                    {
                        json["nextblockhash"] = hash.ToString();
                    }
                    return(json);
                }
                else
                {
                    return(block.ToArray().ToHexString());
                }
            }

            case "getblockcount":
                return(Blockchain.Default.Height + 1);

            case "getblockhash":
            {
                uint height = (uint)_params[0].AsNumber();
                return(Blockchain.Default.GetBlockHash(height).ToString());
            }

            case "getconnectioncount":
                return(LocalNode.RemoteNodeCount);

            case "getrawmempool":
                return(new JArray(LocalNode.GetMemoryPool().Select(p => (JObject)p.Hash.ToString())));

            case "getrawtransaction":
            {
                UInt256     hash    = UInt256.Parse(_params[0].AsString());
                bool        verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false);
                int         height  = -1;
                Transaction tx      = LocalNode.GetTransaction(hash);
                if (tx == null)
                {
                    tx = Blockchain.Default.GetTransaction(hash, out height);
                }
                if (tx == null)
                {
                    throw new RpcException(-101, "Unknown transaction");
                }
                if (verbose)
                {
                    JObject json = tx.ToJson();
                    if (height >= 0)
                    {
                        Header header = Blockchain.Default.GetHeader((uint)height);
                        json["blockhash"]     = header.Hash.ToString();
                        json["confirmations"] = Blockchain.Default.Height - header.Index + 1;
                        json["blocktime"]     = header.Timestamp;
                    }
                    return(json);
                }
                else
                {
                    return(tx.ToArray().ToHexString());
                }
            }

            case "gettxout":
            {
                UInt256 hash  = UInt256.Parse(_params[0].AsString());
                ushort  index = (ushort)_params[1].AsNumber();
                return(Blockchain.Default.GetUnspent(hash, index)?.ToJson(index));
            }

            case "sendrawtransaction":
            {
                Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes());
                return(LocalNode.Relay(tx));
            }

            case "submitblock":
            {
                Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>();
                return(LocalNode.Relay(block));
            }

            case "validateaddress":
            {
                JObject json = new JObject();
                UInt160 scriptHash;
                try
                {
                    scriptHash = Wallet.ToScriptHash(_params[0].AsString());
                }
                catch
                {
                    scriptHash = null;
                }
                json["address"] = _params[0];
                json["isvalid"] = scriptHash != null;
                return(json);
            }

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }