Example #1
0
        public AddBlockResult Insert(Block block)
        {
            if (!CanAcceptNewBlocks)
            {
                return(AddBlockResult.CannotAccept);
            }

            if (block.Number == 0)
            {
                throw new InvalidOperationException("Genesis block should not be inserted.");
            }

            Rlp newRlp = _blockDecoder.Encode(block);

            _blockDb.Set(block.Hash, newRlp.Bytes);

            long expectedNumber = (LowestInsertedBody?.Number - 1 ?? LongConverter.FromString(_syncConfig.PivotNumber ?? "0"));

            if (block.Number != expectedNumber)
            {
                throw new InvalidOperationException($"Trying to insert out of order block {block.Number} when expected number was {expectedNumber}");
            }

            if (block.Number < (LowestInsertedBody?.Number ?? long.MaxValue))
            {
                LowestInsertedBody = block;
            }

            return(AddBlockResult.Added);
        }
Example #2
0
        public override BlockParameter ReadJson(JsonReader reader, Type objectType, BlockParameter existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            if (reader.Value == null)
            {
                return(BlockParameter.Latest);
            }

            if (reader.Value.IsNonStringValueType())
            {
                return(new BlockParameter((long)reader.Value));
            }

            string value = reader.Value as string;

            switch (value)
            {
            case "":
            case { } latest when latest.Equals("latest", StringComparison.InvariantCultureIgnoreCase):
                return(BlockParameter.Latest);

            case { } latest when latest.Equals("earliest", StringComparison.InvariantCultureIgnoreCase):
                return(BlockParameter.Earliest);

            case { } latest when latest.Equals("pending", StringComparison.InvariantCultureIgnoreCase):
                return(BlockParameter.Pending);

            default:
                return(new BlockParameter(LongConverter.FromString(value)));
            }
        }
Example #3
0
        public void FromJson(string jsonValue)
        {
            switch (jsonValue)
            {
            case string earliest when string.Equals(earliest, "earliest", StringComparison.InvariantCultureIgnoreCase):
                Type = BlockParameterType.Earliest;

                return;

            case string pending when string.Equals(pending, "pending", StringComparison.InvariantCultureIgnoreCase):
                Type = BlockParameterType.Pending;

                return;

            case string latest when string.Equals(latest, "latest", StringComparison.InvariantCultureIgnoreCase):
                Type = BlockParameterType.Latest;

                return;

            case string empty when string.IsNullOrWhiteSpace(empty):
                Type = BlockParameterType.Latest;

                return;

            case null:
                Type = BlockParameterType.Latest;
                return;

            default:
                Type        = BlockParameterType.BlockNumber;
                BlockNumber = LongConverter.FromString(jsonValue.Trim('"'));
                return;
            }
        }
Example #4
0
        public static BlockParameter FromJson(string jsonValue)
        {
            switch (jsonValue)
            {
            case { } earliest when string.Equals(earliest, "earliest", StringComparison.InvariantCultureIgnoreCase):
                return(Earliest);

            case { } pending when string.Equals(pending, "pending", StringComparison.InvariantCultureIgnoreCase):
                return(Pending);

            case { } latest when string.Equals(latest, "latest", StringComparison.InvariantCultureIgnoreCase):
                return(Latest);

            case { } empty when string.IsNullOrWhiteSpace(empty):
                return(Latest);

            case null:
                return(Latest);

            case { } hash when hash.Length == 66 && hash.StartsWith("0x"):
                return(Latest);

            default:
                return(new BlockParameter(LongConverter.FromString(jsonValue.Trim('"'))));
            }
        }
