public void TipShouldNotBecomeNewBlock()
 {
     block2 = _GenesisBlock.Child();
     block3 = block2.Child();
     Assert.That(HandleBlock(block3), Is.EqualTo(BlockVerificationHelper.BkResultEnum.AcceptedOrphan));
     Assert.That(_BlockChain.Tip.Value.Equals(block1), Is.True);
 }
예제 #2
0
 public new void OneTimeSetUp()
 {
     base.OneTimeSetUp();
     block1 = _GenesisBlock.Child().AddTx(tx).Tag("block1");
     block2 = _GenesisBlock.Child().AddTx(tx).Tag("block2");
     block3 = block2.Child().Tag("block3");
 }
예제 #3
0
        Types.Block Child(Types.Block bk, int addHours)
        {
            var nonce = new byte[10];

            new Random().NextBytes(nonce);
            //var nonce = new byte[] { };

            var timestamp = DateTime.Now.ToUniversalTime().AddHours(addHours).Ticks;

            var header = new Types.BlockHeader(
                0,
                Merkle.blockHeaderHasher.Invoke(bk.header),
                bk.header.blockNumber + 1,
                new byte[] { },
                new byte[] { },
                new byte[] { },
                ListModule.OfSeq <byte[]>(new List <byte[]>()),
                timestamp,
                0,
                nonce
                );

            var txs = new List <Types.Transaction>();

            txs.Add(Utils.GetTx());

            return(new Types.Block(header, ListModule.OfSeq(txs)));
        }
예제 #4
0
        void DispatchBlock()
        {
            try
            {
                _Hasher.Pause("dispatching block");

                MinerTrace.Information($"dispatching block with {_ValidatedTxs.Count()} txs");

                var txs = FSharpList <Types.Transaction> .Cons(_Coinbase, ListModule.OfSeq(_ValidatedTxs.Select(TransactionValidation.unpoint)));

                var block = new Types.Block(_Header, txs);


                var result = new HandleBlockAction(block).Publish().Result.BkResultEnum;

                if (result == BlockVerificationHelper.BkResultEnum.Accepted)
                {
                    if (OnMined != null)
                    {
                        OnMined(block);
                    }
                }
                else
                {
                    Reset();
                }

                MinerTrace.Information($"  block {block.header.blockNumber} is " + result);
            } catch (Exception e)
            {
                MinerTrace.Error("Dispatch block exception", e);
            }
        }
예제 #5
0
 /// <summary>
 /// Transmits a block on the network.
 /// </summary>
 public void Transmit(Types.Block bk)
 {
     if (_MinerBehavior != null)
     {
         _MinerBehavior.BroadcastBlock(bk);
     }
 }
예제 #6
0
        public static Types.Block Child(this Types.Block bk)
        {
            var nonce = new byte[10];

            new Random().NextBytes(nonce);
            //var nonce = new byte[] { };

            var header = new Types.BlockHeader(
                0,
                Merkle.blockHeaderHasher.Invoke(bk.header),
                bk.header.blockNumber + 1,
                new byte[] { },
                new byte[] { },
                new byte[] { },
                ListModule.OfSeq <byte[]>(new List <byte[]>()),
                DateTime.Now.ToUniversalTime().Ticks,
                0,
                nonce
                );

            var txs = new List <Types.Transaction>();

            txs.Add(Utils.GetCoinbaseTx(bk.header.blockNumber + 1));

            return(new Types.Block(header, ListModule.OfSeq(txs)));
        }
예제 #7
0
        public static Types.Block AddTx(this Types.Block bk, Types.Transaction tx)
        {
            //var nonce = new byte[10];
            //new Random().NextBytes(nonce);
            var nonce = new byte[] { };

            var header = new Types.BlockHeader(
                0,
                new byte[] { },
                bk.header.blockNumber + 1,
                new byte[] { },
                new byte[] { },
                new byte[] { },
                ListModule.OfSeq <byte[]>(new List <byte[]>()),
                DateTime.Now.ToUniversalTime().Ticks,
                0,
                nonce
                );

            var txs = bk.transactions.ToList();

            txs.Add(tx);

            return(new Types.Block(bk.header, ListModule.OfSeq <Types.Transaction>(txs)));
        }
