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]);
        }
示例#3
0
        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);
        }
示例#4
0
        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());
        }
示例#5
0
        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();
            }
        }