Example #5
0
        private void LoadEngine(ChainSpecJson chainSpecJson, ChainSpec chainSpec)
        {
            if (chainSpecJson.Engine?.AuthorityRound != null)
            {
                chainSpec.SealEngineType = SealEngineType.AuRa;
            }
            else if (chainSpecJson.Engine?.Clique != null)
            {
                chainSpec.SealEngineType = SealEngineType.Clique;
                chainSpec.Clique         = new CliqueParameters();
                chainSpec.Clique.Epoch   = chainSpecJson.Engine.Clique.Epoch;
                chainSpec.Clique.Period  = chainSpecJson.Engine.Clique.Period;
                chainSpec.Clique.Reward  = chainSpecJson.Engine.Clique.BlockReward ?? UInt256.Zero;
            }
            else if (chainSpecJson.Engine?.Ethash != null)
            {
                chainSpec.SealEngineType                = SealEngineType.Ethash;
                chainSpec.Ethash                        = new EthashParameters();
                chainSpec.Ethash.MinimumDifficulty      = chainSpecJson.Engine.Ethash.MinimumDifficulty ?? 0L;
                chainSpec.Ethash.DifficultyBoundDivisor = chainSpecJson.Engine.Ethash.DifficultyBoundDivisor ?? 0x0800L;
                chainSpec.Ethash.DurationLimit          = chainSpecJson.Engine.Ethash.DurationLimit ?? 13L;
                chainSpec.Ethash.HomesteadTransition    = chainSpecJson.Engine.Ethash.HomesteadTransition ?? 0;
                chainSpec.Ethash.DaoHardforkTransition  = chainSpecJson.Engine.Ethash.DaoHardforkTransition;
                chainSpec.Ethash.DaoHardforkBeneficiary = chainSpecJson.Engine.Ethash.DaoHardforkBeneficiary;
                chainSpec.Ethash.DaoHardforkAccounts    = chainSpecJson.Engine.Ethash.DaoHardforkAccounts ?? new Address[0];
                chainSpec.Ethash.Eip100bTransition      = chainSpecJson.Engine.Ethash.Eip100bTransition ?? 0L;

                chainSpec.Ethash.BlockRewards = new Dictionary <long, UInt256>();
                foreach (KeyValuePair <string, UInt256> reward in chainSpecJson.Engine.Ethash.BlockReward)
                {
                    chainSpec.Ethash.BlockRewards.Add(LongConverter.FromString(reward.Key), reward.Value);
                }

                chainSpec.Ethash.DifficultyBombDelays = new Dictionary <long, long>();
                foreach (KeyValuePair <string, long> reward in chainSpecJson.Engine.Ethash.DifficultyBombDelays)
                {
                    chainSpec.Ethash.DifficultyBombDelays.Add(LongConverter.FromString(reward.Key), reward.Value);
                }
            }
            else if (chainSpecJson.Engine?.NethDev != null)
            {
                chainSpec.SealEngineType = SealEngineType.NethDev;
            }
            else
            {
                throw new NotSupportedException("unknown seal engine in chainspec");
            }
        }
        private void LoadLowestInsertedBody()
        {
            long left  = 0L;
            long right = LongConverter.FromString(_syncConfig.PivotNumber ?? "0x0");

            Block lowestInsertedBlock = null;

            while (left != right)
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Finding lowest inserted body - L {left} | R {right}");
                }
                long           index = left + (right - left) / 2 + 1;
                ChainLevelInfo level = LoadLevel(index, true);
                Block          block = level == null ? null : FindBlock(level.BlockInfos[0].BlockHash, false);
                if (block == null)
                {
                    left = index;
                }
                else
                {
                    lowestInsertedBlock = block;
                    right = index - 1;
                }
            }

            if (lowestInsertedBlock == null)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Lowest inserted body is null - L {left} | R {right}");
                }
                LowestInsertedBody = null;
            }
            else
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Lowest inserted body is {LowestInsertedBody?.ToString(Block.Format.Short)} {right} - L {left} | R {right}");
                }
                LowestInsertedBody = lowestInsertedBlock;
            }
        }
        private void LoadLowestInsertedHeader()
        {
            long left  = 0L;
            long right = LongConverter.FromString(_syncConfig.PivotNumber ?? "0x0");

            ChainLevelInfo lowestInsertedLevel = null;

            while (left != right)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Finding lowest inserted header - L {left} | R {right}");
                }
                long           index = left + (right - left) / 2 + 1;
                ChainLevelInfo level = LoadLevel(index, true);
                if (level == null)
                {
                    left = index;
                }
                else
                {
                    lowestInsertedLevel = level;
                    right = index - 1L;
                }
            }

            if (lowestInsertedLevel == null)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Lowest inserted header is null - L {left} | R {right}");
                }
                LowestInsertedHeader = null;
            }
            else
            {
                BlockInfo blockInfo = lowestInsertedLevel.BlockInfos[0];
                LowestInsertedHeader = FindHeader(blockInfo.BlockHash);
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Lowest inserted header is {LowestInsertedHeader?.ToString(BlockHeader.Format.Short)} {right} - L {left} | R {right}");
                }
            }
        }
        public override ChainSpecJson.AuraEngineParamsJson.StepDurationJson ReadJson(JsonReader reader, Type objectType, ChainSpecJson.AuraEngineParamsJson.StepDurationJson existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            existingValue ??= new ChainSpecJson.AuraEngineParamsJson.StepDurationJson();
            if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer)
            {
                var stepDuration = serializer.Deserialize <long>(reader);
                existingValue.Add(0, stepDuration);
            }
            else
            {
                var stepDurations = serializer.Deserialize <Dictionary <string, long> >(reader);
                foreach (var stepDuration in stepDurations ?? throw new ArgumentException("Cannot deserialize StepDuration."))
                {
                    existingValue.Add(LongConverter.FromString(stepDuration.Key), stepDuration.Value);
                }
            }

            return(existingValue);
        }
        public override ChainSpecJson.BlockRewardJson ReadJson(JsonReader reader, Type objectType, ChainSpecJson.BlockRewardJson existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            existingValue ??= new ChainSpecJson.BlockRewardJson();
            if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer)
            {
                var blockReward = serializer.Deserialize <UInt256>(reader);
                existingValue.Add(0, blockReward);
            }
            else
            {
                var blockRewards = serializer.Deserialize <Dictionary <string, UInt256> >(reader);
                foreach (var blockReward in blockRewards ?? throw new ArgumentException("Cannot deserialize BlockReward."))
                {
                    existingValue.Add(LongConverter.FromString(blockReward.Key), blockReward.Value);
                }
            }

            return(existingValue);
        }