예제 #8
0
        public void Put(
            TransactionContext transactionContext,
            byte[] BkHash,
            Types.Block block,
            LocationEnum location,
            double totalWork)
        {
            var txs = block.transactions.Select(t =>
            {
                return(new KeyValuePair <byte[], Types.Transaction>(Merkle.transactionHasher.Invoke(t), t));
            });

            Put(transactionContext, BkHash, new Block
            {
                BlockHeader = block.header,
                TxHashes    = txs.Select(t => t.Key).ToList()
            });

            //children
            var children = new HashSet <byte[]>();

            children.Add(BkHash);

            transactionContext.Transaction.InsertHashSet <byte[], byte[]>(
                CHILDREN,
                block.header.parent,
                children,
                0,
                false
                );

            //location
            transactionContext.Transaction.Insert <byte[], int>(LOCATIONS, BkHash, (int)location);

            //total work
            transactionContext.Transaction.Insert <byte[], double>(TOTAL_WORK, BkHash, totalWork);

            //transactions
            var isFirstTx = true;

            foreach (var tx in txs)
            {
                if (!TxStore.ContainsKey(transactionContext, tx.Key))
                {
                    TxStore.Put(transactionContext, tx.Key,
                                new Transaction {
                        Tx          = tx.Value,
                        InMainChain = false
                    });

                    if (isFirstTx)
                    {
                        transactionContext.Transaction.Insert <byte[], byte[]>(COINBASETX_BLOCK, tx.Key, BkHash);
                        isFirstTx = false;
                    }
                }
            }
        }
예제 #9
0
        internal void OnBlockBroadcasted(Types.Block tx)
        {
            var evt = BlockBroadcasted;

            if (evt != null)
            {
                evt(tx);
            }
        }
예제 #10
0
        internal void OnBlockRejected(Types.Block tx, RejectPayload reject)
        {
            var evt = BlockRejected;

            if (evt != null)
            {
                evt(tx, reject);
            }
        }
예제 #11
0
    public void OneTimeSetUp()
    {
        Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        Dispose();
        _GenesisBlock = Utils.GetGenesisBlock();

        _BlockChain    = new BlockChain.BlockChain(BLOCKCHAIN_DB, Merkle.blockHeaderHasher.Invoke(_GenesisBlock.header));
        _WalletManager = new WalletManager(_BlockChain, WALLET_DB);
    }
예제 #12
0
        public void TestCase()
        {
            Types.Block block = Util.GetBlock(null, 0);

            var data = Merkle.serialize <Types.Block>(block);

            Types.Block _block = Serialization.context.GetSerializer <Types.Block>().UnpackSingleObject(data);

            Assert.IsTrue(block.Equals(_block));
        }
예제 #13
0
        protected LocationEnum Location(Types.Block block)
        {
#if DEBUG
            return(new GetBlockLocationAction {
                Block = Merkle.blockHeaderHasher.Invoke(block.header)
            }.Publish().Result);
#else
            return(LocationEnum.Main);
#endif
        }
