// Checks that node can sync from scratch if federation voted in favor of adding a new fed member. public async Task CanSyncIfFedMemberAddedAsync() { int originalFedMembersCount = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count; TestHelper.Connect(this.node1, this.node2); var model = new HexPubKeyModel() { PubKeyHex = "03025fcadedd28b12665de0542c8096f4cd5af8e01791a4d057f67e2866ca66ba7" }; this.node1.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); this.node2.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); await this.node2.MineBlocksAsync((int)this.network.Consensus.MaxReorgLength * 3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Equal(originalFedMembersCount + 1, this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
public async Task ReorgRevertsAppliedChangesAsync() { TestHelper.Connect(this.node1, this.node2); var model = new HexPubKeyModel() { PubKeyHex = this.testPubKey.ToHex() }; this.node1.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); this.node1.FullNode.NodeService <FederationVotingController>().VoteKickFedMember(model); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); this.node2.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); await this.node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Single(this.node2.FullNode.NodeService <VotingManager>().GetPendingPolls()); Assert.Single(this.node2.FullNode.NodeService <VotingManager>().GetFinishedPolls()); await this.node3.MineBlocksAsync(4); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); Assert.Empty(this.node2.FullNode.NodeService <VotingManager>().GetPendingPolls()); Assert.Empty(this.node2.FullNode.NodeService <VotingManager>().GetFinishedPolls()); }
// Checks that node can sync from scratch if federation voted in favor of kicking a fed member. public async Task CanSyncIfFedMemberKickedAsync() { int originalFedMembersCount = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count; TestHelper.Connect(this.node1, this.node2); byte[] fedMemberBytes = (this.poaNetwork.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(new FederationMember(this.poaNetwork.FederationKey2.PubKey)); var votingData = new VotingData() { Key = VoteKey.KickFederationMember, Data = fedMemberBytes }; this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); this.node2.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); await this.node1.MineBlocksAsync((int)this.poaNetwork.Consensus.MaxReorgLength * 3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Equal(originalFedMembersCount - 1, this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
// Checks that node can sync from scratch if federation voted in favor of kicking a fed member. public async Task CanSyncIfFedMemberKickedAsync() { int originalFedMembersCount = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count; TestHelper.Connect(this.node1, this.node2); var model = new HexPubKeyModel() { PubKeyHex = this.network.FederationKey2.PubKey.ToHex() }; this.node1.FullNode.NodeService <FederationVotingController>().VoteKickFedMember(model); this.node2.FullNode.NodeService <FederationVotingController>().VoteKickFedMember(model); await this.node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); await this.node1.MineBlocksAsync((int)this.network.Consensus.MaxReorgLength * 3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Equal(originalFedMembersCount - 1, this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
// Checks that node can sync from scratch if federation voted in favor of adding a new fed member. public async Task CanSyncIfFedMemberAddedAsync() { List <IFederationMember> originalFedMembers = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers(); TestHelper.Connect(this.node1, this.node2); IFederationMember federationMember = new FederationMember(new PubKey("03025fcadedd28b12665de0542c8096f4cd5af8e01791a4d057f67e2866ca66ba7")); byte[] fedMemberBytes = (this.poaNetwork.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(federationMember); var votingData = new VotingData() { Key = VoteKey.AddFederationMember, Data = fedMemberBytes }; this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); this.node2.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); await this.node2.MineBlocksAsync((int)this.poaNetwork.Consensus.MaxReorgLength * 3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); List <IFederationMember> newFedMembers = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers(); Assert.Equal(originalFedMembers.Count + 1, newFedMembers.Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
public async Task CanMineVotingRequestTransactionAsync() { var network = new TestPoACollateralNetwork(true, Guid.NewGuid().ToString()); using (PoANodeBuilder builder = PoANodeBuilder.CreatePoANodeBuilder(this)) { string walletName = "mywallet"; string walletPassword = "******"; string walletAccount = "account 0"; Money transferAmount = Money.Coins(0.01m); Money feeAmount = Money.Coins(0.0001m); var counterchainNetwork = new StraxTest(); CoreNode nodeA = builder.CreatePoANodeWithCounterchain(network, counterchainNetwork, network.FederationKey1).WithWallet(walletPassword, walletName).Start(); CoreNode nodeB = builder.CreatePoANodeWithCounterchain(network, counterchainNetwork, network.FederationKey2).WithWallet(walletPassword, walletName).Start(); TestHelper.Connect(nodeA, nodeB); long toMineCount = network.Consensus.PremineHeight + network.Consensus.CoinbaseMaturity + 1 - nodeA.GetTip().Height; // Get coins on nodeA via the premine. await nodeA.MineBlocksAsync((int)toMineCount).ConfigureAwait(false); CoreNodePoAExtensions.WaitTillSynced(nodeA, nodeB); // Create voting-request transaction. var minerKey = new Key(); var collateralKey = new Key(); var request = new JoinFederationRequest(minerKey.PubKey, new Money(CollateralFederationMember.MinerCollateralAmount, MoneyUnit.BTC), collateralKey.PubKey.Hash); // In practice this signature will come from calling the counter-chain "signmessage" API. request.AddSignature(collateralKey.SignMessage(request.SignatureMessage)); var encoder = new JoinFederationRequestEncoder(nodeA.FullNode.NodeService <Microsoft.Extensions.Logging.ILoggerFactory>()); Transaction trx = JoinFederationRequestBuilder.BuildTransaction(nodeA.FullNode.WalletTransactionHandler(), this.network, request, encoder, walletName, walletAccount, walletPassword); await nodeA.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(trx.ToHex())); TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 1 && nodeB.CreateRPCClient().GetRawMempool().Length == 1); await nodeB.MineBlocksAsync((int)toMineCount).ConfigureAwait(false); TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 0 && nodeB.CreateRPCClient().GetRawMempool().Length == 0); IWalletManager walletManager = nodeB.FullNode.NodeService <IWalletManager>(); TestBase.WaitLoop(() => { long balance = walletManager.GetBalances(walletName, walletAccount).Sum(x => x.AmountConfirmed); return(balance == feeAmount); }); Assert.Single(nodeA.FullNode.NodeService <VotingManager>().GetPendingPolls()); Assert.Single(nodeB.FullNode.NodeService <VotingManager>().GetPendingPolls()); } }
public async Task TransactionSentFeesReceivedByMinerAsync() { TestPoANetwork network = new TestPoANetwork(); using (PoANodeBuilder builder = PoANodeBuilder.CreatePoANodeBuilder(this)) { string walletName = "mywallet"; string walletPassword = "******"; string walletAccount = "account 0"; Money transferAmount = Money.Coins(1m); Money feeAmount = Money.Coins(0.0001m); CoreNode nodeA = builder.CreatePoANode(network, network.FederationKey1).WithWallet(walletPassword, walletName).Start(); CoreNode nodeB = builder.CreatePoANode(network, network.FederationKey2).WithWallet(walletPassword, walletName).Start(); TestHelper.Connect(nodeA, nodeB); long toMineCount = network.Consensus.PremineHeight + network.Consensus.CoinbaseMaturity + 1 - nodeA.GetTip().Height; // Get coins on nodeA via the premine. await nodeA.MineBlocksAsync((int)toMineCount).ConfigureAwait(false); CoreNodePoAExtensions.WaitTillSynced(nodeA, nodeB); // Will send funds to one of nodeB's addresses. Script destination = nodeB.FullNode.WalletManager().GetUnusedAddress().ScriptPubKey; var context = new TransactionBuildContext(network) { AccountReference = new WalletAccountReference(walletName, walletAccount), MinConfirmations = 0, FeeType = FeeType.High, WalletPassword = walletPassword, Recipients = new[] { new Recipient { Amount = transferAmount, ScriptPubKey = destination } }.ToList() }; Transaction trx = nodeA.FullNode.WalletTransactionHandler().BuildTransaction(context); nodeA.FullNode.NodeController <WalletController>().SendTransaction(new SendTransactionRequest(trx.ToHex())); TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 1 && nodeB.CreateRPCClient().GetRawMempool().Length == 1); await nodeB.MineBlocksAsync((int)toMineCount).ConfigureAwait(false); TestBase.WaitLoop(() => nodeA.CreateRPCClient().GetRawMempool().Length == 0 && nodeB.CreateRPCClient().GetRawMempool().Length == 0); IWalletManager walletManager = nodeB.FullNode.NodeService <IWalletManager>(); long balance = walletManager.GetBalances(walletName, walletAccount).Sum(x => x.AmountConfirmed); Assert.True(balance == transferAmount + feeAmount); } }
// Checks that fed members cant vote twice. // Checks that miner adds voting data if it exists. public async Task CantVoteTwiceAsync() { int originalFedMembersCount = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count; TestHelper.Connect(this.node1, this.node2); await this.node1.MineBlocksAsync(3); IFederationMember federationMember = new FederationMember(new PubKey("03025fcadedd28b12665de0542c8096f4cd5af8e01791a4d057f67e2866ca66ba7")); byte[] fedMemberBytes = (this.poaNetwork.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(federationMember); var votingData = new VotingData() { Key = VoteKey.AddFederationMember, Data = fedMemberBytes }; this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); // Vote 2nd time and make sure nothing changed. this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node1.MineBlocksAsync(1); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); // Node 2 votes. After that it will be enough to change the federation. this.node2.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node2.MineBlocksAsync((int)this.poaNetwork.Consensus.MaxReorgLength + 1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Equal(originalFedMembersCount + 1, this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); Assert.Equal(originalFedMembersCount + 1, this.node2.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
private async Task VoteAndMineBlockAsync(PubKey key, bool add, CoreNode node) { byte[] fedMemberBytes = (this.poaNetwork.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(new FederationMember(key)); var votingData = new VotingData() { Key = add ? VoteKey.AddFederationMember : VoteKey.KickFederationMember, Data = fedMemberBytes }; node.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await node.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
// Checks that fed members cant vote twice. // Checks that miner adds voting data if it exists. public async Task CantVoteTwiceAsync() { int originalFedMembersCount = this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count; TestHelper.Connect(this.node1, this.node2); await this.node1.MineBlocksAsync(3); var model = new HexPubKeyModel() { PubKeyHex = "03025fcadedd28b12665de0542c8096f4cd5af8e01791a4d057f67e2866ca66ba7" }; this.node1.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); // Vote 2nd time and make sure nothing changed. this.node1.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); await this.node1.MineBlocksAsync(1); Assert.Empty(this.node1.FullNode.NodeService <VotingManager>().GetScheduledVotes()); Assert.Single(this.node1.FullNode.NodeService <VotingManager>().GetPendingPolls()); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); // Node 2 votes. After that it will be enough to change the federation. this.node2.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); await this.node2.MineBlocksAsync((int)this.network.Consensus.MaxReorgLength + 1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Equal(originalFedMembersCount + 1, this.node1.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); Assert.Equal(originalFedMembersCount + 1, this.node2.FullNode.NodeService <IFederationManager>().GetFederationMembers().Count); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
public async Task CanVoteToWhitelistAndRemoveHashesAsync() { int maxReorg = (int)this.network.Consensus.MaxReorgLength; Assert.Empty(this.node1.FullNode.NodeService <IWhitelistedHashesRepository>().GetHashes()); TestHelper.Connect(this.node1, this.node2); await this.node1.MineBlocksAsync(1); var model = new HashModel() { Hash = Hashes.Hash256(RandomUtils.GetUInt64().ToBytes()).ToString() }; // Node 1 votes to add hash this.node1.FullNode.NodeService <DefaultVotingController>().VoteWhitelistHash(model); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); // Node 2 votes to add hash this.node2.FullNode.NodeService <DefaultVotingController>().VoteWhitelistHash(model); await this.node2.MineBlocksAsync(maxReorg + 2); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Single(this.node1.FullNode.NodeService <IWhitelistedHashesRepository>().GetHashes()); // Node 1 votes to remove hash this.node1.FullNode.NodeService <DefaultVotingController>().VoteRemoveHash(model); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); // Node 2 votes to remove hash this.node2.FullNode.NodeService <DefaultVotingController>().VoteRemoveHash(model); await this.node2.MineBlocksAsync(maxReorg + 2); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Empty(this.node1.FullNode.NodeService <IWhitelistedHashesRepository>().GetHashes()); }
private async Task VoteAndMineBlockAsync(PubKey key, bool add, CoreNode node) { var model = new HexPubKeyModel() { PubKeyHex = key.ToHex() }; if (add) { node.FullNode.NodeService <FederationVotingController>().VoteAddFedMember(model); } else { node.FullNode.NodeService <FederationVotingController>().VoteKickFedMember(model); } await node.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); }
public async Task ReorgRevertsAppliedChangesAsync() { TestHelper.Connect(this.node1, this.node2); byte[] fedMemberBytes = (this.poaNetwork.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(new FederationMember(this.testPubKey)); var votingData = new VotingData() { Key = VoteKey.AddFederationMember, Data = fedMemberBytes }; this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); votingData = new VotingData() { Key = VoteKey.KickFederationMember, Data = fedMemberBytes }; this.node1.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); votingData = new VotingData() { Key = VoteKey.AddFederationMember, Data = fedMemberBytes }; this.node2.FullNode.NodeService <VotingManager>().ScheduleVote(votingData); await this.node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2); Assert.Single(this.node2.FullNode.NodeService <VotingManager>().GetPendingPolls()); Assert.Single(this.node2.FullNode.NodeService <VotingManager>().GetApprovedPolls()); await this.node3.MineBlocksAsync(4); TestHelper.Connect(this.node2, this.node3); CoreNodePoAExtensions.WaitTillSynced(this.node1, this.node2, this.node3); Assert.Empty(this.node2.FullNode.NodeService <VotingManager>().GetPendingPolls()); Assert.Empty(this.node2.FullNode.NodeService <VotingManager>().GetApprovedPolls()); }
public async Task EnableAutoKickAsync() { using (var builder = PoANodeBuilder.CreatePoANodeBuilder(this)) { const int idleTimeSeconds = 10 * 60; // Have a network that mimics Cirrus where voting is on and kicking is off. var votingNetwork1 = new TestPoANetwork("VoteNetwork1"); var votingNetwork2 = new TestPoANetwork("VoteNetwork2"); var oldOptions = (PoAConsensusOptions)votingNetwork1.Consensus.Options; votingNetwork1.Consensus.Options = new PoAConsensusOptions(maxBlockBaseSize: oldOptions.MaxBlockBaseSize, maxStandardVersion: oldOptions.MaxStandardVersion, maxStandardTxWeight: oldOptions.MaxStandardTxWeight, maxBlockSigopsCost: oldOptions.MaxBlockSigopsCost, maxStandardTxSigopsCost: oldOptions.MaxStandardTxSigopsCost, genesisFederationMembers: oldOptions.GenesisFederationMembers, targetSpacingSeconds: 60, votingEnabled: true, autoKickIdleMembers: false, federationMemberMaxIdleTimeSeconds: oldOptions.FederationMemberMaxIdleTimeSeconds); CoreNode node1 = builder.CreatePoANode(votingNetwork1, votingNetwork1.FederationKey1).Start(); CoreNode node2 = builder.CreatePoANode(votingNetwork2, votingNetwork2.FederationKey2).Start(); TestHelper.Connect(node1, node2); // Mine a block on this network from each node. Confirm it's alive. await node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(node1, node2); await node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(node1, node2); // Edit the consensus options so that kicking is turned on. votingNetwork1.Consensus.Options = new PoAConsensusOptions(maxBlockBaseSize: oldOptions.MaxBlockBaseSize, maxStandardVersion: oldOptions.MaxStandardVersion, maxStandardTxWeight: oldOptions.MaxStandardTxWeight, maxBlockSigopsCost: oldOptions.MaxBlockSigopsCost, maxStandardTxSigopsCost: oldOptions.MaxStandardTxSigopsCost, genesisFederationMembers: oldOptions.GenesisFederationMembers, targetSpacingSeconds: 60, votingEnabled: true, autoKickIdleMembers: true, federationMemberMaxIdleTimeSeconds: idleTimeSeconds); // Restart node 1 to ensure that we have the new network consensus options which reflects // the autokicking enabled. node1.Restart(); // Lets get our 2 nodes to actively mine some blocks. // In doing so, their test datetimeprovider will increment by minutes at a time. for (int i = 0; i < 5; i++) { await node1.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(node1, node2); await node2.MineBlocksAsync(1); CoreNodePoAExtensions.WaitTillSynced(node1, node2); } // Enough time has passed - Check that our new node wants to vote the third fed member out, who has not mined at all. // Check that we have a single active poll to vote him out. List <Poll> activePolls = node1.FullNode.NodeService <VotingManager>().GetPendingPolls(); Assert.Single(activePolls); Assert.Equal(VoteKey.KickFederationMember, activePolls[0].VotingData.Key); byte[] lastMemberBytes = (votingNetwork1.Consensus.ConsensusFactory as PoAConsensusFactory).SerializeFederationMember(votingNetwork1.ConsensusOptions.GenesisFederationMembers[2]); Assert.Equal(lastMemberBytes, activePolls[0].VotingData.Data); } }