Example #10
0
        private void LoadEngine(ChainSpecJson chainSpecJson, ChainSpec chainSpec)
        {
            AuRaParameters.Validator LoadValidator(ChainSpecJson.AuRaValidatorJson validatorJson, int level = 0)
            {
                var validatorType = validatorJson.GetValidatorType();
                var validator     = new AuRaParameters.Validator()
                {
                    ValidatorType = validatorType
                };

                switch (validator.ValidatorType)
                {
                case AuRaParameters.ValidatorType.List:
                    validator.Addresses = validatorJson.List;
                    break;

                case AuRaParameters.ValidatorType.Contract:
                    validator.Addresses = new[] { validatorJson.SafeContract };
                    break;

                case AuRaParameters.ValidatorType.ReportingContract:
                    validator.Addresses = new[] { validatorJson.Contract };
                    break;

                case AuRaParameters.ValidatorType.Multi:
                    if (level != 0)
                    {
                        throw new ArgumentException("AuRa multi validator cannot be inner validator.");
                    }
                    validator.Validators = validatorJson.Multi
                                           .ToDictionary(kvp => kvp.Key, kvp => LoadValidator(kvp.Value, level + 1))
                                           .ToImmutableSortedDictionary();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                return(validator);
            }

            if (chainSpecJson.Engine?.AuthorityRound != null)
            {
                chainSpec.SealEngineType = SealEngineType.AuRa;
                chainSpec.AuRa           = new AuRaParameters
                {
                    MaximumUncleCount           = chainSpecJson.Engine.AuthorityRound.MaximumUncleCount,
                    MaximumUncleCountTransition = chainSpecJson.Engine.AuthorityRound.MaximumUncleCountTransition,
                    StepDuration = chainSpecJson.Engine.AuthorityRound.StepDuration,
                    BlockReward  = chainSpecJson.Engine.AuthorityRound.BlockReward,
                    BlockRewardContractAddress     = chainSpecJson.Engine.AuthorityRound.BlockRewardContractAddress,
                    BlockRewardContractTransition  = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransition,
                    BlockRewardContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransitions,
                    ValidateScoreTransition        = chainSpecJson.Engine.AuthorityRound.ValidateScoreTransition,
                    ValidateStepTransition         = chainSpecJson.Engine.AuthorityRound.ValidateStepTransition,
                    Validators = LoadValidator(chainSpecJson.Engine.AuthorityRound.Validator),
                    RandomnessContractAddress        = chainSpecJson.Engine.AuthorityRound.RandomnessContractAddress,
                    BlockGasLimitContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockGasLimitContractTransitions,
                };
            }
            else if (chainSpecJson.Engine?.Clique != null)
            {
                chainSpec.SealEngineType = SealEngineType.Clique;
                chainSpec.Clique         = new CliqueParameters
                {
                    Epoch  = chainSpecJson.Engine.Clique.Epoch,
                    Period = chainSpecJson.Engine.Clique.Period,
                    Reward = chainSpecJson.Engine.Clique.BlockReward ?? UInt256.Zero
                };
            }
            else if (chainSpecJson.Engine?.Ethash != null)
            {
                chainSpec.SealEngineType = SealEngineType.Ethash;
                chainSpec.Ethash         = new EthashParameters
                {
                    MinimumDifficulty      = chainSpecJson.Engine.Ethash.MinimumDifficulty ?? 0L,
                    DifficultyBoundDivisor = chainSpecJson.Engine.Ethash.DifficultyBoundDivisor ?? 0x0800L,
                    DurationLimit          = chainSpecJson.Engine.Ethash.DurationLimit ?? 13L,
                    HomesteadTransition    = chainSpecJson.Engine.Ethash.HomesteadTransition ?? 0,
                    DaoHardforkTransition  = chainSpecJson.Engine.Ethash.DaoHardforkTransition,
                    DaoHardforkBeneficiary = chainSpecJson.Engine.Ethash.DaoHardforkBeneficiary,
                    DaoHardforkAccounts    = chainSpecJson.Engine.Ethash.DaoHardforkAccounts ?? new Address[0],
                    Eip100bTransition      = chainSpecJson.Engine.Ethash.Eip100bTransition ?? 0L,
                    BlockRewards           = new Dictionary <long, UInt256>()
                };

                foreach (KeyValuePair <string, UInt256> reward in chainSpecJson.Engine.Ethash.BlockReward)
                {
                    chainSpec.Ethash.BlockRewards.Add(LongConverter.FromString(reward.Key), reward.Value);
                }

                chainSpec.Ethash.DifficultyBombDelays = new Dictionary <long, long>();
                foreach (KeyValuePair <string, long> reward in chainSpecJson.Engine.Ethash.DifficultyBombDelays)
                {
                    chainSpec.Ethash.DifficultyBombDelays.Add(LongConverter.FromString(reward.Key), reward.Value);
                }
            }
            else if (chainSpecJson.Engine?.NethDev != null)
            {
                chainSpec.SealEngineType = SealEngineType.NethDev;
            }
            else
            {
                throw new NotSupportedException("unknown seal engine in chainspec");
            }
        }
Example #11
0
        private int InsertBodies(BodiesSyncBatch batch)
        {
            List <Block> validResponses = new List <Block>();

            for (int i = 0; i < batch.Response.Length; i++)
            {
                BlockBody blockBody = batch.Response[i];
                if (blockBody == null)
                {
                    break;
                }

                Block block = new Block(batch.Headers[i], blockBody.Transactions, blockBody.Ommers);
                if (new TxTrie(block.Transactions).RootHash != block.TxRoot ||
                    OmmersHash.Calculate(block) != block.OmmersHash)
                {
                    if (_logger.IsWarn)
                    {
                        _logger.Warn($"{batch} - reporting INVALID - tx or ommers");
                    }
                    _syncPeerPool.ReportBreachOfProtocol(batch.ResponseSourcePeer, $"invalid tx or ommers root");
                    break;
                }

                validResponses.Add(block);
            }

            int validResponsesCount = validResponses.Count;

            if (validResponses.Count < batch.Request.Length)
            {
                BodiesSyncBatch fillerBatch = new BodiesSyncBatch();
                fillerBatch.MinNumber = batch.MinNumber;

                int originalLength = batch.Request.Length;
                fillerBatch.Request = new Keccak[originalLength - validResponsesCount];
                fillerBatch.Headers = new BlockHeader[originalLength - validResponsesCount];

                for (int i = validResponsesCount; i < originalLength; i++)
                {
                    fillerBatch.Request[i - validResponsesCount] = batch.Request[i];
                    fillerBatch.Headers[i - validResponsesCount] = batch.Headers[i];
                }

                if (_logger.IsDebug)
                {
                    _logger.Debug($"{batch} -> FILLER {fillerBatch}");
                }
                _pending.Enqueue(fillerBatch);
            }

            if (validResponses.Any())
            {
                long expectedNumber = _blockTree.LowestInsertedBody?.Number - 1 ?? LongConverter.FromString(_syncConfig.PivotNumber ?? "0");
                if (validResponses.Last().Number != expectedNumber)
                {
                    _dependencies.TryAdd(validResponses.Last().Number, validResponses);
                }
                else
                {
                    validResponses.Reverse();
                    InsertBlocks(validResponses);
                }

                if (_blockTree.LowestInsertedBody != null)
                {
                    _syncReport.FastBlocksBodies.Update(_pivotNumber - _blockTree.LowestInsertedBody.Number + 1);
                }
            }

            if (_logger.IsDebug)
            {
                _logger.Debug($"LOWEST_INSERTED {_blockTree.LowestInsertedBody?.Number} | HANDLED {batch}");
            }

            _syncReport.BodiesInQueue.Update(BodiesInQueue);
            return(validResponsesCount);
        }
            static AuRaParameters.Validator LoadValidator(ChainSpecJson.AuRaValidatorJson validatorJson, int level = 0)
            {
                AuRaParameters.ValidatorType validatorType = validatorJson.GetValidatorType();
                AuRaParameters.Validator     validator     = new() { ValidatorType = validatorType };
                switch (validator.ValidatorType)
                {
                case AuRaParameters.ValidatorType.List:
                    validator.Addresses = validatorJson.List;
                    break;

                case AuRaParameters.ValidatorType.Contract:
                    validator.Addresses = new[] { validatorJson.SafeContract };
                    break;

                case AuRaParameters.ValidatorType.ReportingContract:
                    validator.Addresses = new[] { validatorJson.Contract };
                    break;

                case AuRaParameters.ValidatorType.Multi:
                    if (level != 0)
                    {
                        throw new ArgumentException("AuRa multi validator cannot be inner validator.");
                    }
                    validator.Validators = validatorJson.Multi
                                           .ToDictionary(kvp => kvp.Key, kvp => LoadValidator(kvp.Value, level + 1))
                                           .ToImmutableSortedDictionary();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                return(validator);
            }

            if (chainSpecJson.Engine?.AuthorityRound != null)
            {
                chainSpec.SealEngineType = SealEngineType.AuRa;
                chainSpec.AuRa           = new AuRaParameters
                {
                    MaximumUncleCount           = chainSpecJson.Engine.AuthorityRound.MaximumUncleCount,
                    MaximumUncleCountTransition = chainSpecJson.Engine.AuthorityRound.MaximumUncleCountTransition,
                    StepDuration = chainSpecJson.Engine.AuthorityRound.StepDuration,
                    BlockReward  = chainSpecJson.Engine.AuthorityRound.BlockReward,
                    BlockRewardContractAddress     = chainSpecJson.Engine.AuthorityRound.BlockRewardContractAddress,
                    BlockRewardContractTransition  = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransition,
                    BlockRewardContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockRewardContractTransitions,
                    ValidateScoreTransition        = chainSpecJson.Engine.AuthorityRound.ValidateScoreTransition,
                    ValidateStepTransition         = chainSpecJson.Engine.AuthorityRound.ValidateStepTransition,
                    Validators = LoadValidator(chainSpecJson.Engine.AuthorityRound.Validator),
                    RandomnessContractAddress        = chainSpecJson.Engine.AuthorityRound.RandomnessContractAddress,
                    BlockGasLimitContractTransitions = chainSpecJson.Engine.AuthorityRound.BlockGasLimitContractTransitions,
                    TwoThirdsMajorityTransition      = chainSpecJson.Engine.AuthorityRound.TwoThirdsMajorityTransition ?? AuRaParameters.TransitionDisabled,
                    PosdaoTransition = chainSpecJson.Engine.AuthorityRound.PosdaoTransition ?? AuRaParameters.TransitionDisabled,
                    RewriteBytecode  = chainSpecJson.Engine.AuthorityRound.RewriteBytecode,
                };
            }
            else if (chainSpecJson.Engine?.Clique != null)
            {
                chainSpec.SealEngineType = SealEngineType.Clique;
                chainSpec.Clique         = new CliqueParameters
                {
                    Epoch  = chainSpecJson.Engine.Clique.Epoch,
                    Period = chainSpecJson.Engine.Clique.Period,
                    Reward = chainSpecJson.Engine.Clique.BlockReward ?? UInt256.Zero
                };
            }
            else if (chainSpecJson.Engine?.Ethash != null)
            {
                chainSpec.SealEngineType = SealEngineType.Ethash;
                chainSpec.Ethash         = new EthashParameters
                {
                    MinimumDifficulty      = chainSpecJson.Engine.Ethash.MinimumDifficulty ?? 0L,
                    DifficultyBoundDivisor = chainSpecJson.Engine.Ethash.DifficultyBoundDivisor ?? 0x0800L,
                    DurationLimit          = chainSpecJson.Engine.Ethash.DurationLimit ?? 13L,
                    HomesteadTransition    = chainSpecJson.Engine.Ethash.HomesteadTransition ?? 0,
                    DaoHardforkTransition  = chainSpecJson.Engine.Ethash.DaoHardforkTransition,
                    DaoHardforkBeneficiary = chainSpecJson.Engine.Ethash.DaoHardforkBeneficiary,
                    DaoHardforkAccounts    = chainSpecJson.Engine.Ethash.DaoHardforkAccounts ?? Array.Empty <Address>(),
                    Eip100bTransition      = chainSpecJson.Engine.Ethash.Eip100bTransition ?? 0L,
                    FixedDifficulty        = chainSpecJson.Engine.Ethash.FixedDifficulty,
                    BlockRewards           = chainSpecJson.Engine.Ethash.BlockReward
                };

                chainSpec.Ethash.DifficultyBombDelays = new Dictionary <long, long>();
                if (chainSpecJson.Engine.Ethash.DifficultyBombDelays != null)
                {
                    foreach (KeyValuePair <string, long> reward in chainSpecJson.Engine.Ethash.DifficultyBombDelays)
                    {
                        chainSpec.Ethash.DifficultyBombDelays.Add(LongConverter.FromString(reward.Key), reward.Value);
                    }
                }
            }
            else if (chainSpecJson.Engine?.NethDev != null)
            {
                chainSpec.SealEngineType = SealEngineType.NethDev;
            }

            var customEngineType = chainSpecJson.Engine?.CustomEngineData?.FirstOrDefault().Key;

            if (!string.IsNullOrEmpty(customEngineType))
            {
                chainSpec.SealEngineType = customEngineType;
            }

            if (string.IsNullOrEmpty(chainSpec.SealEngineType))
            {
                throw new NotSupportedException("unknown seal engine in chainspec");
            }
        }