예제 #14
0
        void UndoBlock(Types.Block block, byte[] key)
        {
            BlockChainTrace.Information($"undoing block {block.header.blockNumber}", block);

            _BlockChain.BlockStore.SetLocation(_DbTx, key, LocationEnum.Branch);

            var blockUndoData = _BlockChain.BlockStore.GetUndoData(_DbTx, key);

            if (blockUndoData != null)
            {
                blockUndoData.AddedUTXO.ForEach(u =>
                {
                    BlockChainTrace.Information($"undo block {block.header.blockNumber}: utxo removed, amount {u.Item2.spend.amount}", block);
                    _BlockChain.UTXOStore.Remove(_DbTx, u.Item1.txHash, u.Item1.index);
                });

                blockUndoData.RemovedUTXO.ForEach(u =>
                {
                    BlockChainTrace.Information($"undo block {block.header.blockNumber}: new utxo, amount {u.Item2.spend.amount}", block);
                    _BlockChain.UTXOStore.Put(_DbTx, u.Item1.txHash, u.Item1.index, u.Item2);
                });

                foreach (var item in blockUndoData.ACSDeltas)
                {
                    if (item.Value.LastBlock.HasValue) // restore last block - undo extend
                    {
                        var current = new ActiveContractSet().Get(_DbTx, item.Key);

                        if (current != null)
                        {
                            current.Value.LastBlock = item.Value.LastBlock.Value;
                            _BlockChain.ActiveContractSet.Add(_DbTx, current.Value);
                        }
                        else
                        {
                            BlockChainTrace.Error("missing ACS item!", new Exception());
                        }
                    }
                    else if (item.Value.ACSItem != null) // restore entire item - undo expire
                    {
                        _BlockChain.ActiveContractSet.Add(_DbTx, item.Value.ACSItem);
                    }
                    else // remove item - undo activate
                    {
                        _BlockChain.ActiveContractSet.Remove(_DbTx, item.Key);
                    }
                }
            }

            block.transactions.ToList().ForEach(tx =>
            {
                var txHash             = Merkle.transactionHasher.Invoke(tx);
                UnconfirmedTxs[txHash] = tx;
            });
        }
예제 #15
0
        public void OneTimeSetUp()
        {
            Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Dispose();

            _TxMessagesListenerScope = MessageProducer <BlockChainMessage> .Instance.AddMessageListener(
                new MessageListener <BlockChainMessage>(OnBlockChainMessage));

            _GenesisBlock     = new GenesisBlock().Block;
            _GenesisBlockHash = Merkle.blockHeaderHasher.Invoke(_GenesisBlock.header);
            _BlockChain       = new BlockChain(DB, _GenesisBlockHash);
        }
예제 #16
0
        internal void OnBroadcastBlock(Types.Block block)
        {
            var nodes = Nodes
                        .Select(n => n.Key.Behaviors.Find <MinerBehavior>())
                        .Where(n => n != null)
                        .ToArray();

            foreach (var node in nodes)
            {
                node.BroadcastBlockCore(block);
            }
        }
예제 #17
0
        public static Types.Block GetBlock(Types.Block parent, Double difficulty)
        {
            UInt32 pdiff = Convert.ToUInt32(difficulty);

            byte[] parentKey = parent == null ? new byte[] {} : Merkle.blockHeaderHasher.Invoke(parent.header);

            Types.BlockHeader newBlockHeader = new Types.BlockHeader(1, parentKey, 0, new byte[] { }, new byte[] { }, new byte[] { }, ListModule.OfSeq(new List <byte[]>()), 0, pdiff, null);
            var transactions = new List <Types.Transaction>();
            FSharpList <Types.Transaction> newBlockTransactions = ListModule.OfSeq(transactions);

            Types.Block newBlock = new Types.Block(newBlockHeader, newBlockTransactions);

            return(newBlock);
        }
예제 #18
0
 //demo
 private byte[] GetHash(Types.Block block)
 {
     try
     {
         //	if (block.Block != null)
         return(Merkle.blockHeaderHasher.Invoke(block.header));
         //	else
         //		return Merkle.blockHasher.Invoke(block.Block);
     }
     catch (Exception e)
     {
         Console.WriteLine(e.Message);
         return(null);
     }
 }
        public new void OneTimeSetUp()
        {
            base.OneTimeSetUp();

            block1_tx = Utils.GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Tag("block1_tx");
            block2_tx = Utils.GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Tag("block2_tx");
            block3_tx = Utils.GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Tag("block3_tx");
            block4_tx = Utils.GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Tag("block4_tx");
            block5_tx = Utils.GetTx().AddOutput(Key.Create().Address, Consensus.Tests.zhash, 1).Tag("block5_tx");

            block1 = _GenesisBlock.Child().AddTx(block1_tx).Tag("block1");
            block2 = _GenesisBlock.Child().AddTx(block2_tx).Tag("block2");
            block3 = block2.Child().AddTx(block3_tx).Tag("block3");
            block4 = block1.Child().AddTx(block4_tx).Tag("block4");
            block5 = block4.Child().AddTx(block5_tx).Tag("block5");
        }
