예제 #1
0
 /// <summary>
 /// Inform this Controller that the output pipeline send output data "to the wire".
 /// </summary>
 /// <param name="device">ExternalDevice that output the data</param>
 /// <param name="outputTime">Approximate time the data was sent to the wire</param>
 /// <param name="duration">Duration of the data block send to the wire</param>
 /// <param name="configuration">Pipeline node configuration(s) for the output pipeline that processed the outgoing data</param>
 public virtual void DidOutputData(IExternalDevice device, DateTimeOffset outputTime, TimeSpan duration, IEnumerable <IPipelineNodeConfiguration> configuration)
 {
     //virtual for Moq
     if (CurrentEpoch != null && !CurrentEpoch.IsComplete)
     {
         CurrentEpoch.DidOutputData(device, outputTime, duration, configuration);
     }
 }
예제 #2
0
        /// <summary>
        /// Pulls IOutputData from the current Epoch destined for a given external deivce.
        /// Result will have duration greater than zero, but may not equal the requested duration.
        /// </summary>
        /// <param name="device">ExternalDevice for this outputdata</param>
        /// <param name="duration">Duration of the data requested</param>
        /// <returns>Output data for the requested device</returns>
        public virtual IOutputData PullOutputData(IExternalDevice device, TimeSpan duration)
        {
            if (CurrentEpoch == null)
            {
                return(null);
            }

            return(CurrentEpoch.PullOutputData(device, duration));
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }