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; } }
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(); }
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); }
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; } }
/// <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; } }
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"); } }
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"); } }
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); }
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."); } }
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"); } }
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)); } }
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); }
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)); } }
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)); } }
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)); } }
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"); } }
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"); } }