예제 #20
0
        internal void BroadcastBlockCore(Types.Block block)
        {
            if (block == null)
            {
                throw new ArgumentNullException("block");
            }
            var tx = new BlockBroadcast();

            tx.Block = block;
            tx.State = BroadcastState.NotSent;
            var hash = GetHash(block);

            if (_HashToBlock.TryAdd(hash, tx))
            {
                Announce(tx, hash);
            }
        }
예제 #21
0
        public Keyed <Types.Block> GetBlock(TransactionContext transactionContext, byte[] key)
        {
            var _block = Get(transactionContext, key);

            if (_block == null)
            {
                BlockChainTrace.Information("Block not found: " + Convert.ToBase64String(key));
                return(null);
            }
            else
            {
                var txs = _block.Value.TxHashes.Select(t => TxStore.Get(transactionContext, t).Value).ToList();

                var block = new Types.Block(_block.Value.BlockHeader, ListModule.OfSeq <Types.Transaction>(txs.Select(t => t.Tx)));

                return(new Keyed <Types.Block>(key, block));
            }
        }
예제 #22
0
        public void Render()
        {
            if (Value != null)
            {
                return;
            }

            var parentKey = new byte[] { };

            if (Parent != null)
            {
                Parent.Render();
                parentKey = Parent.Value.Key;
            }

            uint   version = 1;
            string date    = "2000-02-02";

            var blockHeader = new Types.BlockHeader(
                version,
                parentKey,
                0,
                new byte[] { },
                new byte[] { },
                new byte[] { },
                ListModule.OfSeq <byte[]>(new List <byte[]>()),
                DateTime.Parse(date).ToBinary(),
                1,
                new byte[] { }
                );

            //_TestTransactionPool.Render();

            //var block = new Types.Block(blockHeader, ListModule.OfSeq<Types.Transaction>(_TestTransactionPool.Values.Select(t => t.Value.Value)));
            var block = new Types.Block(blockHeader, ListModule.OfSeq <Types.Transaction>(_Transactions));

//			byte[] key = Merkle.blockHasher.Invoke(block);
            byte[] key = Merkle.blockHeaderHasher.Invoke(block.header);

            Value = new Keyed <Types.Block>(key, block);

            TestTrace.Transaction(Tag, key);
        }
예제 #23
0
        /// <summary>
        /// Broadcast a block on the hub
        /// </summary>
        /// <param name="block">The block to broadcast</param>
        /// <returns>The cause of the rejection or null</returns>
        public Task <RejectPayload> BroadcastBlockAsync(Types.Block block)
        {
            if (block == null)
            {
                throw new ArgumentNullException("block");
            }

            TaskCompletionSource <RejectPayload> completion = new TaskCompletionSource <RejectPayload>();
            var hash = GetHash(block);

            if (BroadcastedBlock.TryAdd(hash, block))
            {
                BlockBroadcastedDelegate broadcasted = null;
                BlockRejectedDelegate    rejected    = null;
                broadcasted = (t) =>
                {
                    if (GetHash(t) == hash)
                    {
                        completion.SetResult(null);
                        BlockRejected    -= rejected;
                        BlockBroadcasted -= broadcasted;
                    }
                };
                BlockBroadcasted += broadcasted;
                rejected          = (t, r) =>
                {
                    if (r.Hash == hash)
                    {
                        completion.SetResult(r);
                        BlockRejected    -= rejected;
                        BlockBroadcasted -= broadcasted;
                    }
                };
                BlockRejected += rejected;
                OnBroadcastBlock(block);
            }
            return(completion.Task);
        }
