/// <summary> /// Initializes an instance of the <see cref="ScriptPubKey"/> class. /// </summary> /// <param name="script">The script.</param> /// <param name="network">The network where the transaction was conducted.</param> public ScriptPubKey(NBitcoin.Script script, Network network) : base(script) { var destinations = new List <TxDestination> { script.GetDestination(network) }; this.Type = this.GetScriptType(script.FindTemplate(network)); if (destinations[0] == null) { destinations = script.GetDestinationPublicKeys(network) .Select(p => p.Hash) .ToList <TxDestination>(); } else { if (destinations.Count == 1) { this.ReqSigs = 1; this.Addresses = new List <string> { destinations[0].GetAddress(network).ToString() }; } else { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script); this.ReqSigs = multi.SignatureCount; this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); } } }
public override Script GenerateScriptSig(Network network, Script scriptPubKey, IKeyRepository keyRepo, ISigner signer) { PayToMultiSigTemplateParameters multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(network, scriptPubKey); var signatures = new TransactionSignature[multiSigParams.PubKeys.Length]; Key[] keys = multiSigParams .PubKeys .Select(p => keyRepo.FindKey(p.ScriptPubKey)) .ToArray(); int sigCount = 0; for (int i = 0; i < keys.Length; i++) { if (sigCount == multiSigParams.SignatureCount) { break; } if (keys[i] != null) { TransactionSignature sig = signer.Sign(keys[i]); signatures[i] = sig; sigCount++; } } IEnumerable <TransactionSignature> sigs = signatures; if (sigCount == multiSigParams.SignatureCount) { sigs = sigs.Where(s => s != TransactionSignature.Empty && s != null); } return(PayToMultiSigTemplate.Instance.GenerateScriptSig(sigs)); }
public string Signature() { PayToMultiSigTemplateParameters multisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.RedeemScript); int index = multisigParams.PubKeys.IndexOf(this.PubKey); TransactionSignature signature = PayToMultiSigTemplate.Instance.ExtractScriptSigParameters(this.Network, new Script(tx.Inputs[0].ScriptSig.ToOps().SkipLast(1)))[index]; return(signature.ToString()); }
public FederatedPegSettings(NodeSettings nodeSettings, IFederatedPegOptions federatedPegOptions = null) { Guard.NotNull(nodeSettings, nameof(nodeSettings)); TextFileConfiguration configReader = nodeSettings.ConfigReader; this.IsMainChain = configReader.GetOrDefault("mainchain", false); if (!this.IsMainChain && !configReader.GetOrDefault("sidechain", false)) { throw new ConfigurationException("Either -mainchain or -sidechain must be specified"); } string redeemScriptRaw = configReader.GetOrDefault <string>(RedeemScriptParam, null); Console.WriteLine(redeemScriptRaw); if (redeemScriptRaw == null) { throw new ConfigurationException($"could not find {RedeemScriptParam} configuration parameter"); } this.MultiSigRedeemScript = new Script(redeemScriptRaw); this.MultiSigAddress = this.MultiSigRedeemScript.Hash.GetAddress(nodeSettings.Network); PayToMultiSigTemplateParameters payToMultisigScriptParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.MultiSigRedeemScript); this.MultiSigM = payToMultisigScriptParams.SignatureCount; this.MultiSigN = payToMultisigScriptParams.PubKeys.Length; this.FederationPublicKeys = payToMultisigScriptParams.PubKeys; this.PublicKey = configReader.GetOrDefault <string>(PublicKeyParam, null); if (this.FederationPublicKeys.All(p => p != new PubKey(this.PublicKey))) { throw new ConfigurationException("Please make sure the public key passed as parameter was used to generate the multisig redeem script."); } // Federation IPs - These are required to receive and sign withdrawal transactions. string federationIpsRaw = configReader.GetOrDefault <string>(FederationIpsParam, null); if (federationIpsRaw == null) { throw new ConfigurationException("Federation IPs must be specified."); } IEnumerable <IPEndPoint> endPoints = federationIpsRaw.Split(',').Select(a => a.ToIPEndPoint(nodeSettings.Network.DefaultPort)); this.FederationNodeIpEndPoints = new HashSet <IPEndPoint>(endPoints, new IPEndPointComparer()); this.FederationNodeIpAddresses = new HashSet <IPAddress>(endPoints.Select(x => x.Address), new IPAddressComparer()); // These values are only configurable for tests at the moment. Fed members on live networks shouldn't play with them. this.CounterChainDepositStartBlock = configReader.GetOrDefault(CounterChainDepositBlock, this.IsMainChain ? 1 : StratisMainDepositStartBlock); this.FasterDepositThresholdAmount = Money.Coins(configReader.GetOrDefault(FasterDepositThresholdAmountParam, 100)); this.FasterDepositMinimumConfirmations = configReader.GetOrDefault(FasterDepositMinimumConfirmationsParam, 10); this.MinimumDepositConfirmations = configReader.GetOrDefault(MinimumDepositConfirmationsParam, (int)nodeSettings.Network.Consensus.MaxReorgLength + 1); this.WalletSyncFromHeight = configReader.GetOrDefault(WalletSyncFromHeightParam, federatedPegOptions?.WalletSyncFromHeight ?? 0); }
/// <summary> /// Initializes an instance of the <see cref="ScriptPubKey"/> class. /// </summary> /// <param name="script">The script.</param> /// <param name="network">The network where the transaction was conducted.</param> public ScriptPubKey(NBitcoin.Script script, Network network) : base(script) { this.Type = this.GetScriptType(script.FindTemplate(network)); // To avoid modifying the very low-level GetDestination logic, check for a cold staking script first. // The decision to show the cold pubkey's address in the 'addresses' list is based on the following: // 1. It seems more intuitive from a user's perspective that their balance will appear against this address. // 2. A balance should never appear against a hot address from an exchange's perspective, as they have no guarantee they will be able to spend those funds. // It is also presumed that it is preferable to show an address rather than not, as a block explorer would then have to show only a relatively meaningless raw script as the output's destination. // Another considered alternative was to show both addresses, but with a modified version byte. The underlying pubkey hashes would be the same, but the resulting addresses would be visually distinct from regular P2PKH. // This may have caused user confusion, however, as the modified addresses would not look like those they used to configure the cold staking setup, making searching for them on a block explorer more difficult. if (script.IsScriptType(ScriptType.ColdStaking)) { var coldPubKeyHash = new KeyId(script.ToBytes(true).SafeSubarray(28, 20)); this.ReqSigs = 1; this.Addresses = new List <string> { coldPubKeyHash.GetAddress(network).ToString() }; return; } var destinations = new List <TxDestination> { script.GetDestination(network) }; if (destinations[0] == null) { destinations = script.GetDestinationPublicKeys(network).Select(p => p.Hash).ToList <TxDestination>(); } // TODO: We do not want to put the cold staking addresses into the 'addresses' element due to the high potential for confusion. Maybe introduce an additional element? if (destinations.Count == 1) { this.ReqSigs = 1; this.Addresses = new List <string> { destinations[0].GetAddress(network).ToString() }; } else if (destinations.Count > 1) { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(script) ?? PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(script, network); if (multi != null) { this.ReqSigs = multi.SignatureCount; this.Addresses = multi.PubKeys.Select(m => m.GetAddress(network).ToString()).ToList(); } } }
public FederationGatewaySettings(NodeSettings nodeSettings) { Guard.NotNull(nodeSettings, nameof(nodeSettings)); TextFileConfiguration configReader = nodeSettings.ConfigReader; this.IsMainChain = configReader.GetOrDefault <bool>("mainchain", false); if (!this.IsMainChain && !configReader.GetOrDefault("sidechain", false)) { throw new ConfigurationException("Either -mainchain or -sidechain must be specified"); } string redeemScriptRaw = configReader.GetOrDefault <string>(RedeemScriptParam, null); Console.WriteLine(redeemScriptRaw); if (redeemScriptRaw == null) { throw new ConfigurationException($"could not find {RedeemScriptParam} configuration parameter"); } this.MultiSigRedeemScript = new Script(redeemScriptRaw); this.MultiSigAddress = this.MultiSigRedeemScript.Hash.GetAddress(nodeSettings.Network); PayToMultiSigTemplateParameters payToMultisigScriptParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.MultiSigRedeemScript); this.MultiSigM = payToMultisigScriptParams.SignatureCount; this.MultiSigN = payToMultisigScriptParams.PubKeys.Length; this.FederationPublicKeys = payToMultisigScriptParams.PubKeys; this.PublicKey = configReader.GetOrDefault <string>(PublicKeyParam, null); this.MinCoinMaturity = configReader.GetOrDefault <int>(MinCoinMaturityParam, (int)nodeSettings.Network.Consensus.MaxReorgLength + 1); if (this.MinCoinMaturity <= 0) { throw new ConfigurationException("The minimum coin maturity can't be set to zero or less."); } this.TransactionFee = new Money(configReader.GetOrDefault <decimal>(TransactionFeeParam, 0.01m), MoneyUnit.BTC); if (this.FederationPublicKeys.All(p => p != new PubKey(this.PublicKey))) { throw new ConfigurationException("Please make sure the public key passed as parameter was used to generate the multisig redeem script."); } this.CounterChainApiPort = configReader.GetOrDefault(CounterChainApiPortParam, 0); this.FederationNodeIpEndPoints = configReader.GetOrDefault <string>(FederationIpsParam, null)?.Split(',') .Select(a => a.ToIPEndPoint(nodeSettings.Network.DefaultPort)) ?? new List <IPEndPoint>(); //todo : remove that for prod code this.MinimumDepositConfirmations = (uint)configReader.GetOrDefault <int>(MinimumDepositConfirmationsParam, (int)nodeSettings.Network.Consensus.MaxReorgLength + 1); //this.MinimumDepositConfirmations = nodeSettings.Network.Consensus.MaxReorgLength + 1; }
public static KeyId[] ExtractKeyIDs(Script script) { KeyId keyId = PayToPubkeyHashTemplate.Instance.ExtractScriptPubKeyParameters(script); if (keyId != null) { return(new[] { keyId }); } else { PayToMultiSigTemplateParameters para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(Network.Main, script); if (para == null) { throw new ArgumentException("Invalid stealth spendable output script", "spendable"); } return(para.PubKeys.Select(k => k.Hash).ToArray()); } }
public override Script CombineScriptSig(Network network, Script scriptPubKey, Script a, Script b) { PayToMultiSigTemplateParameters para = PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey, network); // Combine all the signatures we've got: TransactionSignature[] aSigs = PayToFederationTemplate.Instance.ExtractScriptSigParameters(network, a); if (aSigs == null) { return(b); } TransactionSignature[] bSigs = PayToFederationTemplate.Instance.ExtractScriptSigParameters(network, b); if (bSigs == null) { return(a); } int sigCount = 0; var sigs = new TransactionSignature[para.PubKeys.Length]; for (int i = 0; i < para.PubKeys.Length; i++) { TransactionSignature aSig = i < aSigs.Length ? aSigs[i] : null; TransactionSignature bSig = i < bSigs.Length ? bSigs[i] : null; TransactionSignature sig = aSig ?? bSig; if (sig != null) { sigs[i] = sig; sigCount++; } if (sigCount == para.SignatureCount) { break; } } if (sigCount == para.SignatureCount) { sigs = sigs.Where(s => s != null && s != TransactionSignature.Empty).ToArray(); } return(PayToFederationTemplate.Instance.GenerateScriptSig(sigs)); }
private static void HandleSwitchGenerateFundsRecoveryTransaction(string[] args, bool newFormat = false) { ConfigReader = new TextFileConfiguration(args); // datadir = Directory of old federation. if (newFormat) { ConfirmArguments(ConfigReader, "network", "datadir", "fedpubkeys", "password", "txtime"); } else { ConfirmArguments(ConfigReader, "network", "datadir", "fedpubkeys", "quorum", "password", "txtime"); } PayToMultiSigTemplateParameters para = new PayToMultiSigTemplateParameters() { PubKeys = GetFederatedPublicKeysFromArguments().Select(p => new PubKey(p)).ToArray(), SignatureCount = newFormat ? 0 : GetQuorumFromArguments() }; string password = GetPasswordFromArguments(); string dataDirPath = GetDataDirFromArguments(); (Network mainChain, Network sideChain) = GetMainAndSideChainNetworksFromArguments(); DateTime txTime = GetTransactionTimeFromArguments(); Console.WriteLine($"Creating funds recovery transaction for {sideChain.Name}."); FundsRecoveryTransactionModel sideChainInfo = (new RecoveryTransactionCreator()).CreateFundsRecoveryTransaction(true, sideChain, mainChain, dataDirPath, para, password, txTime, newFormat); sideChainInfo.DisplayInfo(); Console.WriteLine($"Creating funds recovery transaction for {mainChain.Name}."); FundsRecoveryTransactionModel mainChainInfo = (new RecoveryTransactionCreator()).CreateFundsRecoveryTransaction(false, mainChain, sideChain, dataDirPath, para, password, txTime, newFormat, true); mainChainInfo.DisplayInfo(); }
public override int EstimateScriptSigSize(Network network, Script scriptPubKey) { PayToMultiSigTemplateParameters para = PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey, network); return(PayToFederationTemplate.Instance.GenerateScriptSig(Enumerable.Range(0, para.SignatureCount).Select(o => DummySignature).ToArray()).Length); }
protected override void WriteTransaction(JsonTextWriter writer, Transaction tx) { WritePropertyValue(writer, "txid", tx.GetHash().ToString()); WritePropertyValue(writer, "version", tx.Version); WritePropertyValue(writer, "locktime", tx.LockTime.Value); writer.WritePropertyName("vin"); writer.WriteStartArray(); foreach (TxIn txin in tx.Inputs) { writer.WriteStartObject(); if (txin.PrevOut.Hash == uint256.Zero) { WritePropertyValue(writer, "coinbase", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes())); } else { WritePropertyValue(writer, "txid", txin.PrevOut.Hash.ToString()); WritePropertyValue(writer, "vout", txin.PrevOut.N); writer.WritePropertyName("scriptSig"); writer.WriteStartObject(); WritePropertyValue(writer, "asm", txin.ScriptSig.ToString()); WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txin.ScriptSig.ToBytes())); writer.WriteEndObject(); } WritePropertyValue(writer, "sequence", (uint)txin.Sequence); writer.WriteEndObject(); } writer.WriteEndArray(); writer.WritePropertyName("vout"); writer.WriteStartArray(); int i = 0; foreach (TxOut txout in tx.Outputs) { writer.WriteStartObject(); writer.WritePropertyName("value"); writer.WriteRawValue(ValueFromAmount(txout.Value)); WritePropertyValue(writer, "n", i); writer.WritePropertyName("scriptPubKey"); writer.WriteStartObject(); WritePropertyValue(writer, "asm", txout.ScriptPubKey.ToString()); WritePropertyValue(writer, "hex", Encoders.Hex.EncodeData(txout.ScriptPubKey.ToBytes())); var destinations = new List <TxDestination>() { txout.ScriptPubKey.GetDestination(this.Network) }; if (destinations[0] == null) { destinations = txout.ScriptPubKey.GetDestinationPublicKeys(this.Network) .Select(p => p.Hash) .ToList <TxDestination>(); } if (destinations.Count == 1) { WritePropertyValue(writer, "reqSigs", 1); WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.Network))); writer.WritePropertyName("addresses"); writer.WriteStartArray(); writer.WriteValue(destinations[0].GetAddress(this.Network).ToString()); writer.WriteEndArray(); } else { PayToMultiSigTemplateParameters multi = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(this.Network, txout.ScriptPubKey); if (multi != null) { WritePropertyValue(writer, "reqSigs", multi.SignatureCount); } WritePropertyValue(writer, "type", GetScriptType(txout.ScriptPubKey.FindTemplate(this.Network))); if (multi != null) { writer.WritePropertyName("addresses"); writer.WriteStartArray(); foreach (PubKey key in multi.PubKeys) { writer.WriteValue(key.Hash.GetAddress(this.Network).ToString()); } writer.WriteEndArray(); } } writer.WriteEndObject(); //endscript writer.WriteEndObject(); //in out i++; } writer.WriteEndArray(); }
/// <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); }
public FederatedPegSettings(NodeSettings nodeSettings, CounterChainNetworkWrapper counterChainNetworkWrapper) { Guard.NotNull(nodeSettings, nameof(nodeSettings)); TextFileConfiguration configReader = nodeSettings.ConfigReader; this.IsMainChain = configReader.GetOrDefault("mainchain", false); if (!this.IsMainChain && !configReader.GetOrDefault("sidechain", false)) { throw new ConfigurationException("Either -mainchain or -sidechain must be specified"); } string redeemScriptRaw = configReader.GetOrDefault <string>(RedeemScriptParam, null); Console.WriteLine(redeemScriptRaw); PayToMultiSigTemplateParameters para = null; if (!string.IsNullOrEmpty(redeemScriptRaw)) { var redeemScript = new Script(redeemScriptRaw); para = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(redeemScript) ?? PayToFederationTemplate.Instance.ExtractScriptPubKeyParameters(redeemScript, nodeSettings.Network); } if (para == null) { string pubKeys = configReader.GetOrDefault <string>(FederationKeysParam, null); if (string.IsNullOrEmpty(pubKeys)) { throw new ConfigurationException($"Either -{RedeemScriptParam} or -{FederationKeysParam} must be specified."); } para.PubKeys = pubKeys.Split(",").Select(s => new PubKey(s.Trim())).ToArray(); para.SignatureCount = (pubKeys.Length + 1) / 2; } para.SignatureCount = configReader.GetOrDefault(FederationQuorumParam, para.SignatureCount); IFederation federation; federation = new Federation(para.PubKeys, para.SignatureCount); nodeSettings.Network.Federations.RegisterFederation(federation); counterChainNetworkWrapper.CounterChainNetwork.Federations.RegisterFederation(federation); this.MultiSigRedeemScript = federation.MultisigScript; this.MultiSigAddress = this.MultiSigRedeemScript.Hash.GetAddress(nodeSettings.Network); this.MultiSigM = para.SignatureCount; this.MultiSigN = para.PubKeys.Length; this.FederationPublicKeys = para.PubKeys; this.PublicKey = configReader.GetOrDefault <string>(PublicKeyParam, null); if (this.FederationPublicKeys.All(p => p != new PubKey(this.PublicKey))) { throw new ConfigurationException("Please make sure the public key passed as parameter was used to generate the multisig redeem script."); } // Federation IPs - These are required to receive and sign withdrawal transactions. string federationIpsRaw = configReader.GetOrDefault <string>(FederationIpsParam, null); if (federationIpsRaw == null) { throw new ConfigurationException("Federation IPs must be specified."); } IEnumerable <IPEndPoint> endPoints = federationIpsRaw.Split(',').Select(a => a.ToIPEndPoint(nodeSettings.Network.DefaultPort)); this.FederationNodeIpEndPoints = new HashSet <IPEndPoint>(endPoints, new IPEndPointComparer()); this.FederationNodeIpAddresses = new HashSet <IPAddress>(endPoints.Select(x => x.Address), new IPAddressComparer()); // These values are only configurable for tests at the moment. Fed members on live networks shouldn't play with them. this.CounterChainDepositStartBlock = configReader.GetOrDefault(CounterChainDepositBlock, 1); this.SmallDepositThresholdAmount = Money.Coins(configReader.GetOrDefault(ThresholdAmountSmallDepositParam, 50)); this.NormalDepositThresholdAmount = Money.Coins(configReader.GetOrDefault(ThresholdAmountNormalDepositParam, 1000)); this.MinimumConfirmationsSmallDeposits = configReader.GetOrDefault(MinimumConfirmationsSmallDepositsParam, 25); this.MinimumConfirmationsNormalDeposits = configReader.GetOrDefault(MinimumConfirmationsNormalDepositsParam, 80); this.MinimumConfirmationsLargeDeposits = (int)nodeSettings.Network.Consensus.MaxReorgLength + 1; this.MinimumConfirmationsDistributionDeposits = (int)nodeSettings.Network.Consensus.MaxReorgLength + 1; this.MaximumPartialTransactionThreshold = configReader.GetOrDefault(MaximumPartialTransactionsParam, CrossChainTransferStore.MaximumPartialTransactions); this.WalletSyncFromHeight = configReader.GetOrDefault(WalletSyncFromHeightParam, 0); }