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