Example #1
0
        private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message)
        {
            TR.Enter();
            Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}");
            if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived))
            {
                TR.Exit();
                return;
            }
            if (payload.ValidatorIndex != context.PrimaryIndex)
            {
                return;
            }
            if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp())
            {
                Log($"Timestamp incorrect: {payload.Timestamp}");
                TR.Exit();
                return;
            }
            context.State            |= ConsensusState.RequestReceived;
            context.Timestamp         = payload.Timestamp;
            context.Nonce             = message.Nonce;
            context.NextConsensus     = message.NextConsensus;
            context.TransactionHashes = message.TransactionHashes;
            context.Transactions      = new Dictionary <UInt256, Transaction>();
            if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
            {
                TR.Exit(); return;
            }
            context.Signatures = new byte[context.Validators.Length][];
            context.Signatures[payload.ValidatorIndex] = message.Signature;
            Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in context.TransactionHashes.Skip(1))
            {
                if (mempool.TryGetValue(hash, out Transaction tx))
                {
                    if (!AddTransaction(tx, false))
                    {
                        TR.Exit();
                        return;
                    }
                }
            }
            if (!AddTransaction(message.MinerTransaction, true))
            {
                TR.Exit(); return;
            }
            if (context.Transactions.Count < context.TransactionHashes.Length)
            {
                UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray();
                LocalNode.AllowHashes(hashes);
                InvPayload msg = InvPayload.Create(InventoryType.TX, hashes);
                foreach (RemoteNode node in localNode.GetRemoteNodes())
                {
                    node.EnqueueMessage("getdata", msg);
                }
            }
            TR.Exit();
        }
Example #2
0
 private void OnTimeout(object state)
 {
     Log($"{nameof(OnTimeout)} h:{timer_height} v:{timer_view} state:{context.State}");
     lock (context)
     {
         if (timer_height != context.Height || timer_view != context.ViewNumber)
         {
             Log($"ignored");
             return;
         }
         if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
         {
             Log($"SendPerpareRequest h:{timer_height} v:{timer_view}");
             context.State |= ConsensusState.RequestSent;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                 context.Nonce     = GetNonce();
                 List <Transaction> transactions = LocalNode.GetMemoryPool().ToList();
                 transactions.Insert(0, CreateMinerTransaction(transactions, context.Height, context.Nonce));
                 context.TransactionHashes = transactions.Select(p => p.Hash).ToArray();
                 context.Transactions      = transactions.ToDictionary(p => p.Hash);
                 context.NextMiner         = Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(transactions).ToArray());
                 context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex]));
             }
             SignAndRelay(context.MakePerpareRequest());
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
         }
         else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
         {
             RequestChangeView();
         }
     }
 }
        private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message)
        {
            Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}");
            if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived))
            {
                return;
            }
            if (payload.ValidatorIndex != context.PrimaryIndex)
            {
                return;
            }
            if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp())
            {
                Log($"Timestamp incorrect: {payload.Timestamp}");
                return;
            }
            context.State            |= ConsensusState.RequestReceived;
            context.Timestamp         = payload.Timestamp;
            context.Nonce             = message.Nonce;
            context.CurrentConsensus  = message.CurrentConsensus;
            context.NextConsensus     = message.NextConsensus;
            context.TransactionHashes = message.TransactionHashes;
            if (context.TransactionHashes.Length > MaxTransactionsPerBlock)
            {
                return;
            }
            context.Transactions = new Dictionary <UInt256, Transaction>();
            if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
            {
                return;
            }
            context.Signatures = new byte[context.Validators.Length][];
            context.Signatures[payload.ValidatorIndex] = message.Signature;
            Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in context.TransactionHashes.Skip(1))
            {
                if (mempool.TryGetValue(hash, out Transaction tx))
                {
                    if (!AddTransaction(tx, false))
                    {
                        return;
                    }
                }
            }
            if (!AddTransaction(message.MinerTransaction, true))
            {
                return;
            }
            LocalNode.AllowHashes(context.TransactionHashes.Except(context.Transactions.Keys));
            if (context.Transactions.Count < context.TransactionHashes.Length)
            {
                localNode.SynchronizeMemoryPool();
            }
        }