예제 #24
0
        public GenesisBlock()
        {
            Keys        = new Key[10];
            CoinbaseKey = Key.Create();

            for (int i = 0; i < 10; i++)
            {
                Keys[i] = Key.Create();
            }

            var nonce = new byte[10];

            new Random().NextBytes(nonce);

            var header = new Types.BlockHeader(
                0,
                new byte[] { },
                0,
                new byte[] { },
                new byte[] { },
                new byte[] { },
                ListModule.OfSeq <byte[]>(new List <byte[]>()),
                DateTime.Now.ToUniversalTime().Ticks,
                0,
                nonce
                );

            var txs = new List <Types.Transaction>();

            txs.Add(Utils.GetCoinbaseTx(0));

            for (int i = 0; i < 10; i++)
            {
                txs.Add(Utils.GetTx().AddOutput(Keys[i].Address, Consensus.Tests.zhash, (ulong)i * 1111));
            }

            Block = new Types.Block(header, ListModule.OfSeq(txs));
        }
예제 #25
0
        private Tuple <bool, IList <string> > TryUploadBlock(int index,
                                                             string minedBy,
                                                             string data,
                                                             string previousHash,
                                                             int nonce,
                                                             string hash)
        {
            var lastBlock = _repository.TryGetLastBlock();

            if (lastBlock == null)
            {
                throw new ApplicationException("No blocks in blockchain");
            }

            Types.Block block = new Types.Block(
                index,
                minedBy,
                data,
                previousHash,
                nonce);

            var blockWithHash = new Types.BlockWithHash(block, hash);
            var isValidBlock  = Miner.isValidBlock(blockWithHash, DtoHelpers.DtoToBlock(lastBlock));

            if (isValidBlock.IsInvalid)
            {
                var invalid = isValidBlock as Types.IsValidBlock.Invalid;
                var errors  = invalid.Item.ToList();

                return(Tuple.Create <bool, IList <string> >(false, errors));
            }

            _repository.Save(DtoHelpers.BlockToDto(blockWithHash));

            return(Tuple.Create <bool, IList <string> >(true, new List <string>()));
        }
