Exemplo n.º 1
0
        public async Task NodeVersionInitialFailTryAgain()
        {
            // Arrange
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection();

            IBeaconNodeOApiClient beaconNodeOApiClient1 = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient1.VersionAsync(Arg.Any <CancellationToken>()).Throws(new HttpRequestException("TESTEXCEPTION"));
            IBeaconNodeOApiClient beaconNodeOApiClient2 = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient2.VersionAsync(Arg.Any <CancellationToken>()).Returns("TESTVERSION");
            IBeaconNodeOApiClientFactory beaconNodeOApiClientFactory = Substitute.For <IBeaconNodeOApiClientFactory>();

            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Returns(beaconNodeOApiClient1, beaconNodeOApiClient2);
            testServiceCollection.AddSingleton <IBeaconNodeOApiClientFactory>(beaconNodeOApiClientFactory);

            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            // Act
            IBeaconNodeApi beaconNodeProxy = testServiceProvider.GetService <IBeaconNodeApi>();

            beaconNodeProxy.ShouldBeOfType(typeof(BeaconNodeProxy));
            string version1 = await beaconNodeProxy.GetNodeVersionAsync(CancellationToken.None);

            // Assert
            version1.ShouldBe("TESTVERSION");
            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Received(2);
        }
Exemplo n.º 2
0
        public async Task NodeVersionTwiceShouldUseSameClient()
        {
            // Arrange
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection();

            IBeaconNodeOApiClient beaconNodeOApiClient = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient.VersionAsync(Arg.Any <CancellationToken>()).Returns("TESTVERSION");
            IBeaconNodeOApiClientFactory beaconNodeOApiClientFactory = Substitute.For <IBeaconNodeOApiClientFactory>();

            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Returns(beaconNodeOApiClient);
            testServiceCollection.AddSingleton <IBeaconNodeOApiClientFactory>(beaconNodeOApiClientFactory);

            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            // Act
            IBeaconNodeApi beaconNodeProxy = testServiceProvider.GetService <IBeaconNodeApi>();

            beaconNodeProxy.ShouldBeOfType(typeof(BeaconNodeProxy));
            string version1 = await beaconNodeProxy.GetNodeVersionAsync(CancellationToken.None);

            string version2 = await beaconNodeProxy.GetNodeVersionAsync(CancellationToken.None);

            // Assert
            version1.ShouldBe("TESTVERSION");
            version2.ShouldBe("TESTVERSION");
            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Received(1);
        }
Exemplo n.º 3
0
        public async Task NodeVersionInitialFailAfterSuccessTryAgain()
        {
            // Arrange
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection();

            IBeaconNodeOApiClient beaconNodeOApiClient1 = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient1.VersionAsync(Arg.Any <CancellationToken>()).Returns(
                callInfo => "TESTVERSION1",
                callInfo => throw new HttpRequestException("TESTEXCEPTION")
                );
            beaconNodeOApiClient1.BaseUrl.Returns("CLIENT1");
            IBeaconNodeOApiClient beaconNodeOApiClient2 = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient2.VersionAsync(Arg.Any <CancellationToken>()).Returns("TESTVERSION2");
            IBeaconNodeOApiClientFactory beaconNodeOApiClientFactory = Substitute.For <IBeaconNodeOApiClientFactory>();

            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Returns(beaconNodeOApiClient1, beaconNodeOApiClient2);
            testServiceCollection.AddSingleton <IBeaconNodeOApiClientFactory>(beaconNodeOApiClientFactory);

            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            // Act
            IBeaconNodeApi beaconNodeProxy = testServiceProvider.GetService <IBeaconNodeApi>();

            beaconNodeProxy.ShouldBeOfType(typeof(BeaconNodeProxy));
            string version1 = await beaconNodeProxy.GetNodeVersionAsync(CancellationToken.None);

            string version2 = await beaconNodeProxy.GetNodeVersionAsync(CancellationToken.None);

            // Assert
            version1.ShouldBe("TESTVERSION1");
            version2.ShouldBe("TESTVERSION2");
            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Received(2);

            List <ICall> client1Received = beaconNodeOApiClient1.ReceivedCalls().ToList();

            client1Received.Count(x => x.GetMethodInfo().Name == nameof(beaconNodeOApiClient1.VersionAsync)).ShouldBe(2);

            List <ICall> client2Received = beaconNodeOApiClient2.ReceivedCalls().ToList();

            client2Received.Count(x => x.GetMethodInfo().Name == nameof(beaconNodeOApiClient1.VersionAsync)).ShouldBe(1);
        }