Example #4
0
        private void OnPerpareRequestReceived(ConsensusPayload payload, PerpareRequest message)
        {
            Log($"{nameof(OnPerpareRequestReceived)} h:{payload.Height} v:{message.ViewNumber} i:{payload.MinerIndex} tx:{message.TransactionHashes.Length}");
            if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived))
            {
                return;
            }
            if (payload.MinerIndex != context.PrimaryIndex)
            {
                return;
            }
            if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp())
            {
                Log($"Timestamp incorrect:{payload.Timestamp}");
                return;
            }
            context.State            |= ConsensusState.RequestReceived;
            context.Timestamp         = payload.Timestamp;
            context.Nonce             = message.Nonce;
            context.NextMiner         = message.NextMiner;
            context.TransactionHashes = message.TransactionHashes;
            context.Transactions      = new Dictionary <UInt256, Transaction>();
            if (!context.MakeHeader().VerifySignature(context.Miners[payload.MinerIndex], message.Signature))
            {
                return;
            }
            context.Signatures = new byte[context.Miners.Length][];
            context.Signatures[payload.MinerIndex] = message.Signature;
            if (!AddTransaction(message.MinerTransaction))
            {
                return;
            }
            Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in context.TransactionHashes.Skip(1))
            {
                if (mempool.ContainsKey(hash))
                {
                    if (!AddTransaction(mempool[hash]))
                    {
                        return;
                    }
                }
            }
            LocalNode.AllowHashes(context.TransactionHashes.Except(context.Transactions.Keys));
            if (context.Transactions.Count < context.TransactionHashes.Length)
            {
                LocalNode.SynchronizeMemoryPool();
            }
        }
Example #5
0
 private void OnTimeout(object state)
 {
     lock (context)
     {
         if (timer_height != context.BlockIndex || timer_view != context.ViewNumber)
         {
             return;
         }
         Log($"timeout: height={timer_height} view={timer_view} state={context.State}");
         if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
         {
             Log($"send perpare request: height={timer_height} view={timer_view}");
             context.State |= ConsensusState.RequestSent;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                 context.Nonce     = GetNonce();
                 List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();
                 if (transactions.Count >= Settings.Default.MaxTransactionsPerBlock)
                 {
                     transactions = transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(Settings.Default.MaxTransactionsPerBlock - 1).ToList();
                 }
                 transactions.Insert(0, CreateMinerTransaction(transactions, context.BlockIndex, context.Nonce));
                 context.TransactionHashes           = transactions.Select(p => p.Hash).ToArray();
                 context.Transactions                = transactions.ToDictionary(p => p.Hash);
                 context.NextConsensus               = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());
                 context.Signatures[context.MyIndex] = context.MakeHeader().Sign(context.KeyPair);
             }
             InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes);
             foreach (RemoteNode node in localNode.GetRemoteNodes())
             {
                 node.EnqueueMessage("inv", invPayload);
             }
             SignAndRelay(context.MakePrepareRequest());
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
         }
         else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
         {
             RequestChangeView();
         }
     }
 }
