コード例 #1
0
        public async Task FinalizedHeightCantBeDecreasedAsync()
        {
            string dir = CreateTestDir(this);

            using (var repo = new ChainRepository(dir, new LoggerFactory()))
            {
                await repo.SaveFinalizedBlockHeightAsync(777);

                await repo.SaveFinalizedBlockHeightAsync(555);

                Assert.Equal(777, repo.GetFinalizedBlockHeight());
            }

            using (var repo = new ChainRepository(dir, new LoggerFactory()))
            {
                await repo.LoadFinalizedBlockHeightAsync();

                Assert.Equal(777, repo.GetFinalizedBlockHeight());
            }
        }
コード例 #2
0
 public void CanSaveChainIncrementally()
 {
     using (var repo = new ChainRepository(TestBase.CreateTestDir(this), this.loggerFactory))
     {
         var chain = new ConcurrentChain(Network.RegTest);
         repo.LoadAsync(chain).GetAwaiter().GetResult();
         Assert.True(chain.Tip == chain.Genesis);
         chain = new ConcurrentChain(Network.RegTest);
         ChainedHeader tip = this.AppendBlock(chain);
         repo.SaveAsync(chain).GetAwaiter().GetResult();
         var newChain = new ConcurrentChain(Network.RegTest);
         repo.LoadAsync(newChain).GetAwaiter().GetResult();
         Assert.Equal(tip, newChain.Tip);
         tip = this.AppendBlock(chain);
         repo.SaveAsync(chain).GetAwaiter().GetResult();
         newChain = new ConcurrentChain(Network.RegTest);
         repo.LoadAsync(newChain).GetAwaiter().GetResult();
         Assert.Equal(tip, newChain.Tip);
     }
 }
コード例 #3
0
        public async Task FinalizedHeightCantBeDecreasedAsync()
        {
            string dir = CreateTestDir(this);

            using (var repo = new ChainRepository(dir, new LoggerFactory()))
            {
                await repo.SaveFinalizedBlockHashAndHeightAsync(uint256.One, 777);

                await repo.SaveFinalizedBlockHashAndHeightAsync(uint256.One, 555);

                Assert.Equal(777, repo.GetFinalizedBlockInfo().Height);
            }

            using (var repo = new ChainRepository(dir, new LoggerFactory()))
            {
                await repo.LoadFinalizedBlockInfoAsync(new StratisMain());

                Assert.Equal(777, repo.GetFinalizedBlockInfo().Height);
            }
        }