예제 #26
0
        public BlockVerificationHelper(
            BlockChain blockChain,
            TransactionContext dbTx,
            byte[] bkHash,
            Types.Block bk,
            bool handleOrphan = false,
            bool handleBranch = false,
            HashDictionary <TransactionValidation.PointedTransaction> confirmedTxs = null,
            HashDictionary <Types.Transaction> invalidatedTxs = null,
            List <QueueAction> queuedActions = null
            )
        {
            ConfirmedTxs   = confirmedTxs ?? new HashDictionary <TransactionValidation.PointedTransaction>();
            UnconfirmedTxs = invalidatedTxs ?? new HashDictionary <Types.Transaction>();            //todo: refactor to set as new obj by default
            QueueActions   = queuedActions ?? new List <QueueAction>();

            _BlockChain = blockChain;
            _DbTx       = dbTx;
            _BkHash     = bkHash;
            _Bk         = bk;

            if (!IsValid())
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} is invalid", _Bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            if (IsInStore())
            {
                var    reject        = false;
                byte[] missingParent = null;
                var    location      = blockChain.BlockStore.GetLocation(dbTx, bkHash);

                switch (location)
                {
                case LocationEnum.Branch:
                    reject = !handleBranch;
                    break;

                case LocationEnum.Orphans:
                    missingParent = GetMissingParent();

                    reject = !handleOrphan && !handleBranch;
                    break;

                default:
                    reject = true;
                    break;
                }

                if (reject)
                {
                    BlockChainTrace.Information($"Block {_Bk.header.blockNumber} already in store ({location})", bk);
                    Result = new BkResult(BkResultEnum.Rejected, missingParent);
                    return;
                }
            }

            if (bk.transactions.Count() == 0)
            {
                BlockChainTrace.Information("empty tx list", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            if (!IsValidTime())
            {
                BlockChainTrace.Information("invalid time", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            //TODO:

            /*
             * 3. Transaction list must be non - empty
             * 4. Block hash must satisfy claimed nBits proof of work
             * 5. Block timestamp must not be more than two hours in the future
             * 6. First transaction must be coinbase, the rest must not be
             * 7. For each transaction, apply "tx" checks 2 - 4
             * 8. (omitted)
             * 9. (omitted)
             * 10. Verify Merkle hash
             */

            if (IsGenesis())
            {
                if (!IsGenesisValid())
                {
                    BlockChainTrace.Information("invalid genesis block", bk);
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
                else
                {
                    blockChain.Timestamps.Init(bk.header.timestamp);
                    ExtendMain(QueueActions, 0, true);
                    Result = new BkResult(BkResultEnum.Accepted);
                    BlockChainTrace.Information("accepted genesis block", bk);
                    return;
                }
            }

            if (IsOrphan())
            {
                var missingParent = GetMissingParent();
                blockChain.BlockStore.Put(dbTx, bkHash, bk, LocationEnum.Orphans, 0);
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} added as orphan", bk);
                Result = new BkResult(BkResultEnum.AcceptedOrphan, missingParent);
                return;
            }

            //12. Check that nBits value matches the difficulty rules

            if (!IsValidDifficulty() || !IsValidBlockNumber() || !IsValidTimeStamp())
            {
                BlockChainTrace.Information($"block {_Bk.header.blockNumber} rejected", bk);
                Result = new BkResult(BkResultEnum.Rejected);
                return;
            }

            //14. For certain old blocks(i.e.on initial block download) check that hash matches known values

            var totalWork = TotalWork();

            UtxoLookup = _BlockChain.UtxoLookupFactory(_DbTx, true);


            if (handleBranch)             // make a branch block main
            {
                if (!ExtendMain(QueueActions, totalWork))
                {
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
            }
            else if (!IsNewGreatestWork(totalWork))
            {
                blockChain.BlockStore.Put(dbTx, bkHash, bk, LocationEnum.Branch, totalWork);
            }
            else if (blockChain.BlockStore.IsLocation(dbTx, bk.header.parent, LocationEnum.Main))
            {
                if (!ExtendMain(QueueActions, totalWork))
                {
                    BlockChainTrace.Information($"block {_Bk.header.blockNumber} rejected", bk);
                    Result = new BkResult(BkResultEnum.Rejected);
                    return;
                }
            }
            else
            {
                BlockChainTrace.Information($"block {bk.header.blockNumber} extends a branch with new difficulty", bk);

                Reorg();
            }

            BlockChainTrace.Information($"block {bk.header.blockNumber} accepted", bk);
            Result = new BkResult(BkResultEnum.Accepted);
        }
예제 #27
0
 public HandleBlockAction(Types.Block bk)
 {
     BkHash   = Merkle.blockHeaderHasher.Invoke(bk.header);
     Bk       = bk;
     IsOrphan = false;
 }
예제 #28
0
 public HandleBlockAction(byte[] bkHash, Types.Block bk, bool isOrphan)
 {
     BkHash   = bkHash;
     Bk       = bk;
     IsOrphan = isOrphan;
 }
 public void TipShouldBeOfNewBlock()
 {
     block1 = _GenesisBlock.Child();
     Assert.That(HandleBlock(block1), Is.EqualTo(BlockVerificationHelper.BkResultEnum.Accepted));
     Assert.That(_BlockChain.Tip.Value, Is.EqualTo(block1));
 }
예제 #30
0
 public static Types.Block Tag(this Types.Block block, string value)
 {
     BlockChainTrace.SetTag(block, value);
     return(block);
 }