Example #6
0
        private void FillContext()
        {
            ReportNeoBlockchain reportObj = new ReportNeoBlockchain("[NeoConsensusService-FillContext]");

            List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();

            if (transactions.Count >= Settings.Default.MaxTransactionsPerBlock)
            {
                transactions = transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(Settings.Default.MaxTransactionsPerBlock - 1).ToList();
            }
            Fixed8 amount_netfee = Block.CalculateNetFee(transactions);

            TransactionOutput[] outputs = amount_netfee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput
                                                                                                            {
                                                                                                                AssetId    = Blockchain.UtilityToken.Hash,
                                                                                                                Value      = amount_netfee,
                                                                                                                ScriptHash = wallet.GetChangeAddress()
                                                                                                            } };
            while (true)
            {
                ulong            nonce = GetNonce();
                MinerTransaction tx    = new MinerTransaction
                {
                    Nonce      = (uint)(nonce % (uint.MaxValue + 1ul)),
                    Attributes = new TransactionAttribute[0],
                    Inputs     = new CoinReference[0],
                    Outputs    = outputs,
                    Scripts    = new Witness[0]
                };
                if (Blockchain.Default.GetTransaction(tx.Hash) == null)
                {
                    context.Nonce = nonce;
                    transactions.Insert(0, tx);
                    break;
                }
            }
            context.TransactionHashes = transactions.Select(p => p.Hash).ToArray();
            context.Transactions      = transactions.ToDictionary(p => p.Hash);
            context.NextConsensus     = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());

            reportObj.appendElapsedTime();
        }
Example #7
0
        private void FillContext()
        {
            TR.Enter();
            IEnumerable <Transaction> mem_pool = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p));

            foreach (PolicyPlugin plugin in PolicyPlugin.Instances)
            {
                mem_pool = plugin.Filter(mem_pool);
            }
            List <Transaction> transactions  = mem_pool.ToList();
            Fixed8             amount_netfee = Block.CalculateNetFee(transactions);

            TransactionOutput[] outputs = amount_netfee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput
                                                                                                            {
                                                                                                                AssetId    = Blockchain.UtilityToken.Hash,
                                                                                                                Value      = amount_netfee,
                                                                                                                ScriptHash = wallet.GetChangeAddress()
                                                                                                            } };
            while (true)
            {
                ulong            nonce = GetNonce();
                MinerTransaction tx    = new MinerTransaction
                {
                    Nonce      = (uint)(nonce % (uint.MaxValue + 1ul)),
                    Attributes = new TransactionAttribute[0],
                    Inputs     = new CoinReference[0],
                    Outputs    = outputs,
                    Scripts    = new Witness[0]
                };
                if (Blockchain.Default.GetTransaction(tx.Hash) == null)
                {
                    context.Nonce = nonce;
                    transactions.Insert(0, tx);
                    break;
                }
            }
            context.TransactionHashes = transactions.Select(p => p.Hash).ToArray();
            context.Transactions      = transactions.ToDictionary(p => p.Hash);
            context.NextConsensus     = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());
            TR.Exit();
        }
Example #8
0
 internal bool Verify(bool mempool)
 {
     if (!base.Verify())
     {
         return(false);
     }
     TransactionResult[] results = GetTransactionResults()?.Where(p => p.Amount < Fixed8.Zero).ToArray();
     if (results == null)
     {
         return(false);
     }
     foreach (TransactionResult r in results)
     {
         RegisterTransaction tx = Blockchain.Default.GetTransaction(r.AssetId) as RegisterTransaction;
         if (tx == null)
         {
             return(false);
         }
         if (tx.Amount < Fixed8.Zero)
         {
             continue;
         }
         if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.Statistics))
         {
             return(false);
         }
         Fixed8 quantity_issued = Blockchain.Default.GetQuantityIssued(r.AssetId);
         if (mempool)
         {
             quantity_issued += LocalNode.GetMemoryPool().OfType <IssueTransaction>().SelectMany(p => p.Outputs).Where(p => p.AssetId == r.AssetId).Sum(p => p.Value);
         }
         if (tx.Amount - quantity_issued < -r.Amount)
         {
             return(false);
         }
     }
     return(true);
 }
