Ejemplo n.º 1
0
        public void TestDBChangeSetStorageMapClear()
        {
            var storage   = new KeyStoreStorage(CreateKeyStoreAdapterTest("test2"));
            var changeSet = new StorageChangeSetContext(storage);

            var testMapKey  = Encoding.UTF8.GetBytes($".test._valueMap");
            var testMapKey2 = Encoding.UTF8.GetBytes($".test2._valueMap");

            var testMap  = new StorageMap(testMapKey, changeSet);
            var testMap2 = new StorageMap(testMapKey2, changeSet);

            testMap.Set("test1", "Value1");
            testMap.Set("test2", "Value2");
            testMap.Set("test3", "Value3");
            testMap.Set("test4", "Value4");
            Assert.IsTrue(testMap.Count() == 4);

            testMap2.Set <BigInteger, string>(new BigInteger(1), "Value21");
            testMap2.Set <BigInteger, string>(new BigInteger(2), "Value22");
            testMap2.Set <BigInteger, string>(new BigInteger(3), "Value23");
            testMap2.Set <BigInteger, string>(new BigInteger(4), "Value24");
            Assert.IsTrue(testMap2.Count() == 4);

            changeSet.Execute();
            var count = 0;

            testMap.Visit <string, string>((key, value) => {
                count++;
            });

            testMap2.Visit <BigInteger, string>((key, value) => {
                count++;
            });

            Console.WriteLine($"visit: {count} count: {(int)testMap.Count() + testMap2.Count()}");
            Assert.AreEqual(count, (int)testMap.Count() + testMap2.Count());

            testMap.Clear();
            testMap2.Clear();

            Assert.IsTrue(testMap.Count() == 0);
            Assert.IsTrue(testMap2.Count() == 0);

            Assert.IsNull(testMap.Get <string, string>("test1"));
            Assert.IsNull(testMap.Get <string, string>("test2"));
            Assert.IsNull(testMap.Get <string, string>("test3"));
            Assert.IsNull(testMap.Get <string, string>("test4"));

            Assert.IsNull(testMap2.Get <BigInteger, string>(new BigInteger(1)));
            Assert.IsNull(testMap2.Get <BigInteger, string>(new BigInteger(2)));
            Assert.IsNull(testMap2.Get <BigInteger, string>(new BigInteger(3)));
            Assert.IsNull(testMap2.Get <BigInteger, string>(new BigInteger(4)));
        }
Ejemplo n.º 2
0
        // TODO This test fails sometimes on first "Assert.IsTrue(testMap.Count() == 0);" check.
        // Looks like it's random and related to tests execution order.
        // Calling TestDBChangeSetStorageMapClear() test before this test makes it complete successfully.
        // Changing "test2" to other unique key also helps.
        public void TestDBChangeSetStorageMapClearEmpty()
        {
            var storage    = (StorageContext) new KeyStoreStorage(CreateKeyStoreAdapterTest("test2"));
            var changeSet  = new StorageChangeSetContext(storage);
            var testMapKey = Encoding.UTF8.GetBytes($".test._valueMap");
            var testMap    = new StorageMap(testMapKey, changeSet);

            changeSet.Execute();
            Assert.IsTrue(testMap.Count() == 0);
            testMap.Clear();
            Assert.IsTrue(testMap.Count() == 0);
        }
