public void AddBlock(Block block, IEnumerable <Transaction> transactions, OracleReaderDelegate oracleReader) { /*if (CurrentEpoch != null && CurrentEpoch.IsSlashed(Timestamp.Now)) * { * return false; * }*/ if (LastBlock != null) { if (LastBlock.Height != block.Height - 1) { throw new BlockGenerationException($"height of block should be {LastBlock.Height + 1}"); } if (block.PreviousHash != LastBlock.Hash) { throw new BlockGenerationException($"previous hash should be {LastBlock.PreviousHash}"); } } var inputHashes = new HashSet <Hash>(transactions.Select(x => x.Hash)); foreach (var hash in block.TransactionHashes) { if (!inputHashes.Contains(hash)) { throw new BlockGenerationException($"missing in inputs transaction with hash {hash}"); } } var outputHashes = new HashSet <Hash>(block.TransactionHashes); foreach (var tx in transactions) { if (!outputHashes.Contains(tx.Hash)) { throw new BlockGenerationException($"missing in outputs transaction with hash {tx.Hash}"); } } foreach (var tx in transactions) { if (!tx.IsValid(this)) { throw new InvalidTransactionException(tx.Hash, $"invalid transaction with hash {tx.Hash}"); } } var changeSet = new StorageChangeSetContext(this.Storage); foreach (var tx in transactions) { byte[] result; if (tx.Execute(this, block, changeSet, block.Notify, oracleReader, out result)) { if (result != null) { block.SetResultForHash(tx.Hash, result); } } else { throw new InvalidTransactionException(tx.Hash, $"transaction execution failed with hash {tx.Hash}"); } } // from here on, the block is accepted _blockHeightMap[block.Height] = block; _blocks[block.Hash] = block; _blockChangeSets[block.Hash] = changeSet; changeSet.Execute(); if (CurrentEpoch == null) { GenerateEpoch(); } CurrentEpoch.AddBlockHash(block.Hash); CurrentEpoch.UpdateHash(); LastBlock = block; foreach (Transaction tx in transactions) { _transactions[tx.Hash] = tx; _transactionBlockMap[tx.Hash] = block.Hash; } Nexus.PluginTriggerBlock(this, block); }
internal bool Execute(Chain chain, Block block, StorageChangeSetContext changeSet, Action <Hash, Event> onNotify, OracleReaderDelegate oracleReader, out byte[] result) { result = null; var runtime = new RuntimeVM(this.Script, chain, block, this, changeSet, false); runtime.OracleReader = oracleReader; var state = runtime.Execute(); if (state != ExecutionState.Halt) { return(false); } var cost = runtime.UsedGas; // fee distribution TODO // if (chain.NativeTokenAddress != null && cost > 0) { //chain.TransferToken(this.PublicKey, chain.DistributionPubKey, cost); } foreach (var evt in runtime.Events) { onNotify(this.Hash, evt); } if (runtime.Stack.Count > 0) { var obj = runtime.Stack.Pop(); result = Serialization.Serialize(obj); } return(true); }
internal bool Execute(Chain chain, Block block, StorageChangeSetContext changeSet, Action <Hash, Event> onNotify, OracleReaderDelegate oracleReader, out byte[] result) { result = null; var runtime = new RuntimeVM(this.Script, chain, block, this, changeSet, false); runtime.ThrowOnFault = true; runtime.OracleReader = oracleReader; var state = runtime.Execute(); if (state != ExecutionState.Halt) { return(false); } var cost = runtime.UsedGas; foreach (var evt in runtime.Events) { onNotify(this.Hash, evt); } if (runtime.Stack.Count > 0) { var obj = runtime.Stack.Pop(); result = Serialization.Serialize(obj); } return(true); }
public void AddBlock(Block block, IEnumerable <Transaction> transactions, OracleReaderDelegate oracleReader) { /*if (CurrentEpoch != null && CurrentEpoch.IsSlashed(Timestamp.Now)) * { * return false; * }*/ if (LastBlock != null) { if (LastBlock.Height != block.Height - 1) { throw new BlockGenerationException($"height of block should be {LastBlock.Height + 1}"); } if (block.PreviousHash != LastBlock.Hash) { throw new BlockGenerationException($"previous hash should be {LastBlock.PreviousHash}"); } } var inputHashes = new HashSet <Hash>(transactions.Select(x => x.Hash)); foreach (var hash in block.TransactionHashes) { if (!inputHashes.Contains(hash)) { throw new BlockGenerationException($"missing in inputs transaction with hash {hash}"); } } var outputHashes = new HashSet <Hash>(block.TransactionHashes); foreach (var tx in transactions) { if (!outputHashes.Contains(tx.Hash)) { throw new BlockGenerationException($"missing in outputs transaction with hash {tx.Hash}"); } } foreach (var tx in transactions) { if (!tx.IsValid(this)) { throw new InvalidTransactionException(tx.Hash, $"invalid transaction with hash {tx.Hash}"); } } var changeSet = new StorageChangeSetContext(this.Storage); foreach (var tx in transactions) { byte[] result; try { if (tx.Execute(this, block, changeSet, block.Notify, oracleReader, out result)) { if (result != null) { block.SetResultForHash(tx.Hash, result); } } else { throw new InvalidTransactionException(tx.Hash, $"execution failed"); } } catch (Exception e) { if (e.InnerException != null) { e = e.InnerException; } throw new InvalidTransactionException(tx.Hash, e.Message); } } // from here on, the block is accepted _blockHeightMap[block.Height] = block; _blocks[block.Hash] = block; _blockChangeSets[block.Hash] = changeSet; changeSet.Execute(); if (CurrentEpoch == null) { GenerateEpoch(); } CurrentEpoch.AddBlockHash(block.Hash); CurrentEpoch.UpdateHash(); Dictionary <string, BigInteger> synchMap = null; foreach (Transaction tx in transactions) { _transactions[tx.Hash] = tx; _transactionBlockMap[tx.Hash] = block.Hash; var evts = block.GetEventsForTransaction(tx.Hash); foreach (var evt in evts) { if (evt.Kind == EventKind.TokenMint || evt.Kind == EventKind.TokenBurn || evt.Kind == EventKind.TokenReceive || evt.Kind == EventKind.TokenSend) { if (synchMap == null) { synchMap = new Dictionary <string, BigInteger>(); var eventData = evt.GetContent <TokenEventData>(); var balance = synchMap.ContainsKey(eventData.symbol) ? synchMap[eventData.symbol] : 0; if (evt.Kind == EventKind.TokenBurn || evt.Kind == EventKind.TokenSend) { balance -= eventData.value; } else { balance += eventData.value; } synchMap[eventData.symbol] = balance; } } } } if (synchMap != null) { SynchronizeSupplies(synchMap); } Nexus.PluginTriggerBlock(this, block); }