Example #9
0
 private void OnTimeout(object state)
 {
     lock (context)
     {
         if (timer_height != context.Height || timer_view != context.ViewNumber)
         {
             return;
         }
         Log($"timeout: height={timer_height} view={timer_view} state={context.State}");
         if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
         {
             Log($"send perpare request: height={timer_height} view={timer_view}");
             context.State |= ConsensusState.RequestSent;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                 context.Nonce     = GetNonce();
                 List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();
                 if (transactions.Count >= MaxTransactionsPerBlock)
                 {
                     transactions = transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(MaxTransactionsPerBlock - 1).ToList();
                 }
                 transactions.Insert(0, CreateMinerTransaction(transactions, context.Height, context.Nonce));
                 context.TransactionHashes = transactions.Select(p => p.Hash).ToArray();
                 context.Transactions      = transactions.ToDictionary(p => p.Hash);
                 context.NextMiner         = Blockchain.GetMinerAddress(Blockchain.Default.GetMiners(transactions).ToArray());
                 context.Signatures[context.MinerIndex] = context.MakeHeader().Sign(wallet.GetAccount(context.Miners[context.MinerIndex]));
             }
             SignAndRelay(context.MakePerpareRequest());
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
         }
         else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
         {
             RequestChangeView();
         }
     }
 }