コード例 #4
0
        public void LoadChainFromDisk()
        {
            string        dir   = CreateTestDir(this);
            var           chain = new ChainIndexer(KnownNetworks.StraxRegTest);
            ChainedHeader tip   = this.AppendBlock(chain);

            using (var engine = new DB(new Options {
                CreateIfMissing = true
            }, new DataFolder(dir).ChainPath))
            {
                using (var batch = new WriteBatch())
                {
                    ChainedHeader toSave = tip;
                    var           blocks = new List <ChainedHeader>();
                    while (toSave != null)
                    {
                        blocks.Insert(0, toSave);
                        toSave = toSave.Previous;
                    }

                    foreach (ChainedHeader block in blocks)
                    {
                        batch.Put(1, BitConverter.GetBytes(block.Height),
                                  new ChainRepository.ChainRepositoryData()
                        {
                            Hash = block.HashBlock, Work = block.ChainWorkBytes
                        }
                                  .ToBytes(this.Network.Consensus.ConsensusFactory));
                    }

                    engine.Write(batch);
                }
            }

            using (var repo = new ChainRepository(new LevelDbChainStore(chain.Network, new DataFolder(dir), chain)))
            {
                var testChain = new ChainIndexer(KnownNetworks.StraxRegTest);
                testChain.SetTip(repo.LoadAsync(testChain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, testChain.Tip);
            }
        }
コード例 #5
0
        public void CanSaveChainIncrementally()
        {
            using (var repo = new ChainRepository(TestBase.CreateTestDir(this), this.loggerFactory, this.dBreezeSerializer))
            {
                var chain = new ChainIndexer(this.regTest);

                chain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.True(chain.Tip == chain.Genesis);
                chain = new ChainIndexer(this.regTest);
                ChainedHeader tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                var newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
                tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
            }
        }
コード例 #6
0
        public void CanSaveChainIncrementally()
        {
            var chain = new ChainIndexer(this.regTest);
            var data  = new DataFolder(TestBase.CreateTestDir(this));

            using (var repo = new ChainRepository(new LevelDbChainStore(this.network, data, chain)))
            {
                chain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.True(chain.Tip == chain.Genesis);
                chain = new ChainIndexer(this.regTest);
                ChainedHeader tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                var newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
                tip = this.AppendBlock(chain);
                repo.SaveAsync(chain).GetAwaiter().GetResult();
                newChain = new ChainIndexer(this.regTest);
                newChain.SetTip(repo.LoadAsync(chain.Genesis).GetAwaiter().GetResult());
                Assert.Equal(tip, newChain.Tip);
            }
        }
コード例 #7
0
        public void SaveChainToDisk()
        {
            string dir   = CreateTestDir(this);
            var    chain = new ChainIndexer(this.Network);

            this.AppendBlock(chain);

            using (var repo = new ChainRepository(new RocksDbChainStore(chain.Network, new DataFolder(dir), chain)))
            {
                repo.SaveAsync(chain).GetAwaiter().GetResult();
            }

            using (var engine = RocksDb.Open(new DbOptions().SetCreateIfMissing(), new DataFolder(dir).ChainPath))
            {
                ChainedHeader tip = null;
                var           itr = engine.NewIterator();
                itr.SeekToFirst();
                while (itr.Valid())
                {
                    if (itr.Key()[0] == 1)
                    {
                        var data = new ChainRepository.ChainRepositoryData();
                        data.FromBytes(itr.Value().ToArray(), this.Network.Consensus.ConsensusFactory);

                        tip = new ChainedHeader(data.Hash, data.Work, tip);

                        if (tip.Height == 0)
                        {
                            tip.SetChainStore(new ChainStore());
                        }
                    }

                    itr.Next();
                }

                Assert.Equal(tip, chain.Tip);
            }
        }
コード例 #8
0
 public void CanSaveChainIncrementally()
 {
     using (var dir = TestDirectory.Create())
     {
         using (var repo = new ChainRepository(dir.FolderName))
         {
             var chain = new ConcurrentChain(Network.RegTest);
             repo.Load(chain).GetAwaiter().GetResult();
             Assert.True(chain.Tip == chain.Genesis);
             chain = new ConcurrentChain(Network.RegTest);
             var tip = AppendBlock(chain);
             repo.Save(chain).GetAwaiter().GetResult();
             var newChain = new ConcurrentChain(Network.RegTest);
             repo.Load(newChain).GetAwaiter().GetResult();
             Assert.Equal(tip, newChain.Tip);
             tip = AppendBlock(chain);
             repo.Save(chain).GetAwaiter().GetResult();
             newChain = new ConcurrentChain(Network.RegTest);
             repo.Load(newChain).GetAwaiter().GetResult();
             Assert.Equal(tip, newChain.Tip);
         }
     }
 }
コード例 #9
0
        public void SaveChainToDisk()
        {
            string dir   = CreateTestDir(this);
            var    chain = new ChainIndexer(KnownNetworks.StraxRegTest);

            this.AppendBlock(chain);

            using (var repo = new ChainRepository(new LevelDbChainStore(chain.Network, new DataFolder(dir), chain)))
            {
                repo.SaveAsync(chain).GetAwaiter().GetResult();
            }

            using (var engine = new DB(new Options {
                CreateIfMissing = true
            }, new DataFolder(dir).ChainPath))
            {
                ChainedHeader tip = null;
                var           itr = engine.GetEnumerator();
                while (itr.MoveNext())
                {
                    if (itr.Current.Key[0] == 1)
                    {
                        var data = new ChainRepository.ChainRepositoryData();
                        data.FromBytes(itr.Current.Value.ToArray(), this.Network.Consensus.ConsensusFactory);

                        tip = new ChainedHeader(data.Hash, data.Work, tip);

                        if (tip.Height == 0)
                        {
                            tip.SetChainStore(new ChainStore());
                        }
                    }
                }

                Assert.Equal(tip, chain.Tip);
            }
        }
コード例 #10
0
        /// <summary>
        /// Creates a transaction to transfers funds from an old federation to a new federation.
        /// </summary>
        /// <param name="isSideChain">Indicates whether the <paramref name="network"/> is the sidechain.</param>
        /// <param name="network">The network that we are creating the recovery transaction for.</param>
        /// <param name="counterChainNetwork">The counterchain network.</param>
        /// <param name="dataDirPath">The root folder containing the old federation.</param>
        /// <param name="redeemScript">The new redeem script.</param>
        /// <param name="password">The password required to generate transactions using the federation wallet.</param>
        /// <param name="txTime">Any deposits beyond this UTC date will be ignored when selecting coin inputs.</param>
        /// <returns>A funds recovery transaction that moves funds to the new redeem script.</returns>
        public FundsRecoveryTransactionModel CreateFundsRecoveryTransaction(bool isSideChain, Network network, Network counterChainNetwork, string dataDirPath, Script redeemScript, string password, DateTime txTime)
        {
            var model = new FundsRecoveryTransactionModel()
            {
                Network = network, IsSideChain = isSideChain, RedeemScript = redeemScript
            };

            // Get the old redeem script from the wallet file.
            PayToMultiSigTemplateParameters multisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(redeemScript);
            string           theChain          = isSideChain ? "sidechain" : "mainchain";
            var              nodeSettings      = new NodeSettings(network, args: new string[] { $"datadir={dataDirPath}", $"redeemscript={redeemScript}", $"-{theChain}" });
            var              walletFileStorage = new FileStorage <FederationWallet>(nodeSettings.DataFolder.WalletPath);
            FederationWallet wallet            = walletFileStorage.LoadByFileName("multisig_wallet.json");
            Script           oldRedeemScript   = wallet.MultiSigAddress.RedeemScript;
            PayToMultiSigTemplateParameters oldMultisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(oldRedeemScript);

            model.oldMultisigAddress = oldRedeemScript.Hash.GetAddress(network);
            model.newMultisigAddress = redeemScript.Hash.GetAddress(network);

            // Create dummy inputs to avoid errors when constructing FederatedPegSettings.
            var extraArgs = new Dictionary <string, string>();

            extraArgs[FederatedPegSettings.FederationIpsParam] = oldMultisigParams.PubKeys.Select(p => "0.0.0.0".ToIPEndPoint(nodeSettings.Network.DefaultPort)).Join(",");
            var privateKey = Key.Parse(wallet.EncryptedSeed, password, network);

            extraArgs[FederatedPegSettings.PublicKeyParam] = privateKey.PubKey.ToHex(network);
            (new TextFileConfiguration(extraArgs.Select(i => $"{i.Key}={i.Value}").ToArray())).MergeInto(nodeSettings.ConfigReader);

            model.PubKey = privateKey.PubKey;

            var dBreezeSerializer = new DBreezeSerializer(network.Consensus.ConsensusFactory);
            var blockStore        = new BlockRepository(network, nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);

            blockStore.Initialize();

            var           chain        = new ChainRepository(nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);
            Block         genesisBlock = network.GetGenesis();
            ChainedHeader tip          = chain.LoadAsync(new ChainedHeader(genesisBlock.Header, genesisBlock.GetHash(), 0)).GetAwaiter().GetResult();
            var           chainIndexer = new ChainIndexer(network, tip);

            var nodeLifetime = new NodeLifetime();
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;
            var federatedPegSettings           = new FederatedPegSettings(nodeSettings);
            var opReturnDataReader             = new OpReturnDataReader(nodeSettings.LoggerFactory, new CounterChainNetworkWrapper(counterChainNetwork));
            var walletFeePolicy = new WalletFeePolicy(nodeSettings);

            var walletManager = new FederationWalletManager(nodeSettings.LoggerFactory, network, chainIndexer, nodeSettings.DataFolder, walletFeePolicy,
                                                            new AsyncProvider(nodeSettings.LoggerFactory, new Signals(nodeSettings.LoggerFactory, new DefaultSubscriptionErrorHandler(nodeSettings.LoggerFactory)), nodeLifetime), nodeLifetime,
                                                            dateTimeProvider, federatedPegSettings, new WithdrawalExtractor(nodeSettings.LoggerFactory, federatedPegSettings, opReturnDataReader, network), blockStore);

            walletManager.Start();
            walletManager.EnableFederationWallet(password);

            if (!walletManager.IsFederationWalletActive())
            {
                throw new ArgumentException($"Could not activate the federation wallet on {network}.");
            }

            // Retrieves the unspent outputs in deterministic order.
            List <Stratis.Features.FederatedPeg.Wallet.UnspentOutputReference> coinRefs = walletManager.GetSpendableTransactionsInWallet().ToList();

            // Exclude coins (deposits) beyond the transaction (switch-over) time!
            coinRefs = coinRefs.Where(r => r.Transaction.CreationTime < txTime).ToList();
            if (!coinRefs.Any())
            {
                throw new ArgumentException($"There are no coins to recover from the federation wallet on {network}.");
            }

            Money fee = federatedPegSettings.GetWithdrawalTransactionFee(coinRefs.Count());

            var builder = new TransactionBuilder(network);

            builder.AddKeys(privateKey);
            builder.AddCoins(coinRefs.Select(c => ScriptCoin.Create(network, c.Transaction.Id, (uint)c.Transaction.Index, c.Transaction.Amount, c.Transaction.ScriptPubKey, oldRedeemScript)));

            // Split the coins into multiple outputs.
            Money     amount         = coinRefs.Sum(r => r.Transaction.Amount) - fee;
            const int numberOfSplits = 10;
            Money     splitAmount    = new Money((long)amount / numberOfSplits);
            var       recipients     = new List <Stratis.Features.FederatedPeg.Wallet.Recipient>();

            for (int i = 0; i < numberOfSplits; i++)
            {
                Money sendAmount = (i != (numberOfSplits - 1)) ? splitAmount : amount - splitAmount * (numberOfSplits - 1);

                builder.Send(redeemScript.PaymentScript, sendAmount);
            }

            builder.SetTimeStamp((uint)(new DateTimeOffset(txTime)).ToUnixTimeSeconds());
            builder.CoinSelector = new DeterministicCoinSelector();
            builder.SendFees(fee);

            model.tx = builder.BuildTransaction(true);

            File.WriteAllText(Path.Combine(dataDirPath, $"{network.Name}_{model.PubKey.ToHex(network).Substring(0, 8)}.hex"), model.tx.ToHex(network));

            // Merge our transaction with other transactions which have been placed in the data folder.
            Transaction oldTransaction = model.tx;
            string      namePattern    = $"{network.Name}_*.hex";
            int         sigCount       = 1;

            foreach (string fileName in Directory.EnumerateFiles(dataDirPath, namePattern))
            {
                Transaction incomingPartialTransaction = network.CreateTransaction(File.ReadAllText(fileName));

                // Don't merge with self.
                if (incomingPartialTransaction.GetHash() == oldTransaction.GetHash())
                {
                    continue;
                }

                // Transaction times must match.
                if (incomingPartialTransaction is PosTransaction && incomingPartialTransaction.Time != model.tx.Time)
                {
                    Console.WriteLine($"The locally generated transaction is time-stamped differently from the transaction contained in '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                // Combine signatures.
                Transaction newTransaction = SigningUtils.CheckTemplateAndCombineSignatures(builder, model.tx, new[] { incomingPartialTransaction });

                if (oldTransaction.GetHash() == newTransaction.GetHash())
                {
                    Console.WriteLine($"The locally generated transaction is not similar to '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                model.tx = newTransaction;
                sigCount++;
            }

            Console.WriteLine($"{sigCount} of {multisigParams.SignatureCount} signatures collected for {network.Name}.");

            if (sigCount >= multisigParams.SignatureCount)
            {
                if (builder.Verify(model.tx))
                {
                    // Write the transaction to file.
                    File.WriteAllText(Path.Combine(dataDirPath, $"{(txTime > DateTime.Now ? "Preliminary " : "")}{network.Name}Recovery.txt"), model.tx.ToHex(network));
                }
                else
                {
                    Console.WriteLine("Could not verify the transaction.");
                }
            }

            // Stop the wallet manager to release the database folder.
            nodeLifetime.StopApplication();
            walletManager.Stop();

            return(model);
        }
コード例 #11
0
 public ChainBusiness(ConfigurationModel configuration)
 {
     _envioReadRepository = new ChainRepository(configuration.EnvioRead);
 }