private JObject Process(string method, JArray _params) { switch (method) { case "unlock": if (wallet == null) { return("wallet is null."); } if (_params.Count < 2) { return("parameter is error."); } string password = _params[0].AsString(); int duration = (int)_params[1].AsNumber(); bool ok = walletTimeLock.UnLock(password, duration); string result = ok ? "successfully" : "failed"; return($"Wallet unlocked {result}."); case "dumpprivkey": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UInt160 scriptHash = _params[0].AsString().ToScriptHash(); WalletAccount account = wallet.GetAccount(scriptHash); return(account.GetKey().Export()); } case "getaccountstate": { UInt160 script_hash = _params[0].AsString().ToScriptHash(); AccountState account = Blockchain.Singleton.Store.GetAccounts().TryGet(script_hash) ?? new AccountState(script_hash); return(account.ToJson()); } case "getassetstate": { UInt256 asset_id = UInt256.Parse(_params[0].AsString()); AssetState asset = Blockchain.Singleton.Store.GetAssets().TryGet(asset_id); return(asset?.ToJson() ?? throw new RpcException(-100, "Unknown asset")); } case "getbalance": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { JObject json = new JObject(); switch (UIntBase.Parse(_params[0].AsString())) { case UInt160 asset_id_160: //BRC5 balance json["balance"] = wallet.GetAvailable(asset_id_160).ToString(); break; case UInt256 asset_id_256: //Global Assets balance IEnumerable <Coin> coins = 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 "getbestblockhash": return(Blockchain.Singleton.CurrentBlockHash.ToString()); case "getblock": { Block block; if (_params[0] is JNumber) { uint index = (uint)_params[0].AsNumber(); block = Blockchain.Singleton.Store.GetBlock(index); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); block = Blockchain.Singleton.Store.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.Singleton.Height - block.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(block.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(block.ToArray().ToHexString()); } case "getblockcount": return(Blockchain.Singleton.Height + 1); case "getblockhash": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.GetBlockHash(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getblockheader": { Header header; if (_params[0] is JNumber) { uint height = (uint)_params[0].AsNumber(); header = Blockchain.Singleton.Store.GetHeader(height); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); header = Blockchain.Singleton.Store.GetHeader(hash); } if (header == null) { throw new RpcException(-100, "Unknown block"); } bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); if (verbose) { JObject json = header.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(header.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(header.ToArray().ToHexString()); } case "getblocksysfee": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.Store.GetSysFeeAmount(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getconnectioncount": return(LocalNode.Singleton.ConnectedCount); case "getcontractstate": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractState contract = Blockchain.Singleton.Store.GetContracts().TryGet(script_hash); return(contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract")); } case "getnewaddress": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { WalletAccount account = wallet.CreateAccount(); if (wallet is BRC6Wallet BRC6) { BRC6.Save(); } return(account.Address); } case "getpeers": { JObject json = new JObject(); json["unconnected"] = new JArray(LocalNode.Singleton.GetUnconnectedPeers().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Address.ToString(); peerJson["port"] = p.Port; return(peerJson); })); json["bad"] = new JArray(); //badpeers has been removed json["connected"] = new JArray(LocalNode.Singleton.GetRemoteNodes().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Remote.Address.ToString(); peerJson["port"] = p.ListenerPort; return(peerJson); })); return(json); } case "getrawmempool": return(new JArray(Blockchain.Singleton.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.Singleton.GetTransaction(hash); if (tx == null) { throw new RpcException(-100, "Unknown transaction"); } if (verbose) { JObject json = tx.ToJson(); uint? height = Blockchain.Singleton.Store.GetTransactions().TryGet(hash)?.BlockIndex; if (height != null) { Header header = Blockchain.Singleton.Store.GetHeader((uint)height); json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; } return(json); } return(tx.ToArray().ToHexString()); } case "getstorage": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); byte[] key = _params[1].AsString().HexToBytes(); StorageItem item = Blockchain.Singleton.Store.GetStorages().TryGet(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.Singleton.Store.GetUnspent(hash, index)?.ToJson(index)); } case "createaddress": { byte[] privateKey = new byte[32]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(privateKey); KeyPair key = new KeyPair(privateKey); byte[] pubkey = Contract.CreateSignatureRedeemScript(key.PublicKey); JObject json = new JObject(); json["address"] = pubkey.ToScriptHash().ToAddress(); json["pubkey"] = key.PublicKey.EncodePoint(true).ToHexString(); json["prikey"] = key.PrivateKey.ToHexString(); json["wif"] = key.Export(); json["script"] = pubkey.ToHexString(); return(json); } } case "getutxos": { UInt160 script_hash = _params[0].AsString().ToScriptHash(); AccountState account = Blockchain.Singleton.Store.GetAccounts().TryGet(script_hash) ?? new AccountState(script_hash); return(account.ToJson()); } case "getvalidators": using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) { var validators = snapshot.GetValidators(); return(snapshot.GetEnrollments().Select(p => { JObject validator = new JObject(); validator["publickey"] = p.PublicKey.ToString(); validator["votes"] = p.Votes.ToString(); validator["active"] = validators.Contains(p.PublicKey); return validator; }).ToArray()); } case "getversion": { JObject json = new JObject(); json["port"] = LocalNode.Singleton.ListenerPort; json["nonce"] = LocalNode.Nonce; json["useragent"] = LocalNode.UserAgent; return(json); } case "getwalletheight": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { return((wallet.WalletHeight > 0) ? wallet.WalletHeight - 1 : 0); } 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 "listaddress": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { return(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 (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); 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 ? _params[5].AsString().ToScriptHash() : null; string remark = _params.Count >= 7 ? _params[6].AsString() : null; Transaction tx = 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"); } AddRemak(remark, tx); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "transfer": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); 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 ? _params[5].AsString().ToScriptHash() : from; string remark = _params.Count >= 7 ? _params[6].AsString() : null; Transaction tx = 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"); } AddRemak(remark, tx); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendmany": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } 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 = to[i]["address"].AsString().ToScriptHash() }; 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 ? _params[2].AsString().ToScriptHash() : null; string remark = _params.Count >= 4 ? _params[3].AsString() : null; Transaction tx = wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee); if (tx == null) { throw new RpcException(-300, "Insufficient funds"); } AddRemak(remark, tx); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendrawtransaction": { Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes()); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(tx).Result; return(GetRelayResult(reason)); } case "sendtoaddress": if (wallet == null || walletTimeLock.IsLocked()) { throw new RpcException(-400, "wallet is null or locked."); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); 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 ? _params[4].AsString().ToScriptHash() : null; string remark = _params.Count >= 6 ? _params[5].AsString() : null; Transaction tx = 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"); } AddRemak(remark, tx); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "submitblock": { Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>(); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(block).Result; return(GetRelayResult(reason)); } case "validateaddress": { JObject json = new JObject(); UInt160 scriptHash; try { scriptHash = _params[0].AsString().ToScriptHash(); } catch { scriptHash = null; } json["address"] = _params[0]; json["isvalid"] = scriptHash != null; return(json); } /* * case "backupwallet": * if (wallet == null || walletTimeLock.IsLocked()) * throw new RpcException(-400, "wallet is null or locked."); * else * { * return BackupWallet(); * } * * case "backupwallettosqlite": * if (wallet == null) * throw new RpcException(-400, "Access denied"); * else * { * try * { * string path = ((Bhp.Wallets.BRC6.BRC6Wallet)wallet).Path; * string WalletName = _params.Count >= 1 ? _params[0].AsString().Trim() : path.Substring(path.LastIndexOf("\\") + 1).Trim(); * * int nIndex = WalletName.LastIndexOf('.'); * if (nIndex >= 0) * { * WalletName = WalletName.Substring(0, nIndex).Trim(); * } * else * { * WalletName = WalletName.Trim(); * } * return "Backup Wallet Success! Name:" + SQLiteOperateForBackupWallet.BackupWalletToSQLite(WifToList(), WalletName); * } * catch (Exception ex) * { * throw new Exception(ex.ToString()); * //throw new RpcException(-401, "SQLite Exception"); * } * } * * case "recoverwalletfromsqlite": * if (wallet == null) * throw new RpcException(-400, "Access denied"); * else * { * if (_params.Count == 0) * { * return "Please Input BackupWalletName"; * } * string BackWalletName = _params[0].AsString().Trim(); * //System.IO.Path.GetExtension(BackWalletName) * * string FileName = "";//不含后缀 * int nIndex = BackWalletName.LastIndexOf('.'); * if (nIndex >= 0) * { * FileName = BackWalletName.Substring(0, nIndex) + ".sqlite"; * } * else * { * FileName = BackWalletName + ".sqlite"; * } * List<string> wifs = SQLiteOperateForBackupWallet.RecoverWalletFromSQLite(FileName); * foreach (string wif in wifs) * { * WalletAccount account; * try * { * account = wallet.Import(wif); * } * catch (FormatException) * { * continue; * } * } * if (wallet is BRC6Wallet walletBrc6) * walletBrc6.Save(); * return "Recover Wallet Success"; * } * * case "closewallet": * if (wallet == null) * throw new RpcException(-400, "Access denied"); * else * { * if (wallet is IDisposable disposable) * { * disposable.Dispose(); * wallet = null; * } * return "Close Wallet Success"; * } */ default: throw new RpcException(-32601, "Method not found"); } }
private JObject Process(string method, JArray _params) { switch (method) { /* * case "dumpprivkey": * if (wallet == null) * throw new RpcException(-400, "Access denied"); * else * { * UInt160 scriptHash = _params[0].AsString().ToScriptHash(); * WalletAccount account = wallet.GetAccount(scriptHash); * return account.GetKey().Export(); * } */ case "getaccountstate": { UInt160 script_hash = _params[0].AsString().ToScriptHash(); AccountState account = Blockchain.Singleton.Store.GetAccounts().TryGet(script_hash) ?? new AccountState(script_hash); return(account.ToJson()); } case "getassetstate": { UInt256 asset_id = UInt256.Parse(_params[0].AsString()); AssetState asset = Blockchain.Singleton.Store.GetAssets().TryGet(asset_id); return(asset?.ToJson() ?? throw new RpcException(-100, "Unknown asset")); } case "getbalance": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { JObject json = new JObject(); switch (UIntBase.Parse(_params[0].AsString())) { case UInt160 asset_id_160: //BRC5 balance json["balance"] = wallet.GetAvailable(asset_id_160).ToString(); break; case UInt256 asset_id_256: //Global Assets balance IEnumerable <Coin> coins = 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 "getbestblockhash": return(Blockchain.Singleton.CurrentBlockHash.ToString()); case "getblock": { Block block; if (_params[0] is JNumber) { uint index = (uint)_params[0].AsNumber(); block = Blockchain.Singleton.Store.GetBlock(index); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); block = Blockchain.Singleton.Store.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.Singleton.Height - block.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(block.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(block.ToArray().ToHexString()); } case "getblockcount": return(Blockchain.Singleton.Height + 1); case "getblockhash": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.GetBlockHash(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getblockheader": { Header header; if (_params[0] is JNumber) { uint height = (uint)_params[0].AsNumber(); header = Blockchain.Singleton.Store.GetHeader(height); } else { UInt256 hash = UInt256.Parse(_params[0].AsString()); header = Blockchain.Singleton.Store.GetHeader(hash); } if (header == null) { throw new RpcException(-100, "Unknown block"); } bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); if (verbose) { JObject json = header.ToJson(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; UInt256 hash = Blockchain.Singleton.Store.GetNextBlockHash(header.Hash); if (hash != null) { json["nextblockhash"] = hash.ToString(); } return(json); } return(header.ToArray().ToHexString()); } case "getblocksysfee": { uint height = (uint)_params[0].AsNumber(); if (height <= Blockchain.Singleton.Height) { return(Blockchain.Singleton.Store.GetSysFeeAmount(height).ToString()); } throw new RpcException(-100, "Invalid Height"); } case "getconnectioncount": return(LocalNode.Singleton.ConnectedCount); case "getcontractstate": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractState contract = Blockchain.Singleton.Store.GetContracts().TryGet(script_hash); return(contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract")); } case "getnewaddress": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { WalletAccount account = wallet.CreateAccount(); if (wallet is BRC6Wallet BRC6) { BRC6.Save(); } return(account.Address); } case "getpeers": { JObject json = new JObject(); json["unconnected"] = new JArray(LocalNode.Singleton.GetUnconnectedPeers().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Address.ToString(); peerJson["port"] = p.Port; return(peerJson); })); json["bad"] = new JArray(); //badpeers has been removed json["connected"] = new JArray(LocalNode.Singleton.GetRemoteNodes().Select(p => { JObject peerJson = new JObject(); peerJson["address"] = p.Remote.Address.ToString(); peerJson["port"] = p.ListenerPort; return(peerJson); })); return(json); } case "getrawmempool": return(new JArray(Blockchain.Singleton.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.Singleton.GetTransaction(hash); if (tx == null) { throw new RpcException(-100, "Unknown transaction"); } if (verbose) { JObject json = tx.ToJson(); uint? height = Blockchain.Singleton.Store.GetTransactions().TryGet(hash)?.BlockIndex; if (height != null) { Header header = Blockchain.Singleton.Store.GetHeader((uint)height); json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; } return(json); } return(tx.ToArray().ToHexString()); } case "getstorage": { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); byte[] key = _params[1].AsString().HexToBytes(); StorageItem item = Blockchain.Singleton.Store.GetStorages().TryGet(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.Singleton.Store.GetUnspent(hash, index)?.ToJson(index)); } case "getvalidators": using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) { var validators = snapshot.GetValidators(); return(snapshot.GetEnrollments().Select(p => { JObject validator = new JObject(); validator["publickey"] = p.PublicKey.ToString(); validator["votes"] = p.Votes.ToString(); validator["active"] = validators.Contains(p.PublicKey); return validator; }).ToArray()); } case "getversion": { JObject json = new JObject(); json["port"] = LocalNode.Singleton.ListenerPort; json["nonce"] = LocalNode.Nonce; json["useragent"] = LocalNode.UserAgent; return(json); } case "getwalletheight": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { return((wallet.WalletHeight > 0) ? wallet.WalletHeight - 1 : 0); } 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 "listaddress": if (wallet == null) { throw new RpcException(-400, "Access denied."); } else { return(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 (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); 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 ? _params[5].AsString().ToScriptHash() : null; Transaction tx = 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); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "transfer": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); 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 ? _params[5].AsString().ToScriptHash() : from; Transaction tx = 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); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendmany": if (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 = to[i]["address"].AsString().ToScriptHash() }; 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 ? _params[2].AsString().ToScriptHash() : null; Transaction tx = wallet.MakeTransaction(null, outputs, change_address: change_address, fee: fee); if (tx == null) { throw new RpcException(-300, "Insufficient funds"); } ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "sendrawtransaction": { Transaction tx = Transaction.DeserializeFrom(_params[0].AsString().HexToBytes()); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(tx).Result; return(GetRelayResult(reason)); } case "sendtoaddress": if (wallet == null) { throw new RpcException(-400, "Access denied"); } else { UIntBase assetId = UIntBase.Parse(_params[0].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); 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 ? _params[4].AsString().ToScriptHash() : null; Transaction tx = 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); wallet.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); wallet.ApplyTransaction(tx); system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return(tx.ToJson()); } else { return(context.ToJson()); } } case "submitblock": { Block block = _params[0].AsString().HexToBytes().AsSerializable <Block>(); RelayResultReason reason = system.Blockchain.Ask <RelayResultReason>(block).Result; return(GetRelayResult(reason)); } case "validateaddress": { JObject json = new JObject(); UInt160 scriptHash; try { scriptHash = _params[0].AsString().ToScriptHash(); } catch { scriptHash = null; } json["address"] = _params[0]; json["isvalid"] = scriptHash != null; return(json); } default: throw new RpcException(-32601, "Method not found"); } }