Ejemplo n.º 3
0
        public void AddBlock(Block block, IEnumerable <Transaction> transactions, BigInteger minimumFee)
        {
            /*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);

            var oracle = Nexus.CreateOracleReader();

            foreach (var tx in transactions)
            {
                byte[] result;
                try
                {
                    if (tx.Execute(this, block.Timestamp, changeSet, block.Notify, oracle, minimumFee, 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);
                }
            }

            block.MergeOracle(oracle);

            // from here on, the block is accepted
            _blockHeightMap[block.Height] = block.Hash;
            _blocks[block.Hash]           = block;
            _blockChangeSets[block.Hash]  = changeSet;

            changeSet.Execute();

            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)
                    {
                        var eventData = evt.GetContent <TokenEventData>();
                        var token     = Nexus.GetTokenInfo(eventData.symbol);

                        if (!token.IsFungible)
                        {
                            // TODO support this
                            continue;
                        }

                        if (token.IsCapped)
                        {
                            BigInteger balance;

                            if (synchMap == null)
                            {
                                synchMap = new Dictionary <string, BigInteger>();
                                balance  = 0;
                            }
                            else
                            {
                                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);
            }

            var blockValidator = GetValidatorForBlock(block);

            if (blockValidator.IsNull)
            {
                throw new BlockGenerationException("no validator for this block");
            }

            Nexus.PluginTriggerBlock(this, block);
        }
Ejemplo n.º 4
0
        public void AddBlock(Block block, IEnumerable <Transaction> transactions, BigInteger minimumFee, StorageChangeSetContext changeSet)
        {
            if (!block.IsSigned)
            {
                throw new BlockGenerationException($"block must be signed");
            }

            var unsignedBytes = block.ToByteArray(false);

            if (!block.Signature.Verify(unsignedBytes, block.Validator))
            {
                throw new BlockGenerationException($"block signature does not match validator {block.Validator.Text}");
            }

            var hashList            = new StorageList(BlockHeightListTag, this.Storage);
            var expectedBlockHeight = hashList.Count() + 1;

            if (expectedBlockHeight != block.Height)
            {
                throw new ChainException("unexpected block height");
            }

            // from here on, the block is accepted
            using (var m = new ProfileMarker("changeSet.Execute"))
                changeSet.Execute();

            hashList.Add <Hash>(block.Hash);

            using (var m = new ProfileMarker("Compress"))
            {
                var blockMap   = new StorageMap(BlockHashMapTag, this.Storage);
                var blockBytes = block.ToByteArray(true);
                blockBytes = CompressionUtils.Compress(blockBytes);
                blockMap.Set <Hash, byte[]>(block.Hash, blockBytes);

                var txMap      = new StorageMap(TransactionHashMapTag, this.Storage);
                var txBlockMap = new StorageMap(TxBlockHashMapTag, this.Storage);
                foreach (Transaction tx in transactions)
                {
                    var txBytes = tx.ToByteArray(true);
                    txBytes = CompressionUtils.Compress(txBytes);
                    txMap.Set <Hash, byte[]>(tx.Hash, txBytes);
                    txBlockMap.Set <Hash, Hash>(tx.Hash, block.Hash);
                }
            }

            using (var m = new ProfileMarker("AddressBlockHashMapTag"))
                foreach (var transaction in transactions)
                {
                    var addresses = new HashSet <Address>();
                    var events    = block.GetEventsForTransaction(transaction.Hash);

                    foreach (var evt in events)
                    {
                        if (evt.Address.IsSystem)
                        {
                            continue;
                        }

                        addresses.Add(evt.Address);
                    }

                    var addressTxMap = new StorageMap(AddressBlockHashMapTag, this.Storage);
                    foreach (var address in addresses)
                    {
                        var addressList = addressTxMap.Get <Address, StorageList>(address);
                        addressList.Add <Hash>(transaction.Hash);
                    }
                }

            using (var m = new ProfileMarker("Nexus.PluginTriggerBlock"))
                Nexus.PluginTriggerBlock(this, block);
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
        public void AddBlock(Block block, IEnumerable <Transaction> transactions, BigInteger minimumFee)
        {
            /*if (CurrentEpoch != null && CurrentEpoch.IsSlashed(Timestamp.Now))
             * {
             *  return false;
             * }*/

            var lastBlockHash = GetLastBlockHash();
            var lastBlock     = GetBlockByHash(lastBlockHash);

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

            // TODO avoid fetching this every time
            var expectedProtocol = Nexus.GetGovernanceValue(Nexus.RootStorage, Nexus.NexusProtocolVersionTag);

            if (block.Protocol != expectedProtocol)
            {
                throw new BlockGenerationException($"invalid protocol number {block.Protocol}, expected protocol {expectedProtocol}");
            }

            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);

            var oracle = Nexus.CreateOracleReader();

            foreach (var tx in transactions)
            {
                byte[] result;
                try
                {
                    if (ExecuteTransaction(tx, block.Timestamp, changeSet, block.Notify, oracle, minimumFee, 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);
                }
            }

            block.MergeOracle(oracle);

            var hashList            = new StorageList(BlockHeightListTag, this.Storage);
            var expectedBlockHeight = hashList.Count() + 1;

            if (expectedBlockHeight != block.Height)
            {
                throw new ChainException("unexpected block height");
            }

            // from here on, the block is accepted
            changeSet.Execute();

            hashList.Add <Hash>(block.Hash);

            var blockMap = new StorageMap(BlockHashMapTag, this.Storage);

            blockMap.Set <Hash, Block>(block.Hash, block);

            var txMap      = new StorageMap(TransactionHashMapTag, this.Storage);
            var txBlockMap = new StorageMap(TxBlockHashMapTag, this.Storage);

            foreach (Transaction tx in transactions)
            {
                txMap.Set <Hash, Transaction>(tx.Hash, tx);
                txBlockMap.Set <Hash, Hash>(tx.Hash, block.Hash);
            }

            var blockValidator = GetValidatorForBlock(block);

            if (blockValidator.IsNull)
            {
                throw new BlockGenerationException("no validator for this block");
            }

            Nexus.PluginTriggerBlock(this, block);
        }