Example #10
0
        public override NodeMonitorPayload GetNodeMonitorPayload()
        {
            var lastBlock = Blockchain.Default.GetBlock(Blockchain.Default.Height);
            var payload   = new NodeMonitorPayload
            {
                Version       = this.localNode.UserAgent,
                Peers         = (uint)this.localNode.RemoteNodeCount,
                LastBlockTime = lastBlock.Timestamp,
                UnconfirmedTransactionsCount = (uint)LocalNode.GetMemoryPool().Count(),
                WalletIsOpen = Program.Wallet != null,
                Name         = this.nodeName,
                Type         = this.nodeType,
                P2PEnabled   = this.localNode.ServiceEnabled && this.localNode.RemoteNodeCount > 0,
                RpcEnabled   = this.nodeType == "RPC",
                LastBlock    = new BlockMonitorPayload
                {
                    Height       = lastBlock.Index,
                    Hash         = lastBlock.Hash,
                    Transactions = (uint)lastBlock.Transactions.Length
                }
            };

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                return(json);
            }

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

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Example #12
0
        private JObject InternalCall(string method, JArray _params)
        {
            switch (method)
            {
            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

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

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

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

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

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

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

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

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

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Example #13
0
        private void OnTimeout(object state)
        {
            lock (context)
            {
                if (timer_height != context.BlockIndex || timer_view != context.ViewNumber)
                {
                    return;
                }
                Log($"timeout: height={timer_height} view={timer_view} state={context.State}");
                if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent))
                {
                    Log($"send prepare request: height={timer_height} view={timer_view}");
                    context.State |= ConsensusState.RequestSent;
                    if (!context.State.HasFlag(ConsensusState.SignatureSent))
                    {
                        context.Timestamp = Math.Max(DateTime.Now.ToTimestamp(), Blockchain.Default.GetHeader(context.PrevHash).Timestamp + 1);
                        context.Nonce     = GetNonce();
                        List <Transaction> transactions = LocalNode.GetMemoryPool().Where(p => CheckPolicy(p)).ToList();

                        Dictionary <UInt160, Transaction> scriptHashDictionary = new Dictionary <UInt160, Transaction>();
                        Console.WriteLine("Mempool count " + transactions.Count.ToString());
                        for (int i = 0; i < transactions.Count; i++)
                        {
                            if (transactions[i].Type == TransactionType.MinerTransaction ||
                                transactions[i].Type == TransactionType.AnonymousContractTransaction ||
                                transactions[i].Type == TransactionType.RingConfidentialTransaction)
                            {
                                continue;
                            }
                            if (transactions[i].Inputs == null || transactions[i].Inputs.Length == 0)
                            {
                                continue;
                            }

                            if (transactions[i].References == null)
                            {
                                transactions.RemoveAt(i);
                                i--;
                                continue;
                            }


                            if (transactions[i].Inputs.Length > 0 &&
                                transactions[i].References.ContainsKey(transactions[i].Inputs[0]) &&
                                LocalNode.KnownHashes.Count > 0)
                            {
                                UInt160 scripthash = transactions[i].References[transactions[i].Inputs[0]].ScriptHash;

                                if (scriptHashDictionary.ContainsKey(scripthash))
                                {
                                    Transaction prevTx = scriptHashDictionary[scripthash];
                                    if (LocalNode.KnownHashes.IndexOf(prevTx.Hash) > LocalNode.KnownHashes.IndexOf(transactions[i].Hash))
                                    {
                                        scriptHashDictionary[scripthash] = transactions[i];
                                        transactions.Remove(prevTx);
                                    }
                                    else
                                    {
                                        transactions.RemoveAt(i);
                                    }

                                    i--;
                                }
                                else
                                {
                                    scriptHashDictionary.Add(scripthash, transactions[i]);
                                }
                            }
                        }


                        Transaction[]      tmpool = LocalNode.GetMemoryPool().ToArray();
                        List <Transaction> consensus_transactions = new List <Transaction>();

                        for (int i = 0; i < transactions.Count; i++)
                        {
                            Transaction tx = transactions[i];
                            if (!tx.Verify(tmpool))
                            {
                                Console.Write("Transaction verify failed : ");

                                transactions.RemoveAt(i);
                                LocalNode.RemoveTxFromMempool(tx.Hash);
                                i--;

                                Console.WriteLine(tx.ToJsonString());
                                continue;
                            }

                            UInt160 fromScriptHash = LocalNode.GetFromAddressFromTx(tx); Console.WriteLine("Step_1_2");

                            if (Blockchain.IsConsensusAddress(fromScriptHash))
                            {
                                consensus_transactions.Add(tx);
                                continue;
                            }
                            else if (tx.GetFee() == Fixed8.Zero && fromScriptHash != UInt160.Zero)
                            {
                                if (LocalNode.freetx_pool.ContainsKey(fromScriptHash) &&
                                    LocalNode.freetx_pool[fromScriptHash].Count >= Blockchain.Default.FreeTransactionLimitPerPeriod &&
                                    Blockchain.Default.Height - LocalNode.freetx_pool[fromScriptHash].ElementAt(LocalNode.freetx_pool[fromScriptHash].Count - 1) < Blockchain.Default.FreeTransactionBlockPeriodNum)
                                {
                                    UInt256 removalHash = transactions[i].Hash;

                                    Console.WriteLine("TX removed " + removalHash);

                                    LocalNode.RemoveTxFromMempool(removalHash);

                                    transactions.RemoveAt(i);
                                    i--;
                                }
                                else
                                {
                                    localNode.AddFreeTxAddressToPool(fromScriptHash);

                                    foreach (RemoteNode node in LocalNode.Default.GetRemoteNodes()) // enqueue message
                                    {
                                        node.EnqueueMessage("blockfree", fromScriptHash);
                                    }
                                }
                            }
                        }

                        if (transactions.Count >= MaxTransactionsPerBlock)
                        {
                            transactions = consensus_transactions.Concat(transactions.OrderByDescending(p => p.NetworkFee / p.Size).Take(MaxTransactionsPerBlock - 1 - consensus_transactions.Count).ToList()).ToList();
                        }

                        transactions.Insert(0, CreateMinerTransaction(transactions, context.BlockIndex, context.Nonce));
                        context.TransactionHashes           = transactions.Select(p => p.Hash).ToArray();
                        context.Transactions                = transactions.ToDictionary(p => p.Hash);
                        context.CurrentConsensus            = wallet.GetChangeAddress();
                        context.NextConsensus               = Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(transactions).ToArray());
                        context.Signatures[context.MyIndex] = context.MakeHeader().Sign((KeyPair)wallet.GetKey(context.Validators[context.MyIndex]));
                    }
                    SignAndRelay(context.MakePrepareRequest());
                    timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer_view + 1)), Timeout.InfiniteTimeSpan);
                }
                else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup))
                {
                    RequestChangeView();
                }
            }
        }
Example #14
0
        protected virtual JObject Process(string method, JArray _params)
        {
            switch (method)
            {
            case "getbestblockhash":
                return(Blockchain.Default.CurrentBlockHash.ToString());

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

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

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

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

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

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

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

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

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

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

            default:
                throw new RpcException(-32601, "Method not found");
            }
        }