Exemplo n.º 4
0
        public async Task BasicGensisTime()
        {
            // Arrange
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection();

            IBeaconNodeOApiClient beaconNodeOApiClient = Substitute.For <IBeaconNodeOApiClient>();

            beaconNodeOApiClient.TimeAsync(Arg.Any <CancellationToken>()).Returns(1_578_009_600uL);
            IBeaconNodeOApiClientFactory beaconNodeOApiClientFactory = Substitute.For <IBeaconNodeOApiClientFactory>();

            beaconNodeOApiClientFactory.CreateClient(Arg.Any <string>()).Returns(beaconNodeOApiClient);
            testServiceCollection.AddSingleton <IBeaconNodeOApiClientFactory>(beaconNodeOApiClientFactory);

            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            // Act
            IBeaconNodeApi beaconNodeProxy = testServiceProvider.GetService <IBeaconNodeApi>();

            beaconNodeProxy.ShouldBeOfType(typeof(BeaconNodeProxy));
            ulong genesisTime = await beaconNodeProxy.GetGenesisTimeAsync(CancellationToken.None);

            // Assert
            genesisTime.ShouldBe(1578009600uL);
        }
Exemplo n.º 5
0
        // // The proxy needs to take care of this (i.e. transparent to worker)
        // // Not connected: (remote vs local)
        // // connect to beacon node (priority order)
        // // if not connected, wait and try next
        //
        // public async Task<string> GetNodeVersionAsync(CancellationToken cancellationToken)
        // {
        //     string? result = null;
        //     await ClientOperationWithRetry(
        //         async (oapiClient, innerCancellationToken) =>
        //         {
        //             result = await oapiClient.VersionAsync(innerCancellationToken).ConfigureAwait(false);
        //         }, cancellationToken).ConfigureAwait(false);
        //
        //     return result!;
        // }
        //
        // public Task<Syncing> GetSyncingAsync(CancellationToken cancellationToken)
        // {
        //     throw new NotImplementedException();
        // }
        //
        // public async Task<Core2.Containers.BeaconBlock> NewBlockAsync(Slot slot, BlsSignature randaoReveal,
        //     CancellationToken cancellationToken)
        // {
        //     ulong slotValue = (ulong) slot;
        //     byte[] randaoRevealBytes = randaoReveal.Bytes;
        //
        //     BeaconBlock? result = null;
        //     await ClientOperationWithRetry(
        //         async (oapiClient, innerCancellationToken) =>
        //         {
        //             result = await oapiClient.BlockAsync(slotValue, randaoRevealBytes, innerCancellationToken)
        //                 .ConfigureAwait(false);
        //         }, cancellationToken).ConfigureAwait(false);
        //
        //     BeaconBlock oapiBeaconBlock = result!;
        //     Core2.Containers.BeaconBlock beaconBlock = new Core2.Containers.BeaconBlock(
        //         new Slot((ulong) oapiBeaconBlock.Slot),
        //         new Root(Bytes.FromHexString(oapiBeaconBlock.Parent_root)),
        //         new Root(Bytes.FromHexString(oapiBeaconBlock.State_root)),
        //         new Core2.Containers.BeaconBlockBody(
        //             new BlsSignature(oapiBeaconBlock.Body.Randao_reveal),
        //             new Eth1Data(
        //                 new Root(oapiBeaconBlock.Body.Eth1_data.Deposit_root),
        //                 (ulong) oapiBeaconBlock.Body.Eth1_data.Deposit_count,
        //                 new Bytes32(oapiBeaconBlock.Body.Eth1_data.Block_hash)
        //             ),
        //             new Bytes32(oapiBeaconBlock.Body.Graffiti),
        //             oapiBeaconBlock.Body.Proposer_slashings.Select(x => new ProposerSlashing(
        //                 new ValidatorIndex((ulong) x.Proposer_index),
        //                 new SignedBeaconBlockHeader(MapBeaconBlockHeader(x.Header_1), BlsSignature.Zero),
        //                 new SignedBeaconBlockHeader(MapBeaconBlockHeader(x.Header_2), BlsSignature.Zero)
        //             )),
        //             oapiBeaconBlock.Body.Attester_slashings.Select(x => new AttesterSlashing(
        //                 MapIndexedAttestation(x.Attestation_1),
        //                 MapIndexedAttestation(x.Attestation_2)
        //             )),
        //             oapiBeaconBlock.Body.Attestations.Select(x =>
        //                 new Core2.Containers.Attestation(
        //                     new BitArray(x.Aggregation_bits),
        //                     MapAttestationData(x.Data),
        //                     new BlsSignature(x.Signature)
        //                 )
        //             ),
        //             oapiBeaconBlock.Body.Deposits.Select(x =>
        //                 new Deposit(
        //                     x.Proof.Select(y => new Bytes32(y)),
        //                     new DepositData(
        //                         new BlsPublicKey(x.Data.Pubkey),
        //                         new Bytes32(x.Data.Withdrawal_credentials),
        //                         new Gwei((ulong) x.Data.Amount),
        //                         new BlsSignature(x.Data.Signature)
        //                     )
        //                 )
        //             ),
        //             oapiBeaconBlock.Body.Voluntary_exits.Select(x =>
        //                 new SignedVoluntaryExit(
        //                     new VoluntaryExit(
        //                         new Epoch((ulong) x.Epoch),
        //                         new ValidatorIndex((ulong) x.Validator_index)
        //                     ),
        //                     BlsSignature.Zero
        //                 )
        //             )
        //         )
        //     );
        //
        //     return beaconBlock;
        // }
        //
        // public async Task<bool> PublishBlockAsync(SignedBeaconBlock signedBlock, CancellationToken cancellationToken)
        // {
        //     var block = signedBlock.Message;
        //     BeaconBlock data = new BeaconBlock()
        //     {
        //         Slot = block.Slot,
        //         Parent_root = block.ParentRoot.ToString(),
        //         State_root = block.StateRoot.ToString(),
        //         Body = new BeaconBlockBody()
        //         {
        //             Randao_reveal = block.Body!.RandaoReveal.AsSpan().ToArray(),
        //             Eth1_data = new Eth1_data()
        //             {
        //                 Block_hash = block.Body.Eth1Data.BlockHash.AsSpan().ToArray(),
        //                 Deposit_count = block.Body.Eth1Data.DepositCount,
        //                 Deposit_root = block.Body.Eth1Data.DepositRoot.AsSpan().ToArray()
        //             },
        //             Graffiti = block.Body.Graffiti.AsSpan().ToArray(),
        //             Proposer_slashings = block.Body.ProposerSlashings.Select(x => new Proposer_slashings()
        //             {
        //                 Header_1 = MapBeaconBlockHeader(x.SignedHeader1.Message),
        //                 Header_2 = MapBeaconBlockHeader(x.SignedHeader2.Message),
        //                 Proposer_index = x.ProposerIndex
        //             }).ToList(),
        //             Attester_slashings = block.Body.AttesterSlashings.Select(x => new Attester_slashings()
        //             {
        //                 Attestation_1 = MapIndexedAttestation(x.Attestation1),
        //                 Attestation_2 = MapIndexedAttestation(x.Attestation2)
        //             }).ToList(),
        //             Attestations = block.Body.Attestations.Select(x => new Attestations()
        //             {
        //                 Signature = x.Signature.Bytes,
        //                 Aggregation_bits = x.AggregationBits.Cast<byte>().ToArray(),
        //                 Custody_bits = new byte[0],
        //                 Data = MapAttestationData(x.Data)
        //             }).ToList(),
        //             Voluntary_exits = block.Body.VoluntaryExits.Select(x => new Voluntary_exits()
        //             {
        //                 Validator_index = x.Message.ValidatorIndex,
        //                 Epoch = x.Message.Epoch,
        //                 Signature = x.Signature.Bytes
        //             }).ToList(),
        //             Deposits = block.Body.Deposits.Select((x, index) => new Deposits()
        //             {
        //                 Index = (ulong) index,
        //                 Proof = x.Proof.Select(y => y.AsSpan().ToArray()).ToList(),
        //                 Data = new Data()
        //                 {
        //                     Amount = x.Data.Amount,
        //                     Pubkey = x.Data.PublicKey.Bytes,
        //                     Signature = x.Data.Signature.Bytes,
        //                     Withdrawal_credentials = x.Data.WithdrawalCredentials.AsSpan().ToArray()
        //                 }
        //             }).ToList(),
        //         }
        //     };
        //
        //     await ClientOperationWithRetry(
        //         async (oapiClient, innerCancellationToken) =>
        //         {
        //             await oapiClient.Block2Async(data, signedBlock.Signature, innerCancellationToken)
        //                 .ConfigureAwait(false);
        //         }, cancellationToken).ConfigureAwait(false);
        //
        //     // TODO: Parse 202 result separate from 200 result
        //
        //     return true;
        // }
        //
        // public async IAsyncEnumerable<Core2.Api.ValidatorDuty> ValidatorDutiesAsync(
        //     IEnumerable<BlsPublicKey> validatorPublicKeys,
        //     Epoch epoch, [EnumeratorCancellation] CancellationToken cancellationToken)
        // {
        //     IEnumerable<byte[]> validator_pubkeys = validatorPublicKeys.Select(x => x.Bytes);
        //     ulong? epochValue = (epoch != Epoch.None) ? (ulong?) epoch : null;
        //
        //     ICollection<ValidatorDuty>? result = null;
        //     await ClientOperationWithRetry(
        //         async (oapiClient, innerCancellationToken) =>
        //         {
        //             result = await oapiClient.DutiesAsync(validator_pubkeys, epochValue, innerCancellationToken)
        //                 .ConfigureAwait(false);
        //         }, cancellationToken).ConfigureAwait(false);
        //
        //     foreach (var value in result!)
        //     {
        //         var validatorPublicKey = new BlsPublicKey(value.Validator_pubkey);
        //         var proposalSlot = value.Block_proposal_slot.HasValue
        //             ? new Slot(value.Block_proposal_slot.Value)
        //             : Slot.None;
        //         var validatorDuty = new Core2.Api.ValidatorDuty(validatorPublicKey, new Slot(value.Attestation_slot),
        //             new Shard(value.Attestation_shard), proposalSlot);
        //         yield return validatorDuty;
        //     }
        // }

        private async Task ClientOperationWithRetry(
            Func <IBeaconNodeOApiClient, CancellationToken, Task> clientOperation, CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                IBeaconNodeOApiClient?localClient = _oapiClient;
                if (!(localClient is null))
                {
                    try
                    {
                        await clientOperation(localClient, cancellationToken).ConfigureAwait(false);

                        // exit loop and complete on success
                        break;
                    }
                    catch (HttpRequestException ex)
                    {
                        // Only null out if the same client is still there (i.e. no one else has replaced)
                        IBeaconNodeOApiClient?exchangeResult =
                            Interlocked.CompareExchange(ref _oapiClient, null, localClient);
                        if (exchangeResult == localClient)
                        {
                            if (_logger.IsWarn())
                            {
                                Log.NodeConnectionFailed(_logger, localClient.BaseUrl, ex);
                            }
                        }
                    }
                }

                // take turns trying the first connection
                await _connectionAttemptSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

                try
                {
                    // this routine's turn to try and connect (if no one else has)
                    if (_oapiClient is null)
                    {
                        // create new client
                        _connectionIndex++;
                        BeaconNodeConnection beaconNodeConnection = _beaconNodeConnectionOptions.CurrentValue;
                        if (_connectionIndex >= beaconNodeConnection.RemoteUrls.Length)
                        {
                            _connectionIndex = 0;
                            if (_logger.IsWarn())
                            {
                                Log.AllNodeConnectionsFailing(_logger, beaconNodeConnection.RemoteUrls.Length,
                                                              beaconNodeConnection.ConnectionFailureLoopMillisecondsDelay, null);
                            }
                            await Task.Delay(beaconNodeConnection.ConnectionFailureLoopMillisecondsDelay,
                                             cancellationToken).ConfigureAwait(false);
                        }

                        string baseUrl = beaconNodeConnection.RemoteUrls[_connectionIndex];
                        if (_logger.IsDebug())
                        {
                            LogDebug.AttemptingConnectionToNode(_logger, baseUrl, _connectionIndex, null);
                        }
                        IBeaconNodeOApiClient newClient = _oapiClientFactory.CreateClient(baseUrl);

                        // check if it works
                        await clientOperation(newClient, cancellationToken).ConfigureAwait(false);

                        // success! set the client, and if not the first, set the connection index to restart from first
                        if (_logger.IsInfo())
                        {
                            Log.NodeConnectionSuccess(_logger, baseUrl, _connectionIndex, null);
                        }
                        _oapiClient = newClient;
                        if (_connectionIndex > 0)
                        {
                            _connectionIndex = -1;
                        }

                        // exit loop and complete on success
                        break;
                    }
                }
                catch (HttpRequestException)
                {
                    // Continue
                }
                finally
                {
                    _connectionAttemptSemaphore.Release();
                }
            }
        }