private static List <Recipient> GetRecipients(IServiceNodeRegistrationConfig registrationConfig, RegistrationToken registrationToken) { byte[] tokenBytes = registrationToken.GetRegistrationTokenBytes(registrationConfig.PrivateKey); byte[] markerBytes = Encoding.UTF8.GetBytes(RegistrationToken.Marker); var recipients = new List <Recipient> { new Recipient { Amount = registrationConfig.TxOutputValue, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(markerBytes) } }; recipients.AddRange(BlockChainDataConversions.BytesToPubKeys(tokenBytes).Select(pk => new Recipient { Amount = registrationConfig.TxOutputValue, ScriptPubKey = pk.ScriptPubKey })); if (!recipients.Any()) { throw new Exception("ERROR: No recipients for registration transaction, cannot proceed"); } return(recipients); }
public void ConvertPubKeyTest() { byte[] input = Encoding.ASCII.GetBytes("abc"); List <PubKey> keys = BlockChainDataConversions.BytesToPubKeys(input); byte[] converted = BlockChainDataConversions.PubKeysToBytes(keys); Assert.Equal(0x61, converted[0]); Assert.Equal(0x62, converted[1]); Assert.Equal(0x63, converted[2]); }
public Transaction CreateBreezeRegistrationTx(Network network, byte[] data, Money outputValue) { // Funding of the transaction is handled by the 'fundrawtransaction' RPC // call or its equivalent reimplementation. // Only construct the transaction outputs; the change address is handled // automatically by the funding logic // You need to control *where* the change address output appears inside the // transaction to prevent decoding errors with the addresses. Note that if // the fundrawtransaction RPC call is used there is an option that can be // passed to specify the position of the change output (it is randomly // positioned otherwise) Transaction sendTx = new Transaction(); // Recognisable string used to tag the transaction within the blockchain byte[] bytes = Encoding.UTF8.GetBytes("BREEZE_REGISTRATION_MARKER"); sendTx.Outputs.Add(new TxOut() { Value = outputValue, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes) }); // Add each data-encoding PubKey as a TxOut foreach (PubKey pubKey in BlockChainDataConversions.BytesToPubKeys(data)) { TxOut destTxOut = new TxOut() { Value = outputValue, ScriptPubKey = pubKey.ScriptPubKey }; sendTx.Outputs.Add(destTxOut); } if (sendTx.Outputs.Count == 0) { throw new Exception("ERROR: No outputs in registration transaction, cannot proceed"); } return(sendTx); }
public async Task DummyRegistration(string originWalletName, string originWalletPassword) { // TODO: Move this functionality into the tests var token = new List <byte>(); // Server ID token.AddRange(Encoding.ASCII.GetBytes("".PadRight(34))); // IPv4 address token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); // IPv6 address token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); // Onion address token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); token.Add(0x00); // Port number byte[] portNumber = BitConverter.GetBytes(37123); token.Add(portNumber[0]); token.Add(portNumber[1]); // RSA sig length byte[] rsaLength = BitConverter.GetBytes(256); token.Add(rsaLength[0]); token.Add(rsaLength[1]); // RSA signature byte[] rsaSig = new byte[256]; token.AddRange(rsaSig); // ECDSA sig length byte[] ecdsaLength = BitConverter.GetBytes(128); token.Add(ecdsaLength[0]); token.Add(ecdsaLength[1]); // ECDSA signature byte[] ecdsaSig = new byte[128]; token.AddRange(ecdsaSig); // Configuration hash token.AddRange(Encoding.ASCII.GetBytes("aa4e984c5655a677716539acc8cbc0ce29331429")); // Finally add protocol byte and computed length to beginning of header byte[] protocolVersionByte = BitConverter.GetBytes(254); byte[] headerLength = BitConverter.GetBytes(token.Count); token.Insert(0, protocolVersionByte[0]); token.Insert(1, headerLength[0]); token.Insert(2, headerLength[1]); Money outputValue = new Money(0.0001m, MoneyUnit.BTC); Transaction sendTx = new Transaction(); // Recognisable string used to tag the transaction within the blockchain byte[] bytes = Encoding.UTF8.GetBytes("BREEZE_REGISTRATION_MARKER"); sendTx.Outputs.Add(new TxOut() { Value = outputValue, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes) }); // Add each data-encoding PubKey as a TxOut foreach (PubKey pubKey in BlockChainDataConversions.BytesToPubKeys(token.ToArray())) { TxOut destTxOut = new TxOut() { Value = outputValue, ScriptPubKey = pubKey.ScriptPubKey }; sendTx.Outputs.Add(destTxOut); } HdAccount highestAcc = null; foreach (HdAccount account in this.walletManager.GetAccounts(originWalletName)) { if (highestAcc == null) { highestAcc = account; } if (account.GetSpendableAmount().ConfirmedAmount > highestAcc.GetSpendableAmount().ConfirmedAmount) { highestAcc = account; } } // This fee rate is primarily for regtest, testnet and mainnet have actual estimators that work FeeRate feeRate = new FeeRate(new Money(10000, MoneyUnit.Satoshi)); WalletAccountReference accountRef = new WalletAccountReference(originWalletName, highestAcc.Name); List <Recipient> recipients = new List <Recipient>(); TransactionBuildContext txBuildContext = new TransactionBuildContext(accountRef, recipients); txBuildContext.WalletPassword = originWalletPassword; txBuildContext.OverrideFeeRate = feeRate; txBuildContext.Sign = true; txBuildContext.MinConfirmations = 0; this.walletTransactionHandler.FundTransaction(txBuildContext, sendTx); this.logger.LogDebug("Trying to broadcast transaction: " + sendTx.GetHash()); await this.broadcasterManager.BroadcastTransactionAsync(sendTx).ConfigureAwait(false); var bcResult = this.broadcasterManager.GetTransaction(sendTx.GetHash()).State; switch (bcResult) { case Stratis.Bitcoin.Broadcasting.State.Broadcasted: case Stratis.Bitcoin.Broadcasting.State.Propagated: this.logger.LogDebug("Broadcasted transaction: " + sendTx.GetHash()); break; case Stratis.Bitcoin.Broadcasting.State.ToBroadcast: // Wait for propagation var waited = TimeSpan.Zero; var period = TimeSpan.FromSeconds(1); while (TimeSpan.FromSeconds(21) > waited) { // Check BroadcasterManager for broadcast success var transactionEntry = this.broadcasterManager.GetTransaction(sendTx.GetHash()); if (transactionEntry != null && transactionEntry.State == Stratis.Bitcoin.Broadcasting.State.Propagated) { // TODO: This is cluttering up the console, only need to log it once this.logger.LogDebug("Propagated transaction: " + sendTx.GetHash()); } await Task.Delay(period).ConfigureAwait(false); waited += period; } break; case Stratis.Bitcoin.Broadcasting.State.CantBroadcast: // Do nothing break; } this.logger.LogDebug("Uncertain if transaction was propagated: " + sendTx.GetHash()); }
public void RegistrationTest() { using (NodeBuilder builder = NodeBuilder.Create()) { CoreNode node1 = builder.CreateStratisPosNode(true, fullNodeBuilder => { fullNodeBuilder .UseStratisConsensus() .UseBlockStore() .UseMempool() .UseBlockNotification() .UseTransactionNotification() .UseWallet() .UseWatchOnlyWallet() .AddPowPosMining() //.AddMining() //.UseApi() .AddRPC(); }); CoreNode node2 = builder.CreateStratisPosNode(true, fullNodeBuilder => { fullNodeBuilder .UseStratisConsensus() .UseBlockStore() .UseMempool() .UseBlockNotification() .UseTransactionNotification() .UseWallet() .UseWatchOnlyWallet() .AddPowPosMining() //.AddMining() //.UseApi() .AddRPC() .UseRegistration(); }); node1.NotInIBD(); node2.NotInIBD(); var rpc1 = node1.CreateRPCClient(); var rpc2 = node2.CreateRPCClient(); // addnode RPC call does not seem to work, so connect directly node1.FullNode.ConnectionManager.AddNodeAddress(node2.Endpoint); // Create the originating node's wallet var wm1 = node1.FullNode.NodeService <IWalletManager>() as WalletManager; wm1.CreateWallet("Registration1", "registration"); var wallet1 = wm1.GetWalletByName("registration"); var account1 = wallet1.GetAccountsByCoinType((CoinType)node1.FullNode.Network.Consensus.CoinType).First(); var address1 = account1.GetFirstUnusedReceivingAddress(); var secret1 = wallet1.GetExtendedPrivateKeyForAddress("Registration1", address1); node1.SetDummyMinerSecret(new BitcoinSecret(secret1.PrivateKey, node1.FullNode.Network)); // Generate a block so we have some funds to create a transaction with node1.GenerateStratisWithMiner(52); TestHelper.TriggerSync(node1); TestHelper.TriggerSync(node2); TestHelper.WaitLoop(() => rpc1.GetBestBlockHash() == rpc2.GetBestBlockHash()); var rsa = new RsaKey(); var ecdsa = new Key().GetBitcoinSecret(Network.RegTest); var serverAddress = ecdsa.GetAddress().ToString(); var token = new RegistrationToken(1, serverAddress, IPAddress.Parse("127.0.0.1"), IPAddress.Parse("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), "0123456789ABCDEF", "", 37123, ecdsa.PubKey); var cryptoUtils = new CryptoUtils(rsa, ecdsa); token.RsaSignature = cryptoUtils.SignDataRSA(token.GetHeaderBytes().ToArray()); token.EcdsaSignature = cryptoUtils.SignDataECDSA(token.GetHeaderBytes().ToArray()); byte[] msgBytes = token.GetRegistrationTokenBytes(rsa, ecdsa); Transaction sendTx = new Transaction(); Money outputValue = new Money(0.01m, MoneyUnit.BTC); Money feeValue = new Money(0.01m, MoneyUnit.BTC); byte[] bytes = Encoding.UTF8.GetBytes("BREEZE_REGISTRATION_MARKER"); sendTx.Outputs.Add(new TxOut() { Value = outputValue, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes) }); foreach (PubKey pubKey in BlockChainDataConversions.BytesToPubKeys(msgBytes)) { TxOut destTxOut = new TxOut() { Value = outputValue, ScriptPubKey = pubKey.ScriptPubKey }; sendTx.Outputs.Add(destTxOut); } var wth1 = node1.FullNode.NodeService <IWalletTransactionHandler>() as WalletTransactionHandler; List <Recipient> recipients = new List <Recipient>(); foreach (TxOut txOut in sendTx.Outputs) { recipients.Add(new Recipient() { Amount = txOut.Value, ScriptPubKey = txOut.ScriptPubKey }); } var walletReference = new WalletAccountReference() { // Default to the first wallet & first account AccountName = wm1.Wallets.First().GetAccountsByCoinType((CoinType)node1.FullNode.Network.Consensus.CoinType).First().Name, WalletName = wm1.Wallets.First().Name }; var context = new TransactionBuildContext( walletReference, recipients, "Registration1") { MinConfirmations = 0, OverrideFeeRate = new FeeRate(new Money(0.001m, MoneyUnit.BTC)), Shuffle = false, Sign = true }; var tx = wth1.BuildTransaction(context); node1.AddToStratisPosMempool(tx); TestHelper.WaitLoop(() => rpc1.GetRawMempool().Length > 0); node1.GenerateStratisWithMiner(1); Thread.Sleep(10000); TestHelper.WaitLoop(() => rpc1.GetBestBlockHash() == rpc2.GetBestBlockHash()); Console.WriteLine("Checking if registration was received..."); var rm2 = node2.FullNode.NodeService <RegistrationManager>(); var rs2 = rm2.GetRegistrationStore(); foreach (var record in rs2.GetAll()) { Console.WriteLine("Received registration: " + record.RecordTxId); } Console.WriteLine(rs2.GetAll().Count); Thread.Sleep(10000); node1.Kill(); node2.Kill(); } }