Example #15
0
 private void OnMemPoolMessageReceived()
 {
     EnqueueMessage("inv", InvPayload.Create(InventoryType.TX, LocalNode.GetMemoryPool().Select(p => p.Hash).ToArray()));
 }
        private static JArray GetMempoolTransaction(UInt160 ScriptHash)
        {
            JArray result = new JArray();

            foreach (Transaction tx in LocalNode.GetMemoryPool())
            {
                UInt160 from_script = null;
                UInt160 to_script   = null;
                JObject obj         = new JObject();

                if (tx is ContractTransaction)
                {
                    try
                    {
                        foreach (CoinReference input in tx.Inputs)
                        {
                            Transaction inputTx = Blockchain.Default.GetTransaction(input.PrevHash);
                            if (inputTx != null)
                            {
                                from_script = inputTx.Outputs[input.PrevIndex].ScriptHash;
                            }
                            else
                            {
                                foreach (Transaction inTx in LocalNode.GetMemoryPool())
                                {
                                    if (inTx.Hash.Equals(input.PrevHash))
                                    {
                                        from_script = inTx.Outputs[input.PrevIndex].ScriptHash;
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex) { }

                    if (tx.Outputs.Length > 0)
                    {
                        to_script = tx.Outputs[0].ScriptHash;
                    }

                    Dictionary <UInt256, Fixed8> balance = new Dictionary <UInt256, Fixed8>();
                    Dictionary <UInt256, Fixed8> fee     = new Dictionary <UInt256, Fixed8>();
                    for (int i = 0; i < tx.Outputs.Length; i++)
                    {
                        AssetState state = Blockchain.Default.GetAssetState(tx.Outputs[i].AssetId);
                        if (tx.Outputs[i].ScriptHash.Equals(to_script))
                        {
                            if (balance.ContainsKey(tx.Outputs[i].AssetId))
                            {
                                balance[tx.Outputs[i].AssetId] += tx.Outputs[i].Value;
                            }
                            else
                            {
                                balance[tx.Outputs[i].AssetId] = tx.Outputs[i].Value;
                            }
                        }

                        if (!fee.ContainsKey(tx.Outputs[i].AssetId))
                        {
                            if (tx.Outputs[i].Fee != Fixed8.Zero)
                            {
                                fee[tx.Outputs[i].AssetId] = tx.Outputs[i].Fee;
                            }
                        }
                    }
                    Fixed8 qrgFee = fee.Sum(p => p.Value);
                    if (balance.Count > 0)
                    {
                        UInt256 assetId = balance.First().Key;
                        Fixed8  value   = balance.Sum(p => p.Value);

                        AssetState assetState = Blockchain.Default.GetAssetState(assetId);
                        obj["asset"]  = assetState.GetName();
                        obj["amount"] = value.ToString();
                        obj["fee"]    = qrgFee.ToString();
                    }
                }
                else if (tx is ClaimTransaction)
                {
                    ClaimTransaction claimTx = (ClaimTransaction)tx;
                    if (claimTx.Outputs.Length > 0)
                    {
                        from_script = to_script = tx.Outputs[0].ScriptHash;
                    }

                    Dictionary <UInt256, Fixed8> balance = new Dictionary <UInt256, Fixed8>();
                    Dictionary <UInt256, Fixed8> fee     = new Dictionary <UInt256, Fixed8>();

                    for (int i = 0; i < tx.Outputs.Length; i++)
                    {
                        AssetState state = Blockchain.Default.GetAssetState(tx.Outputs[i].AssetId);
                        if (tx.Outputs[i].ScriptHash.Equals(to_script))
                        {
                            if (balance.ContainsKey(tx.Outputs[i].AssetId))
                            {
                                balance[tx.Outputs[i].AssetId] += tx.Outputs[i].Value;
                            }
                            else
                            {
                                balance[tx.Outputs[i].AssetId] = tx.Outputs[i].Value;
                            }
                        }

                        if (!fee.ContainsKey(tx.Outputs[i].AssetId))
                        {
                            if (tx.Outputs[i].Fee != Fixed8.Zero)
                            {
                                fee[tx.Outputs[i].AssetId] = tx.Outputs[i].Fee;
                            }
                        }
                    }
                    obj["asset"]  = Blockchain.UtilityToken.Name;
                    obj["amount"] = balance[Blockchain.UtilityToken.Hash].value.ToString();
                    obj["fee"]    = Fixed8.Zero.ToString();
                }
                else if (tx is InvocationTransaction)
                {
                    InvocationTransaction invocTx = (InvocationTransaction)tx;
                    try
                    {
                        foreach (CoinReference input in tx.Inputs)
                        {
                            from_script = tx.References[input].ScriptHash;
                        }
                    }
                    catch (Exception ex) { }
                    obj["asset"]  = Blockchain.UtilityToken.Name;
                    obj["amount"] = invocTx.Gas.ToString();
                    obj["fee"]    = Fixed8.Zero.ToString();
                }
                else if (tx is IssueTransaction)
                {
                    AssetState       state   = Blockchain.Default.GetAssetState(Blockchain.UtilityToken.Hash);
                    IssueTransaction issueTx = (IssueTransaction)tx;

                    try
                    {
                        foreach (CoinReference input in tx.Inputs)
                        {
                            from_script = tx.References[input].ScriptHash;
                        }
                    }
                    catch (Exception ex) { }

                    if (tx.Outputs.Length > 0)
                    {
                        to_script = tx.Outputs[0].ScriptHash;
                    }


                    if (tx.Outputs.Length > 0)
                    {
                        state = Blockchain.Default.GetAssetState(tx.Outputs[0].AssetId);
                    }

                    Fixed8 totalAmount = Fixed8.Zero;
                    foreach (TransactionOutput output in tx.Outputs)
                    {
                        if (output.AssetId != Blockchain.UtilityToken.Hash)
                        {
                            totalAmount += output.Value;
                        }
                    }

                    Fixed8 fee = issueTx.NetworkFee + issueTx.SystemFee;

                    obj["asset"]  = state.GetName();
                    obj["amount"] = totalAmount.ToString();
                    obj["fee"]    = fee.ToString();
                }

                if (!ScriptHash.Equals(from_script) && !ScriptHash.Equals(to_script))
                {
                    continue;
                }

                if (from_script != null)
                {
                    obj["from"] = Wallet.ToAddress(from_script);
                }
                else
                {
                    obj["from"] = "";
                }

                if (to_script != null)
                {
                    obj["to"] = Wallet.ToAddress(to_script);
                }
                else
                {
                    obj["to"] = "";
                }

                obj["txType"]      = tx.Type;
                obj["blockHeight"] = Fixed8.Zero.ToString();
                obj["txid"]        = tx.Hash.ToString();
                obj["timestamp"]   = DateTime.Now.ToTimestamp();
                obj["status"]      = 0;
                result.Add(obj);
            }
            return(result);
        }
Example #17
0
        private JObject InternalCall(string method, JArray _params)
        {
            switch (method)
            {
            case "getbalance":
                if (Program.Wallet == null)
                {
                    throw new RpcException(-400, "Access denied.");
                }
                else
                {
                    UInt256            assetId = UInt256.Parse(_params[0].AsString());
                    IEnumerable <Coin> coins   = Program.Wallet.FindCoins().Where(p => p.AssetId.Equals(assetId));
                    JObject            json    = new JObject();
                    json["balance"]   = coins.Where(p => p.State == CoinState.Unspent || p.State == CoinState.Unconfirmed).Sum(p => p.Value).ToString();
                    json["confirmed"] = coins.Where(p => p.State == CoinState.Unspent).Sum(p => p.Value).ToString();
                    return(json);
                }

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

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

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

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

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

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

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

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

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

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

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

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