├── .buildkite ├── default.nix ├── pipeline.nix ├── pipeline.yml ├── publish.sh └── shell.nix ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .gitmodules ├── .jvmopts ├── .scalafix.conf ├── .scalafmt.conf ├── LICENSE ├── NOTICE ├── README.md ├── build.sbt ├── bytes └── src │ ├── main │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ └── utils │ │ ├── ByteStringUtils.scala │ │ ├── ByteUtils.scala │ │ └── Hex.scala │ └── test │ └── scala │ └── io │ └── iohk │ └── ethereum │ └── utils │ ├── ByteStringUtilsTest.scala │ └── ByteUtilsSpec.scala ├── crypto └── src │ ├── main │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ └── crypto │ │ ├── ConcatKDFBytesGenerator.scala │ │ ├── ECDSASignature.scala │ │ ├── ECIESCoder.scala │ │ ├── EthereumIESEngine.scala │ │ ├── MGF1BytesGeneratorExt.scala │ │ ├── SymmetricCipher.scala │ │ ├── package.scala │ │ └── zksnark │ │ ├── BN128.scala │ │ ├── FieldElement.scala │ │ ├── FiniteField.scala │ │ └── PairingCheck.scala │ └── test │ └── scala │ └── io │ └── iohk │ └── ethereum │ └── crypto │ ├── AesCbcSpec.scala │ ├── AesCtrSpec.scala │ ├── ECDSASignatureSpec.scala │ ├── ECIESCoderSpec.scala │ ├── Generators.scala │ ├── Pbkdf2HMacSha256Spec.scala │ ├── Ripemd160Spec.scala │ ├── ScryptSpec.scala │ ├── SecureRandomBuilder.scala │ └── zksnarks │ ├── BN128FpSpec.scala │ └── FpFieldSpec.scala ├── default.nix ├── docker ├── Dockerfile ├── Dockerfile-base ├── Dockerfile-dev ├── besu │ ├── README.md │ ├── docker-compose.yml │ ├── grafana │ │ └── provisioning │ │ │ ├── dashboards │ │ │ ├── besu-dashboard.json │ │ │ └── dashboard.yml │ │ │ └── datasources │ │ │ └── datasource.yml │ ├── prometheus │ │ └── prometheus.yml │ └── runBesu.sh ├── build-base.sh ├── build-dev.sh ├── build.sh ├── buildhelper.sh ├── geth │ ├── README.md │ ├── docker-compose.yml │ ├── grafana │ │ └── provisioning │ │ │ ├── dashboards │ │ │ ├── dashboard.yml │ │ │ └── geth-dashboard.json │ │ │ └── datasources │ │ │ └── datasource.yml │ ├── prometheus │ │ └── prometheus.yml │ └── runGeth.sh ├── mantis │ ├── build.sh │ ├── docker-compose.yml │ ├── grafana │ │ └── provisioning │ │ │ ├── dashboards │ │ │ ├── dashboard.yml │ │ │ └── mantis-dashboard.json │ │ │ └── datasources │ │ │ └── datasource.yml │ └── prometheus │ │ └── prometheus.yml └── scripts │ ├── install-base-system.sh │ ├── install-mantis-dev.sh │ ├── install-mantis.sh │ ├── install-nix-apps-base.sh │ ├── install-nix-apps-dev.sh │ └── install-nix-common.sh ├── ets ├── README.md ├── config │ ├── mantis │ │ ├── config │ │ └── genesis │ │ │ ├── Berlin.json │ │ │ ├── BerlinToLondonAt5.json │ │ │ ├── Byzantium.json │ │ │ ├── ByzantiumToConstantinopleFixAt5.json │ │ │ ├── Constantinople.json │ │ │ ├── ConstantinopleFix.json │ │ │ ├── EIP150.json │ │ │ ├── EIP158.json │ │ │ ├── EIP158ToByzantiumAt5.json │ │ │ ├── Frontier.json │ │ │ ├── FrontierToHomesteadAt5.json │ │ │ ├── Homestead.json │ │ │ ├── HomesteadToDaoAt5.json │ │ │ ├── HomesteadToEIP150At5.json │ │ │ ├── Istanbul.json │ │ │ ├── London.json │ │ │ └── correctMiningReward.json │ └── version ├── retesteth └── run ├── flake.lock ├── flake.nix ├── insomnia_workspace.json ├── nix-in-docker ├── nix.conf └── run ├── nix ├── default.nix ├── entrypoint.sh ├── lllc.nix ├── mantis.nix ├── overlay.nix ├── pkgs │ └── nginx.nix ├── protoc.patch ├── retesteth.nix ├── sources.json └── sources.nix ├── project ├── Dependencies.scala ├── SolidityPlugin.scala ├── build.properties ├── manual-repo.nix ├── plugins.sbt └── scalapb.sbt ├── release.nix ├── rlp └── src │ ├── main │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ └── rlp │ │ ├── RLP.scala │ │ ├── RLPImplicitConversions.scala │ │ ├── RLPImplicitDerivations.scala │ │ ├── RLPImplicits.scala │ │ └── package.scala │ └── test │ └── scala │ └── io │ └── iohk │ └── ethereum │ └── rlp │ └── RLPSuite.scala ├── scalastyle-config.xml ├── scalastyle-test-config.xml ├── shell.nix ├── src ├── benchmark │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ ├── mpt │ │ └── MerklePatriciaTreeSpeedSpec.scala │ │ └── rlp │ │ └── RLPSpeedSuite.scala ├── ets │ └── README.md ├── evmTest │ ├── resources │ │ └── solidity │ │ │ ├── CallSelfDestruct.sol │ │ │ ├── Caller.sol │ │ │ ├── ContractCallingItself.sol │ │ │ ├── Fibonacci.sol │ │ │ ├── MinimumViableToken.sol │ │ │ ├── MutualRecursion.sol │ │ │ ├── PrecompiledContracts.sol │ │ │ └── Throw.sol │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ └── vm │ │ ├── CallSelfDestructSpec.scala │ │ ├── CallerSpec.scala │ │ ├── ContractCallingItselfSpec.scala │ │ ├── FibonacciSpec.scala │ │ ├── MinimumViableTokenSpec.scala │ │ ├── MutualRecursionSpec.scala │ │ ├── PrecompiledContractsSpecEvm.scala │ │ ├── ThrowSpec.scala │ │ └── utils │ │ ├── ABI.scala │ │ ├── EvmTestEnv.scala │ │ └── Utils.scala ├── it │ ├── resources │ │ ├── logback-test.xml │ │ └── txExecTest │ │ │ ├── chainDump.conf │ │ │ ├── documentation │ │ │ ├── ForksTestContract.sol │ │ │ ├── contract.sol │ │ │ ├── keys │ │ │ │ └── Morden │ │ │ │ │ ├── UTC--2017-03-30T13-06-44Z--a9d65fec-d670-1470-9ba1-72b7c3d662f8 │ │ │ │ │ ├── UTC--2017-03-30T15-27-28Z--301e308a-bd95-4334-9b13-b12bc21d2876 │ │ │ │ │ └── UTC--2017-04-03T13-49-13Z--c703a1ec-96ea-305a-717f-3a65269c472d │ │ │ ├── prv.json │ │ │ └── readme.md │ │ │ ├── ecip1017Test │ │ │ ├── bodies.txt │ │ │ ├── contractTrees.txt │ │ │ ├── evmCode.txt │ │ │ ├── headers.txt │ │ │ ├── receipts.txt │ │ │ └── stateTree.txt │ │ │ ├── forksTest │ │ │ ├── bodies.txt │ │ │ ├── contractTrees.txt │ │ │ ├── evmCode.txt │ │ │ ├── headers.txt │ │ │ ├── receipts.txt │ │ │ └── stateTree.txt │ │ │ └── purchaseContract │ │ │ ├── bodies.txt │ │ │ ├── contractTrees.txt │ │ │ ├── evmCode.txt │ │ │ ├── headers.txt │ │ │ ├── receipts.txt │ │ │ └── stateTree.txt │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ ├── db │ │ ├── DataSourceIntegrationTestBehavior.scala │ │ ├── RockDbIteratorSpec.scala │ │ └── RocksDbDataSourceIntegrationSuite.scala │ │ ├── ledger │ │ └── BlockImporterItSpec.scala │ │ ├── mpt │ │ └── MerklePatriciaTreeIntegrationSuite.scala │ │ ├── sync │ │ ├── FastSyncItSpec.scala │ │ ├── RegularSyncItSpec.scala │ │ └── util │ │ │ ├── CommonFakePeer.scala │ │ │ ├── FastSyncItSpecUtils.scala │ │ │ ├── RegularSyncItSpecUtils.scala │ │ │ ├── SyncCommonItSpec.scala │ │ │ └── SyncCommonItSpecUtils.scala │ │ └── txExecTest │ │ ├── ContractTest.scala │ │ ├── ECIP1017Test.scala │ │ ├── ForksTest.scala │ │ ├── ScenarioSetup.scala │ │ └── util │ │ ├── DumpChainActor.scala │ │ ├── DumpChainApp.scala │ │ └── FixtureProvider.scala ├── main │ ├── resources │ │ ├── application.conf │ │ ├── blockchain │ │ │ └── default-genesis.json │ │ ├── conf │ │ │ ├── app.conf │ │ │ ├── base-testnet.conf │ │ │ ├── base.conf │ │ │ ├── chains │ │ │ │ ├── etc-chain.conf │ │ │ │ ├── eth-chain.conf │ │ │ │ ├── mordor-chain.conf │ │ │ │ ├── mordor-genesis.json │ │ │ │ ├── pottery-chain.conf │ │ │ │ ├── pottery-genesis.json │ │ │ │ ├── ropsten-chain.conf │ │ │ │ ├── ropsten-genesis.json │ │ │ │ ├── test-chain.conf │ │ │ │ ├── testnet-allowed-miners.json │ │ │ │ ├── testnet-internal-nomad-chain.conf │ │ │ │ └── testnet-internal-nomad-genesis.json │ │ │ ├── etc.conf │ │ │ ├── eth.conf │ │ │ ├── faucet.conf │ │ │ ├── metrics.conf │ │ │ ├── mordor.conf │ │ │ ├── pottery.conf │ │ │ ├── sagano.conf │ │ │ ├── testmode.conf │ │ │ └── testnet-internal-nomad.conf │ │ ├── logback.xml │ │ └── mallet.conf │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ ├── App.scala │ │ ├── BootstrapDownload.scala │ │ ├── KeyTool.scala │ │ ├── Mantis.scala │ │ ├── blockchain │ │ ├── data │ │ │ ├── GenesisDataLoader.scala │ │ │ └── genesis.scala │ │ └── sync │ │ │ ├── Blacklist.scala │ │ │ ├── BlockchainHostActor.scala │ │ │ ├── PeerComparator.scala │ │ │ ├── PeerListSupportNg.scala │ │ │ ├── PeerRequestHandler.scala │ │ │ ├── PeersClient.scala │ │ │ ├── SyncController.scala │ │ │ ├── SyncProtocol.scala │ │ │ ├── fast │ │ │ ├── DownloaderState.scala │ │ │ ├── FastSync.scala │ │ │ ├── FastSyncBranchResolver.scala │ │ │ ├── FastSyncBranchResolverActor.scala │ │ │ ├── FastSyncMetrics.scala │ │ │ ├── HeaderSkeleton.scala │ │ │ ├── LoadableBloomFilter.scala │ │ │ ├── PivotBlockSelector.scala │ │ │ ├── ReceiptsValidator.scala │ │ │ ├── StateStorageActor.scala │ │ │ ├── SyncBlocksValidator.scala │ │ │ ├── SyncSchedulerActorState.scala │ │ │ ├── SyncStateScheduler.scala │ │ │ └── SyncStateSchedulerActor.scala │ │ │ └── regular │ │ │ ├── BlockBroadcast.scala │ │ │ ├── BlockBroadcasterActor.scala │ │ │ ├── BlockFetcher.scala │ │ │ ├── BlockFetcherState.scala │ │ │ ├── BlockImportResult.scala │ │ │ ├── BlockImporter.scala │ │ │ ├── BodiesFetcher.scala │ │ │ ├── FetchRequest.scala │ │ │ ├── HeadersFetcher.scala │ │ │ ├── ImportMessages.scala │ │ │ ├── RegularSync.scala │ │ │ ├── RegularSyncMetrics.scala │ │ │ └── StateNodeFetcher.scala │ │ ├── cli │ │ ├── CliCommands.scala │ │ └── CliLauncher.scala │ │ ├── common │ │ └── SimpleMap.scala │ │ ├── consensus │ │ ├── Consensus.scala │ │ ├── ConsensusAdapter.scala │ │ ├── ConsensusImpl.scala │ │ ├── blocks │ │ │ ├── BlockGenerator.scala │ │ │ ├── BlockGeneratorSkeleton.scala │ │ │ ├── BlockTimestampProvider.scala │ │ │ ├── CheckpointBlockGenerator.scala │ │ │ ├── NoOmmersBlockGenerator.scala │ │ │ └── package.scala │ │ ├── difficulty │ │ │ └── DifficultyCalculator.scala │ │ ├── mining │ │ │ ├── FullMiningConfig.scala │ │ │ ├── Mining.scala │ │ │ ├── MiningBuilder.scala │ │ │ ├── MiningConfig.scala │ │ │ ├── MiningConfigBuilder.scala │ │ │ ├── MiningMetrics.scala │ │ │ ├── Protocol.scala │ │ │ ├── TestMiningBuilder.scala │ │ │ └── package.scala │ │ ├── pow │ │ │ ├── EthashConfig.scala │ │ │ ├── EthashUtils.scala │ │ │ ├── KeccakCalculation.scala │ │ │ ├── PoWBlockCreator.scala │ │ │ ├── PoWMining.scala │ │ │ ├── PoWMiningCoordinator.scala │ │ │ ├── RestrictedPoWSigner.scala │ │ │ ├── blocks │ │ │ │ ├── PoWBlockGenerator.scala │ │ │ │ ├── RestrictedPoWBlockGeneratorImpl.scala │ │ │ │ └── package.scala │ │ │ ├── difficulty │ │ │ │ ├── EthashDifficultyCalculator.scala │ │ │ │ └── TargetTimeDifficultyCalculator.scala │ │ │ ├── miners │ │ │ │ ├── EthashDAGManager.scala │ │ │ │ ├── EthashMiner.scala │ │ │ │ ├── KeccakMiner.scala │ │ │ │ ├── Miner.scala │ │ │ │ ├── MinerProtocol.scala │ │ │ │ └── MockedMiner.scala │ │ │ └── validators │ │ │ │ ├── EthashBlockHeaderValidator.scala │ │ │ │ ├── KeccakBlockHeaderValidator.scala │ │ │ │ ├── MockedPowBlockHeaderValidator.scala │ │ │ │ ├── OmmersValidator.scala │ │ │ │ ├── PoWBlockHeaderValidator.scala │ │ │ │ ├── RestrictedEthashBlockHeaderValidator.scala │ │ │ │ ├── StdOmmersValidator.scala │ │ │ │ ├── StdValidatorsExecutor.scala │ │ │ │ └── ValidatorsExecutor.scala │ │ └── validators │ │ │ ├── BlockHeaderValidator.scala │ │ │ ├── BlockHeaderValidatorSkeleton.scala │ │ │ ├── BlockValidator.scala │ │ │ ├── BlockWithCheckpointHeaderValidator.scala │ │ │ ├── SignedTransactionValidator.scala │ │ │ ├── Validators.scala │ │ │ └── std │ │ │ ├── MptListValidator.scala │ │ │ ├── StdBlockValidator.scala │ │ │ ├── StdSignedTransactionValidator.scala │ │ │ └── StdValidators.scala │ │ ├── crypto │ │ ├── ECDSASignatureImplicits.scala │ │ ├── EcKeyGen.scala │ │ └── SignatureValidator.scala │ │ ├── db │ │ ├── cache │ │ │ ├── AppCaches.scala │ │ │ ├── Cache.scala │ │ │ ├── CacheComponent.scala │ │ │ ├── LruCache.scala │ │ │ └── MapCache.scala │ │ ├── components │ │ │ ├── DataSourceComponent.scala │ │ │ ├── EphemDataSourceComponent.scala │ │ │ ├── RocksDbDataSourceComponent.scala │ │ │ ├── Storages.scala │ │ │ └── StoragesComponent.scala │ │ ├── dataSource │ │ │ ├── DataSource.scala │ │ │ ├── DataSourceBatchUpdate.scala │ │ │ ├── DataSourceUpdate.scala │ │ │ ├── EphemDataSource.scala │ │ │ └── RocksDbDataSource.scala │ │ └── storage │ │ │ ├── AppStateStorage.scala │ │ │ ├── ArchiveNodeStorage.scala │ │ │ ├── BlockBodiesStorage.scala │ │ │ ├── BlockHeadersStorage.scala │ │ │ ├── BlockNumberMappingStorage.scala │ │ │ ├── CachedKeyValueStorage.scala │ │ │ ├── CachedReferenceCountedStorage.scala │ │ │ ├── ChainWeightStorage.scala │ │ │ ├── EvmCodeStorage.scala │ │ │ ├── FastSyncNodeStorage.scala │ │ │ ├── FastSyncStateStorage.scala │ │ │ ├── KeyValueStorage.scala │ │ │ ├── KnownNodesStorage.scala │ │ │ ├── MptStorage.scala │ │ │ ├── Namespaces.scala │ │ │ ├── NodeStorage.scala │ │ │ ├── ReadOnlyNodeStorage.scala │ │ │ ├── ReceiptStorage.scala │ │ │ ├── ReferenceCountNodeStorage.scala │ │ │ ├── StateStorage.scala │ │ │ ├── StorageStringCharset.scala │ │ │ ├── TransactionMappingStorage.scala │ │ │ ├── TransactionalKeyValueStorage.scala │ │ │ ├── encoding │ │ │ └── package.scala │ │ │ └── pruning │ │ │ └── package.scala │ │ ├── domain │ │ ├── Account.scala │ │ ├── Address.scala │ │ ├── Block.scala │ │ ├── BlockBody.scala │ │ ├── BlockHeader.scala │ │ ├── Blockchain.scala │ │ ├── BlockchainReader.scala │ │ ├── BlockchainWriter.scala │ │ ├── ChainWeight.scala │ │ ├── Checkpoint.scala │ │ ├── HeadersSeq.scala │ │ ├── Receipt.scala │ │ ├── SignedTransaction.scala │ │ ├── Transaction.scala │ │ ├── TransactionOutcome.scala │ │ ├── TxLogEntry.scala │ │ ├── UInt256.scala │ │ ├── appstate │ │ │ └── BlockInfo.scala │ │ ├── branch │ │ │ └── Branch.scala │ │ └── package.scala │ │ ├── extvm │ │ ├── ApiVersionProvider.scala │ │ ├── ExtVMInterface.scala │ │ ├── Implicits.scala │ │ ├── MessageHandler.scala │ │ ├── Storage.scala │ │ ├── VMClient.scala │ │ ├── VMServer.scala │ │ ├── World.scala │ │ ├── cache.scala │ │ └── package.scala │ │ ├── faucet │ │ ├── Faucet.scala │ │ ├── FaucetConfig.scala │ │ ├── FaucetHandler.scala │ │ ├── FaucetSupervisor.scala │ │ ├── SupervisorConfig.scala │ │ ├── jsonrpc │ │ │ ├── FaucetBuilder.scala │ │ │ ├── FaucetDomain.scala │ │ │ ├── FaucetHandlerSelector.scala │ │ │ ├── FaucetJsonRpcController.scala │ │ │ ├── FaucetJsonRpcHealthCheck.scala │ │ │ ├── FaucetMethodsImplicits.scala │ │ │ ├── FaucetRpcService.scala │ │ │ ├── WalletRpcClient.scala │ │ │ └── WalletService.scala │ │ └── package.scala │ │ ├── forkid │ │ ├── ForkId.scala │ │ └── ForkIdValidator.scala │ │ ├── healthcheck │ │ ├── HealthcheckResponse.scala │ │ ├── HealthcheckResult.scala │ │ └── HealthcheckStatus.scala │ │ ├── jsonrpc │ │ ├── AkkaTaskOps.scala │ │ ├── BlockResponse.scala │ │ ├── CheckpointingJsonMethodsImplicits.scala │ │ ├── CheckpointingService.scala │ │ ├── DebugJsonMethodsImplicits.scala │ │ ├── DebugService.scala │ │ ├── EthBlocksJsonMethodsImplicits.scala │ │ ├── EthBlocksService.scala │ │ ├── EthFilterJsonMethodsImplicits.scala │ │ ├── EthFilterService.scala │ │ ├── EthInfoJsonMethodsImplicits.scala │ │ ├── EthInfoService.scala │ │ ├── EthMiningJsonMethodsImplicits.scala │ │ ├── EthMiningService.scala │ │ ├── EthProofJsonMethodsImplicits.scala │ │ ├── EthProofService.scala │ │ ├── EthTxJsonMethodsImplicits.scala │ │ ├── EthTxService.scala │ │ ├── EthUserJsonMethodsImplicits.scala │ │ ├── EthUserService.scala │ │ ├── ExpiringMap.scala │ │ ├── FilterManager.scala │ │ ├── IeleJsonMethodsImplicits.scala │ │ ├── JsonMethodsImplicits.scala │ │ ├── JsonRpcController.scala │ │ ├── JsonRpcControllerMetrics.scala │ │ ├── JsonRpcError.scala │ │ ├── JsonRpcHealthChecker.scala │ │ ├── JsonRpcHealthcheck.scala │ │ ├── JsonRpcRequest.scala │ │ ├── JsonRpcResponse.scala │ │ ├── MantisJsonMethodImplicits.scala │ │ ├── MantisService.scala │ │ ├── NetService.scala │ │ ├── NodeJsonRpcHealthChecker.scala │ │ ├── PersonalService.scala │ │ ├── QAJsonMethodsImplicits.scala │ │ ├── QAService.scala │ │ ├── RawTransactionCodec.scala │ │ ├── ResolveBlock.scala │ │ ├── TestJsonMethodsImplicits.scala │ │ ├── TestService.scala │ │ ├── TransactionReceiptResponse.scala │ │ ├── TransactionRequest.scala │ │ ├── TransactionResponse.scala │ │ ├── Web3Service.scala │ │ ├── client │ │ │ ├── CommonJsonCodecs.scala │ │ │ └── RpcClient.scala │ │ ├── package.scala │ │ ├── serialization │ │ │ ├── JsonEncoder.scala │ │ │ ├── JsonMethodCodec.scala │ │ │ ├── JsonMethodDecoder.scala │ │ │ └── JsonSerializers.scala │ │ └── server │ │ │ ├── controllers │ │ │ └── JsonRpcBaseController.scala │ │ │ ├── http │ │ │ ├── InsecureJsonRpcHttpServer.scala │ │ │ ├── JsonRpcHttpServer.scala │ │ │ ├── RateLimit.scala │ │ │ └── SecureJsonRpcHttpServer.scala │ │ │ └── ipc │ │ │ └── JsonRpcIpcServer.scala │ │ ├── keystore │ │ ├── EncryptedKey.scala │ │ ├── EncryptedKeyJsonCodec.scala │ │ ├── KeyStore.scala │ │ └── Wallet.scala │ │ ├── ledger │ │ ├── BlockData.scala │ │ ├── BlockExecution.scala │ │ ├── BlockMetrics.scala │ │ ├── BlockPreparator.scala │ │ ├── BlockQueue.scala │ │ ├── BlockResult.scala │ │ ├── BlockRewardCalculator.scala │ │ ├── BlockValidation.scala │ │ ├── BloomFilter.scala │ │ ├── BranchResolution.scala │ │ ├── InMemorySimpleMapProxy.scala │ │ ├── InMemoryWorldStateProxy.scala │ │ ├── LocalVM.scala │ │ ├── PreparedBlock.scala │ │ ├── StxLedger.scala │ │ ├── TxResult.scala │ │ └── package.scala │ │ ├── logger │ │ └── LoggingMailbox.scala │ │ ├── metrics │ │ ├── AppJmxConfig.scala │ │ ├── DeltaSpikeGauge.scala │ │ ├── MeterRegistryBuilder.scala │ │ ├── Metrics.scala │ │ ├── MetricsAlreadyConfiguredError.scala │ │ ├── MetricsConfig.scala │ │ ├── MetricsContainer.scala │ │ └── MetricsUtils.scala │ │ ├── mpt │ │ ├── HashByteArraySerializable.scala │ │ ├── HexPrefix.scala │ │ ├── MerklePatriciaTrie.scala │ │ ├── MptTraversals.scala │ │ ├── MptVisitors │ │ │ ├── MptConstructionVisitor.scala │ │ │ ├── MptVisitor.scala │ │ │ ├── RlpEncVisitor.scala │ │ │ └── RlpHashingVisitor.scala │ │ ├── Node.scala │ │ └── package.scala │ │ ├── network │ │ ├── ConnectedPeers.scala │ │ ├── EtcPeerManagerActor.scala │ │ ├── ForkResolver.scala │ │ ├── KnownNodesManager.scala │ │ ├── NetworkMetrics.scala │ │ ├── Peer.scala │ │ ├── PeerActor.scala │ │ ├── PeerEventBusActor.scala │ │ ├── PeerManagerActor.scala │ │ ├── PeerStat.scala │ │ ├── PeerStatisticsActor.scala │ │ ├── PortForwarder.scala │ │ ├── ServerActor.scala │ │ ├── TimeSlotStats.scala │ │ ├── discovery │ │ │ ├── DiscoveryConfig.scala │ │ │ ├── DiscoveryServiceBuilder.scala │ │ │ ├── Node.scala │ │ │ ├── PeerDiscoveryManager.scala │ │ │ ├── Secp256k1SigAlg.scala │ │ │ └── codecs │ │ │ │ └── RLPCodecs.scala │ │ ├── handshaker │ │ │ ├── EtcForkBlockExchangeState.scala │ │ │ ├── EtcHandshaker.scala │ │ │ ├── EtcHelloExchangeState.scala │ │ │ ├── EtcNodeStatus64ExchangeState.scala │ │ │ ├── EtcNodeStatusExchangeState.scala │ │ │ ├── EthNodeStatus63ExchangeState.scala │ │ │ ├── EthNodeStatus64ExchangeState.scala │ │ │ ├── Handshaker.scala │ │ │ └── HandshakerState.scala │ │ ├── p2p │ │ │ ├── Message.scala │ │ │ ├── MessageDecoders.scala │ │ │ ├── MessageSerializableImplicit.scala │ │ │ └── messages │ │ │ │ ├── BaseETH6XMessages.scala │ │ │ │ ├── Capability.scala │ │ │ │ ├── ETC64.scala │ │ │ │ ├── ETH61.scala │ │ │ │ ├── ETH62.scala │ │ │ │ ├── ETH63.scala │ │ │ │ ├── ETH64.scala │ │ │ │ ├── WireProtocol.scala │ │ │ │ └── package.scala │ │ ├── package.scala │ │ └── rlpx │ │ │ ├── AuthHandshaker.scala │ │ │ ├── AuthInitiateEcdsaCodec.scala │ │ │ ├── AuthInitiateMessage.scala │ │ │ ├── AuthInitiateMessageV4.scala │ │ │ ├── AuthResponseMessage.scala │ │ │ ├── AuthResponseMessageV4.scala │ │ │ ├── FrameCodec.scala │ │ │ ├── MessageCodec.scala │ │ │ └── RLPxConnectionHandler.scala │ │ ├── nodebuilder │ │ ├── NodeBuilder.scala │ │ ├── StdNode.scala │ │ ├── TestNode.scala │ │ ├── VmSetup.scala │ │ └── tooling │ │ │ ├── PeriodicConsistencyCheck.scala │ │ │ └── StorageConsistencyChecker.scala │ │ ├── ommers │ │ └── OmmersPool.scala │ │ ├── rlp │ │ └── UInt256RLPImplicits.scala │ │ ├── security │ │ ├── FileUtils.scala │ │ ├── KeyStoreUtils.scala │ │ ├── SSLConfig.scala │ │ ├── SSLContextBuilder.scala │ │ ├── SSLContextFactory.scala │ │ └── SecureRandomBuilder.scala │ │ ├── testmode │ │ ├── SealEngineType.scala │ │ ├── TestEthBlockServiceWrapper.scala │ │ ├── TestModeBlockExecution.scala │ │ ├── TestModeComponentsProvider.scala │ │ ├── TestModeWorldStateProxy.scala │ │ └── TestmodeMining.scala │ │ ├── transactions │ │ ├── PendingTransactionsManager.scala │ │ ├── SignedTransactionsFilterActor.scala │ │ ├── TransactionHistoryService.scala │ │ └── TransactionPicker.scala │ │ ├── utils │ │ ├── BigIntExtensionMethods.scala │ │ ├── BlockchainConfig.scala │ │ ├── Config.scala │ │ ├── ConfigUtils.scala │ │ ├── FunctorOps.scala │ │ ├── LoadFromApplicationConfiguration.scala │ │ ├── Logger.scala │ │ ├── LoggerUtils.scala │ │ ├── NodeStatus.scala │ │ ├── NumericUtils.scala │ │ ├── Picklers.scala │ │ ├── Ref.scala │ │ ├── StringUtils.scala │ │ ├── TryWithResources.scala │ │ ├── ValidationUtils.scala │ │ └── VersionInfo.scala │ │ └── vm │ │ ├── Blake2bCompression.scala │ │ ├── BlockchainConfigForEvm.scala │ │ ├── EvmConfig.scala │ │ ├── ExecEnv.scala │ │ ├── InternalTransaction.scala │ │ ├── Memory.scala │ │ ├── OpCode.scala │ │ ├── PrecompiledContracts.scala │ │ ├── Program.scala │ │ ├── ProgramContext.scala │ │ ├── ProgramError.scala │ │ ├── ProgramResult.scala │ │ ├── ProgramState.scala │ │ ├── Stack.scala │ │ ├── Storage.scala │ │ ├── VM.scala │ │ ├── WorldStateProxy.scala │ │ └── package.scala ├── rpcTest │ ├── README.md │ ├── resources │ │ ├── patch-mantis │ │ ├── privateNetConfig │ │ │ ├── conf │ │ │ │ ├── application.ini │ │ │ │ ├── rpc-test-logback.xml │ │ │ │ ├── rpc-test-private-genesis.json │ │ │ │ └── rpc-test-private.conf │ │ │ └── keystore │ │ │ │ ├── UTC--2018-05-30T07-16-33.631Z--316158e265fa708c623cc3094b2bb5889e0f5ca5 │ │ │ │ ├── UTC--2018-05-30T07-16-58.64Z--b9ec69316a8810db91c36de79c4f1e785f2c35fc │ │ │ │ ├── UTC--2018-05-30T07-17-03.455Z--488c10c91771d3b3c25f63b6414309b119baacb5 │ │ │ │ └── UTC--2018-06-01T10-10-01.852779Z--03010360ebbb7f49362a2c650a67661d464e2089 │ │ └── test.conf │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ └── rpcTest │ │ ├── RpcApiTests.scala │ │ ├── RpcTestConfig.scala │ │ ├── Tags.scala │ │ ├── TestContracts.scala │ │ └── TestData.scala ├── test │ ├── resources │ │ ├── application.conf │ │ ├── block.go.snappy │ │ ├── block.py.snappy │ │ ├── downloadtest.zip │ │ ├── explicit-scheduler.conf │ │ ├── logback-test.xml │ │ ├── rnd.sh │ │ ├── test-genesis-treasury.json │ │ └── test-genesis.json │ └── scala │ │ └── io │ │ └── iohk │ │ └── ethereum │ │ ├── BlockHelpers.scala │ │ ├── BootstrapDownloadSpec.scala │ │ ├── ByteGenerators.scala │ │ ├── Fixtures.scala │ │ ├── Mocks.scala │ │ ├── ObjectGenerators.scala │ │ ├── SpecBase.scala │ │ ├── SuperSlow.scala │ │ ├── Timeouts.scala │ │ ├── WithActorSystemShutDown.scala │ │ ├── blockchain │ │ └── sync │ │ │ ├── BlockBroadcastSpec.scala │ │ │ ├── BlockchainHostActorSpec.scala │ │ │ ├── CacheBasedBlacklistSpec.scala │ │ │ ├── EphemBlockchainTestSetup.scala │ │ │ ├── EtcPeerManagerFake.scala │ │ │ ├── FastSyncSpec.scala │ │ │ ├── LoadableBloomFilterSpec.scala │ │ │ ├── PeersClientSpec.scala │ │ │ ├── PivotBlockSelectorSpec.scala │ │ │ ├── ScenarioSetup.scala │ │ │ ├── SchedulerStateSpec.scala │ │ │ ├── StateStorageActorSpec.scala │ │ │ ├── StateSyncSpec.scala │ │ │ ├── StateSyncUtils.scala │ │ │ ├── SyncControllerSpec.scala │ │ │ ├── SyncStateDownloaderStateSpec.scala │ │ │ ├── SyncStateSchedulerSpec.scala │ │ │ ├── TestSyncConfig.scala │ │ │ ├── TestSyncPeers.scala │ │ │ ├── fast │ │ │ ├── FastSyncBranchResolverActorSpec.scala │ │ │ ├── FastSyncBranchResolverSpec.scala │ │ │ └── HeaderSkeletonSpec.scala │ │ │ └── regular │ │ │ ├── BlockFetcherSpec.scala │ │ │ ├── BlockFetcherStateSpec.scala │ │ │ ├── RegularSyncFixtures.scala │ │ │ └── RegularSyncSpec.scala │ │ ├── checkpointing │ │ └── CheckpointingTestHelpers.scala │ │ ├── cli │ │ └── CliCommandsSpec.scala │ │ ├── consensus │ │ ├── ConsensusAdapterSpec.scala │ │ ├── ConsensusImplSpec.scala │ │ ├── blocks │ │ │ ├── BlockGeneratorSpec.scala │ │ │ └── CheckpointBlockGeneratorSpec.scala │ │ ├── mining │ │ │ ├── MiningConfigs.scala │ │ │ └── MiningSpec.scala │ │ ├── pow │ │ │ ├── EthashUtilsSpec.scala │ │ │ ├── KeccakCalculationSpec.scala │ │ │ ├── KeccakDataUtils.scala │ │ │ ├── MinerSpecSetup.scala │ │ │ ├── PoWMiningCoordinatorSpec.scala │ │ │ ├── PoWMiningSpec.scala │ │ │ ├── RestrictedEthashSignerSpec.scala │ │ │ ├── miners │ │ │ │ ├── EthashMinerSpec.scala │ │ │ │ ├── KeccakMinerSpec.scala │ │ │ │ └── MockedMinerSpec.scala │ │ │ └── validators │ │ │ │ ├── EthashBlockHeaderValidatorSpec.scala │ │ │ │ ├── KeccakBlockHeaderValidatorSpec.scala │ │ │ │ ├── PoWBlockHeaderValidatorSpec.scala │ │ │ │ ├── RestrictedEthashBlockHeaderValidatorSpec.scala │ │ │ │ └── StdOmmersValidatorSpec.scala │ │ └── validators │ │ │ ├── BlockWithCheckpointHeaderValidatorSpec.scala │ │ │ └── std │ │ │ ├── StdBlockValidatorSpec.scala │ │ │ └── StdSignedLegacyTransactionValidatorSpec.scala │ │ ├── db │ │ ├── dataSource │ │ │ ├── DataSourceTestBehavior.scala │ │ │ ├── EphemDataSourceSuite.scala │ │ │ └── RocksDbDataSourceTest.scala │ │ └── storage │ │ │ ├── AppStateStorageSpec.scala │ │ │ ├── BlockBodiesStorageSpec.scala │ │ │ ├── BlockHeadersStorageSpec.scala │ │ │ ├── CachedNodeStorageSpec.scala │ │ │ ├── CachedReferenceCountedStorageSpec.scala │ │ │ ├── ChainWeightStorageSuite.scala │ │ │ ├── CodeStorageSuite.scala │ │ │ ├── KeyValueStorageSuite.scala │ │ │ ├── LegacyTransactionMappingStorageSuite.scala │ │ │ ├── NodeStorageSuite.scala │ │ │ ├── ReadOnlyNodeStorageSpec.scala │ │ │ ├── ReceiptStorageSuite.scala │ │ │ ├── ReferenceCountNodeStorageSpec.scala │ │ │ ├── StateStorageSpec.scala │ │ │ └── TransactionalKeyValueStorageSuite.scala │ │ ├── domain │ │ ├── ArbitraryIntegerMptSpec.scala │ │ ├── BlockHeaderSpec.scala │ │ ├── BlockSpec.scala │ │ ├── BlockchainReaderSpec.scala │ │ ├── BlockchainSpec.scala │ │ ├── SignedLegacyTransactionSpec.scala │ │ ├── SignedTransactionBehavior.scala │ │ ├── SignedTransactionWithAccessListSpec.scala │ │ ├── TransactionSpec.scala │ │ └── UInt256Spec.scala │ │ ├── extvm │ │ ├── MessageHandlerSpec.scala │ │ ├── VMClientSpec.scala │ │ ├── VMServerSpec.scala │ │ └── WorldSpec.scala │ │ ├── faucet │ │ ├── FaucetHandlerSpec.scala │ │ └── jsonrpc │ │ │ ├── FaucetRpcServiceSpec.scala │ │ │ └── WalletServiceSpec.scala │ │ ├── forkid │ │ ├── ForkIdSpec.scala │ │ └── ForkIdValidatorSpec.scala │ │ ├── jsonrpc │ │ ├── CheckpointingJRCSpec.scala │ │ ├── CheckpointingServiceSpec.scala │ │ ├── DebugServiceSpec.scala │ │ ├── EthBlocksServiceSpec.scala │ │ ├── EthFilterServiceSpec.scala │ │ ├── EthInfoServiceSpec.scala │ │ ├── EthMiningServiceSpec.scala │ │ ├── EthProofServiceSpec.scala │ │ ├── EthTxServiceSpec.scala │ │ ├── EthUserServiceSpec.scala │ │ ├── ExpiringMapSpec.scala │ │ ├── FilterManagerSpec.scala │ │ ├── JRCMatchers.scala │ │ ├── JsonRpcControllerEthLegacyTransactionSpec.scala │ │ ├── JsonRpcControllerEthSpec.scala │ │ ├── JsonRpcControllerFixture.scala │ │ ├── JsonRpcControllerPersonalSpec.scala │ │ ├── JsonRpcControllerSpec.scala │ │ ├── MantisJRCSpec.scala │ │ ├── MantisServiceSpec.scala │ │ ├── NetServiceSpec.scala │ │ ├── PersonalServiceSpec.scala │ │ ├── ProofServiceDummy.scala │ │ ├── QAServiceSpec.scala │ │ ├── QaJRCSpec.scala │ │ └── server │ │ │ └── http │ │ │ └── JsonRpcHttpServerSpec.scala │ │ ├── keystore │ │ ├── EncryptedKeySpec.scala │ │ └── KeyStoreImplSpec.scala │ │ ├── ledger │ │ ├── BlockExecutionSpec.scala │ │ ├── BlockPreparatorSpec.scala │ │ ├── BlockQueueSpec.scala │ │ ├── BlockRewardCalculatorOps.scala │ │ ├── BlockRewardCalculatorSpec.scala │ │ ├── BlockRewardSpec.scala │ │ ├── BlockValidationSpec.scala │ │ ├── BloomFilterSpec.scala │ │ ├── BranchResolutionSpec.scala │ │ ├── DeleteAccountsSpec.scala │ │ ├── DeleteTouchedAccountsSpec.scala │ │ ├── InMemorySimpleMapProxySpec.scala │ │ ├── InMemoryWorldStateProxySpec.scala │ │ ├── LedgerTestSetup.scala │ │ └── StxLedgerSpec.scala │ │ ├── mpt │ │ ├── HexPrefixSuite.scala │ │ ├── MerklePatriciaTrieSuite.scala │ │ └── PersistentStorage.scala │ │ ├── network │ │ ├── AsymmetricCipherKeyPairLoaderSpec.scala │ │ ├── AuthHandshakerSpec.scala │ │ ├── AuthInitiateMessageSpec.scala │ │ ├── EtcPeerManagerSpec.scala │ │ ├── KnownNodesManagerSpec.scala │ │ ├── NodeParserSpec.scala │ │ ├── PeerActorHandshakingSpec.scala │ │ ├── PeerEventBusActorSpec.scala │ │ ├── PeerManagerSpec.scala │ │ ├── PeerStatisticsSpec.scala │ │ ├── TimeSlotStatsSpec.scala │ │ ├── discovery │ │ │ ├── PeerDiscoveryManagerSpec.scala │ │ │ ├── Secp256k1SigAlgSpec.scala │ │ │ └── codecs │ │ │ │ ├── EIP8CodecsSpec.scala │ │ │ │ ├── ENRCodecsSpec.scala │ │ │ │ └── RLPCodecsSpec.scala │ │ ├── handshaker │ │ │ └── EtcHandshakerSpec.scala │ │ ├── p2p │ │ │ ├── FrameCodecSpec.scala │ │ │ ├── MessageCodecSpec.scala │ │ │ ├── MessageDecodersSpec.scala │ │ │ ├── PeerActorSpec.scala │ │ │ ├── SecureChannelSetup.scala │ │ │ └── messages │ │ │ │ ├── LegacyTransactionSpec.scala │ │ │ │ ├── MessagesSerializationSpec.scala │ │ │ │ ├── NewBlockSpec.scala │ │ │ │ ├── NodeDataSpec.scala │ │ │ │ └── ReceiptsSpec.scala │ │ └── rlpx │ │ │ ├── MessageCompressionSpec.scala │ │ │ └── RLPxConnectionHandlerSpec.scala │ │ ├── ommers │ │ └── OmmersPoolSpec.scala │ │ ├── patience.scala │ │ ├── proof │ │ └── MptProofVerifier.scala │ │ ├── rlp │ │ └── RLPSpec.scala │ │ ├── security │ │ └── SSLContextFactorySpec.scala │ │ ├── testing │ │ └── ActorsTesting.scala │ │ ├── transactions │ │ ├── LegacyTransactionHistoryServiceSpec.scala │ │ ├── PendingTransactionsManagerSpec.scala │ │ └── testing │ │ │ └── PendingTransactionsManagerAutoPilot.scala │ │ ├── utils │ │ ├── ConfigSpec.scala │ │ ├── ConfigUtilsSpec.scala │ │ ├── GenOps.scala │ │ ├── MockClock.scala │ │ └── VersionInfoSpec.scala │ │ └── vm │ │ ├── Assembly.scala │ │ ├── BlakeCompressionSpec.scala │ │ ├── CallOpFixture.scala │ │ ├── CallOpcodesPostEip2929Spec.scala │ │ ├── CallOpcodesSpec.scala │ │ ├── CallOpcodesSpecPostEip161.scala │ │ ├── CreateOpcodeSpec.scala │ │ ├── Fixtures.scala │ │ ├── Generators.scala │ │ ├── MemorySpec.scala │ │ ├── MockStorage.scala │ │ ├── MockWorldState.scala │ │ ├── OpCodeFunSpec.scala │ │ ├── OpCodeGasSpec.scala │ │ ├── OpCodeGasSpecPostEip161.scala │ │ ├── OpCodeGasSpecPostEip2929.scala │ │ ├── OpCodeTesting.scala │ │ ├── PrecompiledContractsSpec.scala │ │ ├── ProgramSpec.scala │ │ ├── SSTOREOpCodeGasPostConstantinopleSpec.scala │ │ ├── ShiftingOpCodeSpec.scala │ │ ├── StackSpec.scala │ │ ├── StaticCallOpcodeSpec.scala │ │ ├── VMSpec.scala │ │ └── utils │ │ └── MockVmInput.scala └── universal │ ├── LICENSE │ ├── RELEASE │ ├── bin │ ├── eckeygen │ ├── eckeygen.bat │ ├── faucet-server │ ├── faucet-server.bat │ ├── mantis-launcher │ ├── mantis-launcher.bat │ ├── mantis-vm │ ├── mantis-vm.bat │ ├── signatureValidator │ └── signatureValidator.bat │ ├── conf │ ├── application.ini │ └── mallet.conf │ └── mantis_config.txt ├── test-ets.sh ├── tls ├── gen-cert.sh ├── mantisCA.p12 └── password ├── update-nix.sh └── version.sbt /.buildkite/default.nix: -------------------------------------------------------------------------------- 1 | import (import ../nix/sources.nix).nixkite 2 | -------------------------------------------------------------------------------- /.buildkite/pipeline.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - label: ":nix::point_right::pipeline:" 3 | command: | 4 | export NIX_PATH="nixpkgs=$(nix-instantiate --eval --strict --json --read-write-mode -E '(import nix/sources.nix).nixpkgs' | tr -d '"')" 5 | nix-instantiate --eval --strict --json --expr '(import ./.buildkite { pipeline = ./.buildkite/pipeline.nix; })' \ 6 | | buildkite-agent pipeline upload --no-interpolation 7 | agents: 8 | queue: project42 9 | timeout_in_minutes: 60 10 | # - label: "Mantis Automation" 11 | # command: 12 | # - "curl https://raw.githubusercontent.com/input-output-hk/mantis-automation/main/.buildkite/pipeline_erc20_pr.yml -o automation.yml" 13 | # - "buildkite-agent pipeline upload automation.yml" 14 | -------------------------------------------------------------------------------- /.buildkite/shell.nix: -------------------------------------------------------------------------------- 1 | { sources, pkgs }: 2 | let 3 | # TODO, share this code with mantis build in this project 4 | # sbt-protoc puts the scala plugin in /tmp/protobridge. 5 | # it is in fact a shell script with a standard `#!/usr/bin/env sh` shebang 6 | # that makes the Nix sandbox ANGRY and breaks all the things in a cryptic, 7 | # hairpull-inducing way. So we gotta sed it out. Not the prettiest thing 8 | # but it works. 9 | protoc-wrapper = pkgs.writeShellScriptBin "protoc" '' 10 | set -e 11 | 12 | for f in "$@"; do 13 | echo ''${f##*=} 14 | done | grep protocbridge | xargs sed -i "1s|.*|#!${pkgs.bash}/bin/bash|" 15 | 16 | exec ${pkgs.protobuf}/bin/protoc "$@" 17 | ''; 18 | in 19 | with pkgs; 20 | 21 | mkShell { 22 | nativeBuildInputs = [ sbt solc lllc jdk8 protoc-wrapper retesteth netcat-gnu ]; 23 | # SBT = "sbt -v -mem 2048 -J-Xmx4g -Dsbt.ivy.home=/cache/ivy2 -Dsbt.boot.directory=/cache/sbt -Dmaven.repo.local=/cache/maven -Dnix=true"; 24 | SBT = "sbt -v -mem 8192 -Dnix=true"; 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Desktop (please complete the following information):** 21 | - OS: [e.g. Ubuntu 4.15.0-20-generic] 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | _A clear and concise description of what this pull request does or fixes._ 4 | 5 | # Proposed Solution 6 | 7 | 8 | _**Optional** Explain how does this PR solves the problem stated in [Description](#Description). You can also enumerate different alternatives considered while approaching this task._ 9 | 10 | # Important Changes Introduced 11 | 12 | _**Optional** Notice Reviewers about changes that were introduced while developing this task_ 13 | 14 | # Testing 15 | 16 | _**Optional** Leave some recommendations should be useful while reviewers are testing this PR_ 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | dist/* 3 | project/boot/ 4 | project/plugins/project/ 5 | .ensime 6 | .ensime_cache/ 7 | .bloop 8 | out/ 9 | .bsp/ 10 | 11 | # IDE folders 12 | .idea/ 13 | .metals/ 14 | metals.sbt 15 | .vscode/ 16 | 17 | # intellij scala worksheet 18 | *.sc 19 | 20 | *.log 21 | *.log.zip 22 | .evm-runner_history 23 | 24 | # Nix 25 | result 26 | .nix/ 27 | .direnv 28 | 29 | # sonarScan 30 | .scannerwork/ 31 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ets/tests"] 2 | path = ets/tests 3 | url = https://github.com/ethereum/tests 4 | 5 | [submodule "src/main/protobuf/extvm"] 6 | path = src/main/protobuf/extvm 7 | url = https://github.com/input-output-hk/mantis-extvm-pb 8 | -------------------------------------------------------------------------------- /.jvmopts: -------------------------------------------------------------------------------- 1 | -Xms1g 2 | -Xmx4g 3 | -XX:ReservedCodeCacheSize=1024m 4 | -XX:MaxMetaspaceSize=1g 5 | -Xss4M -------------------------------------------------------------------------------- /.scalafix.conf: -------------------------------------------------------------------------------- 1 | rules = [ 2 | ExplicitResultTypes 3 | NoAutoTupling 4 | NoValInForComprehension 5 | OrganizeImports 6 | ProcedureSyntax 7 | RemoveUnused 8 | ] 9 | 10 | OrganizeImports { 11 | groupedImports = Explode 12 | groups = [ 13 | "re:javax?\\." 14 | "akka." 15 | "cats." 16 | "monix." 17 | "scala." 18 | "scala.meta." 19 | "*" 20 | "io.iohk.ethereum." 21 | ] 22 | removeUnused = true 23 | } 24 | 25 | RemoveUnused { 26 | imports = false // handled by OrganizeImports 27 | } -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = "2.7.5" 2 | align.preset = some 3 | maxColumn = 120 4 | 5 | rewrite.rules = [AvoidInfix, RedundantBraces, RedundantParens, SortModifiers] -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Input Output (Hong Kong) Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /bytes/src/main/scala/io/iohk/ethereum/utils/Hex.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | object Hex { 4 | def toHexString(bytes: Array[Byte]): String = 5 | bytes.map("%02x".format(_)).mkString 6 | 7 | def decode(hex: String): Array[Byte] = 8 | hex.toSeq.sliding(2, 2).toArray.map { s => 9 | Integer.parseInt(s.mkString(""), 16).toByte 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bytes/src/test/scala/io/iohk/ethereum/utils/ByteUtilsSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import org.scalacheck.Arbitrary 4 | import org.scalacheck.Gen 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks 7 | 8 | class ByteUtilsSpec extends AnyFunSuite with ScalaCheckPropertyChecks { 9 | def byteArrayOfNItemsGen(n: Int): Gen[Array[Byte]] = 10 | Gen.listOfN(n, Arbitrary.arbitrary[Byte]).map(_.toArray) 11 | 12 | test("Convert Bytes to Int in little endian") { 13 | forAll(byteArrayOfNItemsGen(32)) { bytes => 14 | val toInts = ByteUtils.bytesToInts(bytes, bigEndian = false) 15 | val asBytes = ByteUtils.intsToBytes(toInts, bigEndian = false) 16 | assert(asBytes.sameElements(bytes)) 17 | } 18 | } 19 | 20 | test("Convert Bytes to Int in big endian") { 21 | forAll(byteArrayOfNItemsGen(32)) { bytes => 22 | val toInts = ByteUtils.bytesToInts(bytes, bigEndian = true) 23 | val asBytes = ByteUtils.intsToBytes(toInts, bigEndian = true) 24 | assert(asBytes.sameElements(bytes)) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crypto/src/main/scala/io/iohk/ethereum/crypto/zksnark/FiniteField.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.crypto.zksnark 2 | 3 | trait FiniteField[A] { 4 | def zero: A 5 | def one: A 6 | def add(a: A, b: A): A 7 | def mul(a: A, b: A): A 8 | def sub(a: A, b: A): A 9 | def inv(a: A): A 10 | def neg(a: A): A 11 | def sqr(a: A): A = mul(a, a) 12 | def dbl(a: A): A = add(a, a) 13 | def isZero(a: A): Boolean 14 | def isValid(a: A): Boolean 15 | } 16 | 17 | object FiniteField { 18 | def apply[T](implicit field: FiniteField[T]): FiniteField[T] = field 19 | object Ops { 20 | implicit class FiniteFieldOps[T](t: T)(implicit F: FiniteField[T]) { 21 | def +(o: T): T = F.add(t, o) 22 | def *(o: T): T = F.mul(t, o) 23 | def -(o: T): T = F.sub(t, o) 24 | def doubled(): T = F.dbl(t) 25 | def squared(): T = F.sqr(t) 26 | def inversed(): T = F.inv(t) 27 | def negated(): T = F.neg(t) 28 | def isValid(): Boolean = F.isValid(t) 29 | def isZero(): Boolean = F.isZero(t) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crypto/src/test/scala/io/iohk/ethereum/crypto/Generators.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.crypto 2 | 3 | import akka.util.ByteString 4 | 5 | import org.scalacheck.Arbitrary 6 | import org.scalacheck.Gen 7 | 8 | object Generators { 9 | 10 | def getListGen[T](minSize: Int, maxSize: Int, genT: Gen[T]): Gen[List[T]] = 11 | Gen.choose(minSize, maxSize).flatMap(size => Gen.listOfN(size, genT)) 12 | 13 | def getByteStringGen(minSize: Int, maxSize: Int): Gen[ByteString] = 14 | getListGen(minSize, maxSize, Arbitrary.arbitrary[Byte]).map(l => ByteString(l.toArray)) 15 | } 16 | -------------------------------------------------------------------------------- /crypto/src/test/scala/io/iohk/ethereum/crypto/SecureRandomBuilder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.crypto 2 | 3 | import java.security.SecureRandom 4 | 5 | private[crypto] trait SecureRandomBuilder { 6 | lazy val secureRandom: SecureRandom = new SecureRandom() 7 | } 8 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { system ? builtins.currentSystem 2 | , src ? ./. 3 | , pkgs ? (import ./nix { inherit system src; }).pkgs 4 | }: 5 | pkgs.mantis 6 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM mantis-dev:latest as CURRENTBUILD 3 | 4 | ARG MANTIS_TAG 5 | ENV MANTIS_TAG ${MANTIS_TAG:-phase/iele_testnet} 6 | 7 | # The command `sbt dist` generates a zip file in the `target/universal` directory. 8 | # The value of `MANTIS_DIST_ZIP_NAME` must be the name of the generated zip, 9 | # excluding the extension. 10 | # So, for example, currently (commit `35e06611`) the `sbt dist` command 11 | # produces `target/universal/mantis-1.0-daedalus-rc1.zip`, so we can set 12 | # `MANTIS_DIST_ZIP_NAME` to be `mantis-1.0-daedalus-rc1`. 13 | # A glob like `mantis-*` also works and is more convenient, since it is invariant 14 | # with respect to the other part, which dependens on the software version. 15 | ARG MANTIS_DIST_ZIP_NAME 16 | ENV MANTIS_DIST_ZIP_NAME ${MANTIS_DIST_ZIP_NAME:-mantis-*} 17 | 18 | # Grab latest mantis, build the distribution and install it 19 | RUN ~/install-mantis.sh $MANTIS_TAG $MANTIS_DIST_ZIP_NAME 20 | # Now mantis is in /home/mantis/mantis-dist/app 21 | # or just /app 22 | 23 | # Start over and keep what is needed. 24 | # Now the size optimization comes from `mantis-base`: 25 | # smaller `mantis-base` means smaller `mantis` image (this image). 26 | FROM mantis-base:latest 27 | 28 | USER root 29 | COPY --from=CURRENTBUILD /home/mantis/mantis-dist /home/mantis/mantis-dist 30 | RUN chown -R mantis:mantis /home/mantis/mantis-dist 31 | 32 | USER mantis 33 | WORKDIR /app 34 | VOLUME /app/conf 35 | -------------------------------------------------------------------------------- /docker/Dockerfile-base: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | # This "base" image contains the base OS along with some extra programs. 4 | 5 | # See the accompanying `build-base.sh` script for tagging details. 6 | 7 | ENV DEBIAN_FRONTEND noninteractive 8 | 9 | ADD scripts/install-base-system.sh /root/ 10 | RUN /root/install-base-system.sh 11 | 12 | ADD scripts/install-nix-common.sh /home/mantis/ 13 | ADD scripts/install-nix-apps-base.sh /home/mantis/ 14 | RUN chown mantis:mantis /home/mantis/install-*.sh 15 | 16 | USER mantis 17 | WORKDIR /home/mantis 18 | ENV USER mantis 19 | 20 | RUN ~/install-nix-apps-base.sh 21 | -------------------------------------------------------------------------------- /docker/Dockerfile-dev: -------------------------------------------------------------------------------- 1 | FROM mantis-base:latest 2 | 3 | # This "dev" image creates enough of a Mantis build environment, 4 | # so that the actual Mantis images can be built in less time. 5 | # We are particularly interested in caching the dependencies needed 6 | # during the build process. This means that whenever those change, 7 | # the "dev" image must be recreated. 8 | 9 | # See the `Dockerfile-base` for the parent image details. 10 | # See the accompanying `build-dev.sh` script for tagging details. 11 | 12 | ARG SBT_VERIFY_TAG 13 | ENV SBT_VERIFY_TAG ${SBT_VERIFY_TAG:-v0.4.1} 14 | 15 | ARG MANTIS_TAG 16 | ENV MANTIS_TAG ${MANTIS_TAG:-phase/iele_testnet} 17 | 18 | USER root 19 | 20 | ADD scripts/install-nix-apps-dev.sh /home/mantis/ 21 | ADD scripts/install-mantis-dev.sh /home/mantis/ 22 | ADD scripts/install-mantis.sh /home/mantis/ 23 | 24 | RUN chown mantis:mantis /home/mantis/install-*.sh 25 | 26 | USER mantis 27 | WORKDIR /home/mantis 28 | ENV USER mantis 29 | 30 | RUN ~/install-nix-apps-dev.sh 31 | RUN ~/install-mantis-dev.sh $SBT_VERIFY_TAG $MANTIS_TAG 32 | -------------------------------------------------------------------------------- /docker/besu/README.md: -------------------------------------------------------------------------------- 1 | ## How to run Besu 2 | 3 | In `runBesu.sh` set the Besu `VERSION` you wish to test and then just run the script in a terminal 4 | 5 | ```./runBesu.sh``` 6 | 7 | When the script is running Prometheus metrics and Grafana will be available at: 8 | 9 | `http://localhost:9091` for the list of all available metrics 10 | 11 | `http://localhost:3000/login` to access Grafana (login is admin / admin) 12 | 13 | 14 | ### Metrics 15 | Some metrics are already being displayed in Grafana, using part of the dashboard that can be found in `https://grafana.com/grafana/dashboards/10273` and also replicating some metrics being used by the `mantis-ops` grafana dashboard 16 | 17 | 18 | ### JSON RPC API 19 | JSON-RPC service is available at port 8545 20 | -------------------------------------------------------------------------------- /docker/besu/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'Prometheus' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | options: 11 | path: /etc/grafana/provisioning/dashboards 12 | -------------------------------------------------------------------------------- /docker/besu/grafana/provisioning/datasources/datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | deleteDatasources: 3 | - name: Prometheus 4 | orgId: 1 5 | 6 | datasources: 7 | - name: Prometheus 8 | type: prometheus 9 | access: proxy 10 | orgId: 1 11 | url: http://prometheus:9090 12 | password: 13 | user: 14 | database: 15 | basicAuth: false 16 | basicAuthUser: 17 | basicAuthPassword: 18 | withCredentials: 19 | isDefault: true 20 | jsonData: 21 | graphiteVersion: "1.1" 22 | tlsAuth: false 23 | tlsAuthWithCACert: false 24 | secureJsonData: 25 | tlsCACert: "..." 26 | tlsClientCert: "..." 27 | tlsClientKey: "..." 28 | version: 1 29 | editable: true 30 | -------------------------------------------------------------------------------- /docker/besu/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1m 3 | scrape_timeout: 10s 4 | evaluation_interval: 1m 5 | scrape_configs: 6 | - job_name: push-gateway 7 | metrics_path: /metrics 8 | scheme: http 9 | static_configs: 10 | - targets: 11 | - pushgateway:9091 12 | -------------------------------------------------------------------------------- /docker/besu/runBesu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export VERSION=20.10.4 3 | docker-compose up 4 | -------------------------------------------------------------------------------- /docker/build-base.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | 7 | exec $HERE/buildhelper.sh mantis-base Dockerfile-base latest 8 | -------------------------------------------------------------------------------- /docker/build-dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | 7 | exec $HERE/buildhelper.sh mantis-dev Dockerfile-dev latest 8 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | 7 | $HERE/buildhelper.sh mantis Dockerfile 8 | -------------------------------------------------------------------------------- /docker/buildhelper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | 7 | IMAGE_NAME=$1 8 | DOCKERFILE=$2 9 | 10 | # If IMAGE_TAG is not given in the command line, then compute one in the format 11 | # 12 | # YYYY-MM-DD '.' SHORT_HASH 13 | # 14 | # where the variable parts refer to the latest commit 15 | IMAGE_TAG=${3:-$(git log -1 --format=%cd.%h --date=short)} 16 | 17 | # This is the commit that the image will be based on 18 | GIT_HASH=$(git log -1 --format=%H) 19 | 20 | docker build --build-arg MANTIS_TAG=$GIT_HASH -t $IMAGE_NAME:$IMAGE_TAG -f $HERE/$DOCKERFILE $HERE -------------------------------------------------------------------------------- /docker/geth/README.md: -------------------------------------------------------------------------------- 1 | ## How to run Geth 2 | 3 | Just run the script in a terminal 4 | 5 | ``` ./runGeth.sh``` 6 | 7 | When the script is running Prometheus metrics and Grafana will be available at: 8 | 9 | `http://localhost:6060/debug/metrics/prometheus` for the list of all available metrics 10 | 11 | `http://localhost:3000/login` to access Grafana (login is admin / admin) 12 | 13 | 14 | ### Metrics 15 | Some metrics are already being displayed in Grafana, using Dashboard from: 16 | ``` 17 | https://gist.githubusercontent.com/karalabe/e7ca79abdec54755ceae09c08bd090cd/raw/3a400ab90f9402f2233280afd086cb9d6aac2111/dashboard.json 18 | ``` 19 | 20 | 21 | ### JSON RPC API 22 | JSON-RPC service is available at port 8545 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docker/geth/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'Prometheus' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | options: 11 | path: /etc/grafana/provisioning/dashboards 12 | -------------------------------------------------------------------------------- /docker/geth/grafana/provisioning/datasources/datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | deleteDatasources: 3 | - name: Prometheus 4 | orgId: 1 5 | 6 | datasources: 7 | - name: Prometheus 8 | type: prometheus 9 | access: proxy 10 | orgId: 1 11 | url: http://prometheus:9090 12 | password: 13 | user: 14 | database: 15 | basicAuth: false 16 | basicAuthUser: 17 | basicAuthPassword: 18 | withCredentials: 19 | isDefault: true 20 | jsonData: 21 | graphiteVersion: "1.1" 22 | tlsAuth: false 23 | tlsAuthWithCACert: false 24 | secureJsonData: 25 | tlsCACert: "..." 26 | tlsClientCert: "..." 27 | tlsClientKey: "..." 28 | version: 1 29 | editable: true 30 | -------------------------------------------------------------------------------- /docker/geth/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1m 3 | scrape_timeout: 10s 4 | evaluation_interval: 1m 5 | scrape_configs: 6 | - job_name: node 7 | honor_timestamps: true 8 | scrape_interval: 10s 9 | scrape_timeout: 10s 10 | metrics_path: /debug/metrics/prometheus 11 | scheme: http 12 | static_configs: 13 | - targets: 14 | - geth:6060 15 | labels: 16 | alias: geth-node 17 | 18 | -------------------------------------------------------------------------------- /docker/geth/runGeth.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker-compose up 3 | -------------------------------------------------------------------------------- /docker/mantis/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | HERE=$(dirname $0) 4 | 5 | cd $HERE/../../ 6 | sbt 'set version := "latest"' docker:publishLocal 7 | 8 | docker-compose -f docker/mantis/docker-compose.yml up -d 9 | -------------------------------------------------------------------------------- /docker/mantis/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | volumes: 4 | prometheus_data: {} 5 | grafana_data: {} 6 | 7 | networks: 8 | mantis-net: 9 | 10 | services: 11 | 12 | prometheus: 13 | image: prom/prometheus:v2.23.0 14 | volumes: 15 | - ./prometheus/:/etc/prometheus/ 16 | - prometheus_data:/prometheus 17 | command: 18 | - '--config.file=/etc/prometheus/prometheus.yml' 19 | - '--storage.tsdb.path=/prometheus' 20 | - '--web.console.libraries=/usr/share/prometheus/console_libraries' 21 | - '--web.console.templates=/usr/share/prometheus/consoles' 22 | ports: 23 | - 9090:9090 24 | links: 25 | - mantis:mantis 26 | depends_on: 27 | - mantis 28 | networks: 29 | - mantis-net 30 | restart: always 31 | 32 | mantis: 33 | image: mantis:latest 34 | ports: 35 | - 8546:8546 36 | - 13798:13798 37 | - 9095:9095 38 | networks: 39 | - mantis-net 40 | restart: always 41 | 42 | grafana: 43 | image: grafana/grafana:7.3.6 44 | depends_on: 45 | - prometheus 46 | ports: 47 | - 3000:3000 48 | volumes: 49 | - grafana_data:/var/lib/grafana 50 | - ./grafana/provisioning/:/etc/grafana/provisioning/ 51 | networks: 52 | - mantis-net 53 | restart: always 54 | 55 | -------------------------------------------------------------------------------- /docker/mantis/grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'Prometheus' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | options: 11 | path: /etc/grafana/provisioning/dashboards 12 | -------------------------------------------------------------------------------- /docker/mantis/grafana/provisioning/datasources/datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | deleteDatasources: 3 | - name: Prometheus 4 | orgId: 1 5 | 6 | datasources: 7 | - name: Prometheus 8 | type: prometheus 9 | access: proxy 10 | orgId: 1 11 | url: http://prometheus:9090 12 | password: 13 | user: 14 | database: 15 | basicAuth: false 16 | basicAuthUser: 17 | basicAuthPassword: 18 | withCredentials: 19 | isDefault: true 20 | jsonData: 21 | graphiteVersion: "1.1" 22 | tlsAuth: false 23 | tlsAuthWithCACert: false 24 | secureJsonData: 25 | tlsCACert: "..." 26 | tlsClientCert: "..." 27 | tlsClientKey: "..." 28 | version: 1 29 | editable: true 30 | -------------------------------------------------------------------------------- /docker/mantis/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | # Please, don't use any default port allocations. 2 | # https://github.com/prometheus/prometheus/wiki/Default-port-allocations 3 | global: 4 | scrape_interval: 1m 5 | scrape_timeout: 10s 6 | evaluation_interval: 1m 7 | scrape_configs: 8 | - job_name: prometheus 9 | honor_timestamps: true 10 | scrape_interval: 5s 11 | scrape_timeout: 5s 12 | metrics_path: /metrics 13 | scheme: http 14 | static_configs: 15 | - targets: 16 | - promethues:9090 17 | labels: 18 | alias: prometheus 19 | - job_name: node 20 | honor_timestamps: true 21 | scrape_interval: 10s 22 | scrape_timeout: 10s 23 | metrics_path: /metrics 24 | scheme: http 25 | static_configs: 26 | - targets: 27 | - mantis:13798 28 | labels: 29 | alias: mantis-node 30 | - job_name: akka 31 | honor_timestamps: true 32 | scrape_interval: 10s 33 | scrape_timeout: 10s 34 | scheme: http 35 | static_configs: 36 | - targets: 37 | - mantis:9095 38 | labels: 39 | alias: mantis-akka-node 40 | 41 | -------------------------------------------------------------------------------- /docker/scripts/install-base-system.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | apt-get update 6 | apt-get dist-upgrade -y 7 | apt-get install -y curl bzip2 locales 8 | locale-gen en_US.UTF-8 9 | update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 10 | 11 | adduser --disabled-password --gecos '' mantis 12 | 13 | mkdir /nix 14 | chown mantis:mantis /nix 15 | su mantis -c 'curl https://nixos.org/nix/install | sh \ 16 | && tail -n 1 ~/.profile >> ~/.bashrc' 17 | ln -s /home/mantis/mantis-dist/app /app 18 | 19 | apt-get purge -y curl bzip2 20 | apt-get clean -y 21 | rm -rf /var/cache/debconf/* /var/lib/apt/lists/* /var/log/* /tmp/* /var/tmp/* -------------------------------------------------------------------------------- /docker/scripts/install-mantis-dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | SBT_VERIFY_TAG=$1 6 | MANTIS_TAG=$2 7 | 8 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 9 | . $HERE/install-nix-common.sh 10 | 11 | mkdir ~/repos 12 | 13 | cd ~/repos 14 | git clone https://github.com/input-output-hk/mantis.git 15 | cd mantis 16 | git checkout $MANTIS_TAG 17 | git submodule update --init 18 | 19 | # Trigger compilation, so that we get some dependencies from the internetz. 20 | sbt 'set test in Test := {}' compile -------------------------------------------------------------------------------- /docker/scripts/install-mantis.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | MANTIS_TAG=$1 6 | MANTIS_DIST_ZIP_NAME=$2 7 | 8 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 9 | . $HERE/install-nix-common.sh 10 | 11 | cd ~/repos/mantis 12 | 13 | git checkout $MANTIS_TAG 14 | git submodule update --init 15 | 16 | sbt 'set test in Test := {}' dist 17 | mkdir -p ~/mantis-dist/app 18 | unzip -d ~/mantis-dist/app target/universal/${MANTIS_DIST_ZIP_NAME}.zip 19 | mv ~/mantis-dist/app/*/* ~/mantis-dist/app 20 | rmdir ~/mantis-dist/app/$MANTIS_DIST_ZIP_NAME 21 | rm -rf ~/repos ~/.ivy2 ~/.sbt -------------------------------------------------------------------------------- /docker/scripts/install-nix-apps-base.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | . $HERE/install-nix-common.sh 7 | 8 | nix-install openjdk 9 | nix-collect-garbage -d -------------------------------------------------------------------------------- /docker/scripts/install-nix-apps-dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | HERE=$(readlink -m $(dirname ${BASH_SOURCE[0]})) 6 | . $HERE/install-nix-common.sh 7 | 8 | nix-install sbt gitMinimal unzip 9 | nix-collect-garbage -d -------------------------------------------------------------------------------- /docker/scripts/install-nix-common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euxo pipefail 4 | 5 | NIX_PROFILE=~/.nix-profile/etc/profile.d/nix.sh 6 | 7 | export MANPATH= 8 | . $NIX_PROFILE 9 | 10 | export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-18.03.tar.gz 11 | 12 | function nix-install() { 13 | nix-env -f '' -iA "$@" 14 | } 15 | -------------------------------------------------------------------------------- /ets/config/mantis/config: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "IOHK Mantis on TCP", 3 | "socketType" : "tcp", 4 | "socketAddress" : [ 5 | "0.0.0.0:8546" 6 | ], 7 | "initializeTime" : "5", 8 | "forks" : [ 9 | "Frontier", 10 | "Homestead", 11 | "EIP150", 12 | "EIP158", 13 | "Byzantium", 14 | "Constantinople", 15 | "ConstantinopleFix", 16 | "Istanbul", 17 | "Berlin", 18 | "London" 19 | ], 20 | "additionalForks" : [ 21 | "FrontierToHomesteadAt5", 22 | "HomesteadToEIP150At5", 23 | "EIP158ToByzantiumAt5", 24 | "HomesteadToDaoAt5", 25 | "ByzantiumToConstantinopleFixAt5" 26 | ], 27 | "exceptions" : {} 28 | } 29 | -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Berlin.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00", 8 | "constantinopleFixForkBlock" : "0x00", 9 | "istanbulForkBlock" : "0x00", 10 | "berlinForkBlock" : "0x00", 11 | "chainID" : "0x01" 12 | }, 13 | "accounts" : { 14 | } 15 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/BerlinToLondonAt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00", 8 | "constantinopleFixForkBlock" : "0x00", 9 | "berlinForkBlock" : "0x00", 10 | "londonForkBlock" : "0x05" 11 | }, 12 | "accounts" : { 13 | } 14 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Byzantium.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00" 7 | }, 8 | "accounts" : { 9 | } 10 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/ByzantiumToConstantinopleFixAt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x05", 8 | "constantinopleFixForkBlock" : "0x05" 9 | }, 10 | "accounts" : { 11 | } 12 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Constantinople.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00" 8 | }, 9 | "accounts" : { 10 | } 11 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/ConstantinopleFix.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00", 8 | "constantinopleFixForkBlock" : "0x00" 9 | }, 10 | "accounts" : { 11 | } 12 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/EIP150.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00" 5 | }, 6 | "accounts" : { 7 | } 8 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/EIP158.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00" 6 | }, 7 | "accounts" : { 8 | } 9 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/EIP158ToByzantiumAt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x05" 7 | }, 8 | "accounts" : { 9 | } 10 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Frontier.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | }, 4 | "accounts" : { 5 | } 6 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/FrontierToHomesteadAt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x05" 4 | }, 5 | "accounts" : { 6 | } 7 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Homestead.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00" 4 | }, 5 | "accounts" : { 6 | } 7 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/HomesteadToDaoAt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "daoHardforkBlock" : "0x05" 5 | }, 6 | "accounts" : { 7 | } 8 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/HomesteadToEIP150At5.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x05" 5 | }, 6 | "accounts" : { 7 | } 8 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/Istanbul.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00", 8 | "constantinopleFixForkBlock" : "0x00", 9 | "istanbulForkBlock" : "0x00", 10 | "chainID" : "0x01" 11 | }, 12 | "accounts" : { 13 | } 14 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/London.json: -------------------------------------------------------------------------------- 1 | { 2 | "params" : { 3 | "homesteadForkBlock" : "0x00", 4 | "EIP150ForkBlock" : "0x00", 5 | "EIP158ForkBlock" : "0x00", 6 | "byzantiumForkBlock" : "0x00", 7 | "constantinopleForkBlock" : "0x00", 8 | "constantinopleFixForkBlock" : "0x00", 9 | "istanbulForkBlock" : "0x00", 10 | "berlinForkBlock" : "0x00", 11 | "londonForkBlock" : "0x00", 12 | "chainID" : "0x01" 13 | }, 14 | "accounts" : { 15 | } 16 | } -------------------------------------------------------------------------------- /ets/config/mantis/genesis/correctMiningReward.json: -------------------------------------------------------------------------------- 1 | { 2 | "//comment" : "State Tests does not calculate mining reward in post conditions, so when filling a blockchain test out of it, the mining reward must be set", 3 | "Frontier": "5000000000000000000", 4 | "Homestead": "5000000000000000000", 5 | "EIP150": "5000000000000000000", 6 | "EIP158": "5000000000000000000", 7 | "Byzantium": "3000000000000000000", 8 | "Constantinople": "2000000000000000000", 9 | "ConstantinopleFix": "2000000000000000000", 10 | "Istanbul": "2000000000000000000", 11 | "Berlin" : "2000000000000000000", 12 | "London" : "2000000000000000000" 13 | } -------------------------------------------------------------------------------- /ets/config/version: -------------------------------------------------------------------------------- 1 | - -------------------------------------------------------------------------------- /ets/retesteth: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | dir="$(cd "$(dirname "$0")" && pwd)" 4 | 5 | separator="--" 6 | if [[ $@ =~ "--" ]]; then 7 | separator="" 8 | fi 9 | 10 | retesteth $@ $separator --testpath $dir/tests --datadir $dir/config --clients mantis 11 | -------------------------------------------------------------------------------- /ets/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Boots Mantis and runs retesteth / ETS. Intended for running it locally. 4 | 5 | if [ -z "$SBT" ]; then 6 | SBT="sbt" 7 | fi 8 | 9 | echo "booting Mantis with log level WARN and waiting for RPC API to be up." 10 | $SBT -Dconfig.file=./src/main/resources/conf/testmode.conf -Dlogging.logs-level=WARN run & 11 | 12 | while ! nc -z localhost 8546; do 13 | sleep 0.1 14 | done 15 | 16 | final_exit_code=0 17 | mkdir -p out/ 18 | 19 | function run_and_summarize { 20 | out_file="out/retesteth-$1-log.txt" 21 | 22 | echo "running retesteth $1 with output to $out_file" 23 | timeout 15m ets/retesteth -t "$1" -- --verbosity 3 &> $out_file 24 | exit_code=$? 25 | echo "retesteth $1 exit code: $exit_code" 26 | 27 | style="info" 28 | if [[ "$exit_code" -gt "0" ]]; then 29 | final_exit_code="$exit_code" 30 | style="error" 31 | fi 32 | 33 | summary=$(sed -n '/Total Tests Run/,$p' $out_file) 34 | if [[ -z "$summary" ]]; then 35 | summary="retesteth crashed; check the artifacts" 36 | fi 37 | passed=$(grep -oP 'Total Tests Run: \d+' $out_file) 38 | failed=$(grep -oP 'TOTAL ERRORS DETECTED: \d+' $out_file) 39 | 40 | echo "retesteth: $1 -- $passed -- $failed" 41 | echo "$summary" 42 | } 43 | 44 | run_and_summarize "GeneralStateTests" 45 | run_and_summarize "BlockchainTests" 46 | 47 | echo "shutting down mantis" 48 | kill %1 49 | 50 | exit $final_exit_code 51 | -------------------------------------------------------------------------------- /nix-in-docker/nix.conf: -------------------------------------------------------------------------------- 1 | sandbox = relaxed 2 | experimental-features = nix-command flakes ca-references 3 | substituters = https://hydra.iohk.io https://cache.nixos.org https://mantis-ops.cachix.org https://hydra.mantis.ist 4 | trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= mantis-ops.cachix.org-1:SornDcX8/9rFrpTjU+mAAb26sF8mUpnxgXNjmKGcglQ= hydra.mantis.ist-1:4LTe7Q+5pm8+HawKxvmn2Hx0E3NbkYjtf1oWv+eAmTo= 5 | -------------------------------------------------------------------------------- /nix-in-docker/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | dir="$(cd "$(dirname "$0")" && pwd)" 4 | 5 | docker volume create mantis-root 6 | docker volume create mantis-ops-nix # reuse nix volume from mantis-ops 7 | docker run \ 8 | -it \ 9 | --network="host" \ 10 | --rm \ 11 | -e BUILDKITE=true \ 12 | -v=$dir/..:/mantis \ 13 | -w=/mantis \ 14 | -v=mantis-root:/root \ 15 | -v=mantis-ops-nix:/nix \ 16 | -v=$dir/nix.conf:/etc/nix/nix.conf \ 17 | nixpkgs/nix-unstable:latest \ 18 | nix-shell "$@" 19 | -------------------------------------------------------------------------------- /nix/default.nix: -------------------------------------------------------------------------------- 1 | { system ? builtins.currentSystem, sources ? import ./sources.nix, src ? ../. }: 2 | let 3 | # we need to filter out the nix files in this repository as they will 4 | # affect the fixed derivation calculation from sbt-derivation 5 | overlay = final: prev: 6 | let 7 | inherit (import sources.gitignore { inherit (prev) lib; }) gitignoreSource; 8 | # If src isn't a path, it's likely a prefiltered store path, so use it directly 9 | # This also makes Nix flakes work by passing the flake source as the `src` arg 10 | cleanedSrc = 11 | if builtins.isPath src 12 | then prev.lib.cleanSource (gitignoreSource src) 13 | else src; 14 | in 15 | { 16 | inherit sources; 17 | 18 | # match java version used by devs, this should also change the version used by sbt 19 | jre = prev.jdk8.jre; 20 | 21 | mantis = final.callPackage ./pkgs/mantis.nix { 22 | src = cleanedSrc; 23 | }; 24 | 25 | retesteth = final.callPackage ./retesteth.nix { }; 26 | lllc = final.callPackage ./lllc.nix { }; 27 | }; 28 | 29 | sbt-derivation-overlay = import sources.sbt-derivation; 30 | in 31 | import sources.nixpkgs { 32 | inherit system; 33 | overlays = [ 34 | sbt-derivation-overlay 35 | overlay 36 | ]; 37 | } 38 | -------------------------------------------------------------------------------- /nix/lllc.nix: -------------------------------------------------------------------------------- 1 | { stdenv, cmake, boost, fetchzip }: 2 | let 3 | jsoncppURL = "https://github.com/open-source-parsers/jsoncpp/archive/1.8.4.tar.gz"; 4 | jsoncpp = fetchzip { 5 | url = jsoncppURL; 6 | sha256 = "sha256-lX5sbu2WJuTfyFmFRkCbMOjlMQE62nmrjPN6adSRD/w="; 7 | }; 8 | in 9 | stdenv.mkDerivation rec { 10 | 11 | pname = "lllc"; 12 | version = "14c9d5de6c7e58f1d1b18a04b57ec9f190d7cd2f"; 13 | 14 | src = builtins.fetchurl { 15 | url = "https://github.com/winsvega/solidity/archive/${version}.tar.gz"; 16 | sha256 = "0s6nz0w8fr1347d05kx4z3z72b1k0kmcz6d4dwwc24rydjznkw6r"; 17 | }; 18 | 19 | postPatch = '' 20 | substituteInPlace cmake/jsoncpp.cmake \ 21 | --replace "${jsoncppURL}" ${jsoncpp} 22 | ''; 23 | 24 | preConfigure = '' 25 | echo ${version} > commit_hash.txt 26 | ''; 27 | 28 | cmakeFlags = [ 29 | "-DBoost_USE_STATIC_LIBS=OFF" 30 | "-DCMAKE_BUILD_TYPE=Release" 31 | "-DLLL=1" 32 | ]; 33 | 34 | nativeBuildInputs = [ cmake ]; 35 | buildInputs = [ boost ]; 36 | 37 | buildPhase = '' 38 | make lllc 39 | ''; 40 | 41 | installPhase = '' 42 | mkdir -p $out/bin 43 | mv lllc/lllc $out/bin/ 44 | ''; 45 | } 46 | -------------------------------------------------------------------------------- /nix/pkgs/nginx.nix: -------------------------------------------------------------------------------- 1 | { lib, writeBashBinChecked, nginx, coreutils, package, target }: 2 | writeBashBinChecked "entrypoint" '' 3 | export PATH="${lib.makeBinPath [ nginx coreutils ]}" 4 | mkdir -p /var/cache/nginx 5 | ln -fs ${package} ${target} 6 | 7 | config="$1" 8 | echo "waiting for valid nginx config..." 9 | until nginx -t -c "$config"; do 10 | sleep 1 11 | done 12 | 13 | exec nginx -g 'error_log stderr;' -c "$@" 14 | '' 15 | -------------------------------------------------------------------------------- /nix/protoc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build.sbt b/build.sbt 2 | index 59551123e..88eb70276 100644 3 | --- a/build.sbt 4 | +++ b/build.sbt 5 | @@ -50,6 +50,7 @@ def commonSettings(projectName: String): Seq[sbt.Def.Setting[_]] = Seq( 6 | scalaVersion := `scala-2.13`, 7 | semanticdbEnabled := true, // enable SemanticDB 8 | semanticdbVersion := scalafixSemanticdb.revision, // use Scalafix compatible version 9 | + PB.runProtoc in Compile := (args => Process("@protobuf@/bin/protoc", args)!), 10 | ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value), 11 | ThisBuild / scalafixDependencies ++= List( 12 | "com.github.liancheng" %% "organize-imports" % "0.5.0", 13 | -------------------------------------------------------------------------------- /project/SolidityPlugin.scala: -------------------------------------------------------------------------------- 1 | import java.io.PrintWriter 2 | 3 | import sbt.TaskKey 4 | import sbt._ 5 | import Keys._ 6 | 7 | object SolidityPlugin extends AutoPlugin { 8 | 9 | object autoImport { 10 | lazy val solidityCompile = TaskKey[Unit]("solidityCompile", "Compiles solidity contracts") 11 | } 12 | 13 | import autoImport._ 14 | 15 | override def projectSettings: Seq[Def.Setting[_]] = Seq( 16 | solidityCompile := { 17 | import sys.process._ 18 | 19 | val contractsDir = baseDirectory.value / "src" / "evmTest" / "resources" / "solidity" 20 | val outDir = baseDirectory.value / "target" / "contracts" 21 | 22 | (contractsDir ** "*.sol").get.foreach { f => 23 | Seq("solc", f.getPath, "--bin", "--overwrite", "-o", outDir.getPath).!! 24 | 25 | // this is a temporary workaround, see: https://github.com/ethereum/solidity/issues/1732 26 | val abiOut = Seq("solc", f.getPath, "--abi").!! 27 | val abisLines = abiOut.split("\n").sliding(4, 4) 28 | abisLines.foreach { abiLines => 29 | val contractName = abiLines(1) 30 | .replace(f.getPath, "") 31 | .dropWhile(_ != ':').drop(1) 32 | .takeWhile(_ != ' ') 33 | new PrintWriter(outDir / s"$contractName.abi") { 34 | write(abiLines.drop(3).mkString); close() 35 | } 36 | } 37 | } 38 | } 39 | ) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.5.4 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := sbt.Level.Warn 2 | addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0") 3 | addSbtPlugin("com.github.mwz" % "sbt-sonar" % "2.2.0") 4 | addSbtPlugin("com.lightbend.sbt" % "sbt-javaagent" % "0.1.6") 5 | addSbtPlugin("com.sksamuel.scapegoat" % "sbt-scapegoat" % "1.1.0") 6 | addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0") 7 | addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.5.1") 8 | addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0") 9 | addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.5") 10 | addSbtPlugin("io.kamon" % "sbt-kanela-runner" % "2.0.5") 11 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2") 12 | addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0") 13 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1") 14 | addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.6") 15 | addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.29") 16 | -------------------------------------------------------------------------------- /project/scalapb.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.34") 2 | libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.10.9" 3 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | { src ? builtins.fetchGit ./. 2 | , supportedSystems ? [ builtins.currentSystem ] 3 | }: 4 | let 5 | sources = import nix/sources.nix; 6 | lib = import (sources.nixpkgs + "/lib"); 7 | in 8 | { 9 | mantis = lib.genAttrs supportedSystems (system: import src { 10 | inherit src system; 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { sources ? import nix/sources.nix, pkgs ? import ./nix { } }: 2 | 3 | if __getEnv "BUILDKITE" == "true" then 4 | import .buildkite/shell.nix { inherit sources pkgs; } 5 | else 6 | with pkgs; 7 | 8 | mkShell { 9 | nativeBuildInputs = [ protobuf sbt ]; 10 | inputsFrom = [ mantis ]; 11 | } 12 | -------------------------------------------------------------------------------- /src/ets/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/src/ets/README.md -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/CallSelfDestruct.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract CallSelfDestruct { 4 | 5 | function callDestruct() public { 6 | CallSelfDestruct firstCall = CallSelfDestruct(this); 7 | firstCall.doSelfdestruct(); 8 | 9 | CallSelfDestruct secondCall = CallSelfDestruct(this); 10 | secondCall.doSelfdestruct(); 11 | } 12 | 13 | function doSelfdestruct() public { 14 | selfdestruct(msg.sender); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/Caller.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract Callee { 4 | 5 | uint foo = 2; 6 | 7 | function setFoo(uint v) public { 8 | foo = v; 9 | } 10 | 11 | function getFoo() view public returns (uint) { 12 | return foo; 13 | } 14 | 15 | } 16 | 17 | contract Caller { 18 | 19 | function makeACall(address calleeAddr, uint fooVal) public { 20 | Callee callee = Callee(calleeAddr); 21 | callee.setFoo(fooVal); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/ContractCallingItself.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract ContractCallingItself { 4 | 5 | uint someVar = 10; 6 | 7 | function callSelf() public { 8 | address selfAddress = address(this); 9 | ContractCallingItself selfContract = ContractCallingItself(selfAddress); 10 | selfContract.doubleSomeVar(); 11 | } 12 | 13 | function doubleSomeVar() public { 14 | someVar = someVar * 2; 15 | } 16 | 17 | function getSomeVar() public view returns (uint) { 18 | return someVar; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/Fibonacci.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract Fibonacci { 4 | uint fib = 0; 5 | uint prevFib = 0; 6 | 7 | function getStoredFib() public view returns (uint) { 8 | return fib; 9 | } 10 | 11 | function getNewFib(uint n) public returns (uint) { 12 | prevFib = fib; 13 | fib = calcFib(n); 14 | return fib; 15 | } 16 | 17 | function calcFib(uint n) private returns (uint) { 18 | assert(n >= 0); 19 | 20 | if (n == 0) 21 | return 0; 22 | else if (n == 1) 23 | return 1; 24 | else 25 | return calcFib(n - 1) + calcFib(n - 2); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/MinimumViableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract MinimumViableToken { 4 | /* This creates an array with all balances */ 5 | mapping (address => uint256) public balanceOf; 6 | 7 | /* Initializes contract with initial supply tokens to the creator of the contract */ 8 | constructor(uint256 initialSupply) public { 9 | balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 10 | } 11 | 12 | /* Send coins */ 13 | function transfer(address _to, uint256 _value) public { 14 | assert(balanceOf[msg.sender] >= _value); // Check if the sender has enough 15 | assert(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows 16 | balanceOf[msg.sender] -= _value; // Subtract from the sender 17 | balanceOf[_to] += _value; // Add the same to the recipient 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/MutualRecursion.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract MutualRecursion { 4 | 5 | function isEven(uint n) public returns (bool) { 6 | if (n == 0) 7 | return true; 8 | else 9 | return isOdd(n - 1); 10 | } 11 | 12 | function isOdd(uint n) public returns (bool) { 13 | if (n == 0) 14 | return false; 15 | else 16 | return isEven(n - 1); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/PrecompiledContracts.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract PrecompiledContracts { 4 | function usePrecompiledContracts(bytes32 hash, uint8 v, bytes32 r, bytes32 s) pure public returns (bytes20) { 5 | 6 | // there is no function alias for Identity contract and we cannot get the return data using low-level call: 7 | // https://solidity.readthedocs.io/en/latest/types.html#address 8 | address ecRecovered = ecrecover(hash, v, r, s); 9 | bytes32 hashed = sha256(abi.encodePacked(ecRecovered)); 10 | bytes20 result = ripemd160(abi.encodePacked(hashed)); 11 | 12 | return result; 13 | } 14 | } 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/evmTest/resources/solidity/Throw.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract Throw { 4 | function justThrow() pure public { 5 | assert(false); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/CallSelfDestructSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.freespec.AnyFreeSpec 6 | 7 | class CallSelfDestructSpec extends AnyFreeSpec with Matchers { 8 | 9 | "EVM running CallSelfDestruct contract" - { 10 | 11 | "should refund only once" in new EvmTestEnv { 12 | val (_, callSelfDestruct) = deployContract("CallSelfDestruct") 13 | 14 | val callRes = callSelfDestruct.callDestruct().call() 15 | 16 | callRes.error shouldBe None 17 | callRes.gasRefund shouldBe 24000 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/CallerSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.freespec.AnyFreeSpec 6 | import io.iohk.ethereum.domain.UInt256 7 | 8 | // scalastyle:off magic.number 9 | class CallerSpec extends AnyFreeSpec with Matchers { 10 | 11 | "EVM running Caller contract" - { 12 | 13 | "should handle a call to Callee" in new EvmTestEnv { 14 | val (_, callee) = deployContract("Callee") 15 | val (_, caller) = deployContract("Caller") 16 | 17 | val callRes = caller.makeACall(callee.address, 123).call() 18 | callRes.error shouldBe None 19 | 20 | callee.getFoo().call().returnData shouldBe UInt256(123).bytes 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/ContractCallingItselfSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.freespec.AnyFreeSpec 6 | import io.iohk.ethereum.domain.UInt256 7 | 8 | // scalastyle:off magic.number 9 | class ContractCallingItselfSpec extends AnyFreeSpec with Matchers { 10 | 11 | "EVM running ContractCallingItself contract" - { 12 | 13 | "should handle a call to itself" in new EvmTestEnv { 14 | val (_, contract) = deployContract("ContractCallingItself") 15 | 16 | contract.getSomeVar().call().returnData shouldBe UInt256(10).bytes 17 | 18 | val result = contract.callSelf().call() 19 | result.error shouldBe None 20 | 21 | contract.getSomeVar().call().returnData shouldBe UInt256(20).bytes 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/FibonacciSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.freespec.AnyFreeSpec 6 | import io.iohk.ethereum.domain.UInt256 7 | 8 | // scalastyle:off magic.number 9 | class FibonacciSpec extends AnyFreeSpec with Matchers { 10 | 11 | "EVM running Fibonacci contract" - { 12 | 13 | "should handle getNewFib call" in new EvmTestEnv { 14 | val (_, contract) = deployContract("Fibonacci") 15 | 16 | val result = contract.getNewFib(5).call() 17 | 18 | result.error shouldBe None 19 | result.returnData shouldBe UInt256(5).bytes 20 | } 21 | 22 | "should allow storage write/read" in new EvmTestEnv { 23 | val (_, contract) = deployContract("Fibonacci") 24 | 25 | val getNewRes = contract.getNewFib(6).call() 26 | 27 | getNewRes.error shouldBe None 28 | contract.storage.load(0) shouldBe BigInt(8) 29 | 30 | val getStoredRes = contract.getStoredFib().call() 31 | 32 | getStoredRes.error shouldBe None 33 | getStoredRes.returnData shouldBe UInt256(8).bytes 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/MutualRecursionSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import io.iohk.ethereum.domain.UInt256 5 | import org.scalatest.freespec.AnyFreeSpec 6 | import org.scalatest.matchers.should.Matchers 7 | 8 | // scalastyle:off magic.number 9 | class MutualRecursionSpec extends AnyFreeSpec with Matchers { 10 | 11 | "EVM running MutualRecursion contract" - { 12 | 13 | "should handle a call to mutually recursive functions" in new EvmTestEnv { 14 | val (_, contract) = deployContract("MutualRecursion") 15 | 16 | val isOddRes = contract.isOdd(9).call() 17 | 18 | isOddRes.error shouldBe None 19 | isOddRes.returnData shouldBe UInt256(true).bytes 20 | 21 | val isEvenRes = contract.isEven(99).call() 22 | isEvenRes.error shouldBe None 23 | isEvenRes.returnData shouldBe UInt256(false).bytes 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/ThrowSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.vm.utils.EvmTestEnv 4 | import org.scalatest.freespec.AnyFreeSpec 5 | import org.scalatest.matchers.should.Matchers 6 | 7 | // scalastyle:off magic.number 8 | class ThrowSpec extends AnyFreeSpec with Matchers { 9 | 10 | "EVM running Throw contract" - { 11 | 12 | "should handle throwing" in new EvmTestEnv { 13 | val (_, contract) = deployContract("Throw") 14 | 15 | val result = contract.justThrow().call() 16 | 17 | result.error shouldBe Some(InvalidOpCode(0xfe.toByte)) 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/utils/ABI.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm.utils 2 | 3 | import ABI._ 4 | 5 | object ABI { 6 | case class Param(name: String, `type`: String) 7 | } 8 | 9 | case class ABI(`type`: String, name: String = "", inputs: Seq[Param] = Nil, outputs: Seq[Param] = Nil) { 10 | val shortSignature = s"$name(${inputs.map(_.`type`).mkString(",")})" 11 | 12 | val fullSignature = { 13 | val in = inputs.map(i => i.`type` + " " + i.name).mkString(", ") 14 | val out = outputs.map { o => 15 | val s = if (o.name.isEmpty) "" else " " 16 | o.`type` + s + o.name 17 | }.mkString(", ") 18 | 19 | s"$name($in) returns ($out)" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/evmTest/scala/io/iohk/ethereum/vm/utils/Utils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm.utils 2 | 3 | import java.io.File 4 | 5 | import akka.util.ByteString 6 | import io.circe.parser.decode 7 | import io.circe.generic.extras.Configuration 8 | import io.circe.generic.extras.auto._ 9 | import io.circe.Error 10 | import scala.io.Source 11 | 12 | object Utils { 13 | 14 | def loadContractCodeFromFile(file: File): ByteString = { 15 | val src = Source.fromFile(file) 16 | val raw = try { src.mkString } finally { src.close() } 17 | ByteString(raw.trim.grouped(2).map(Integer.parseInt(_, 16).toByte).toArray) 18 | } 19 | 20 | def loadContractAbiFromFile(file: File): Either[Error, List[ABI]] = { 21 | val src = Source.fromFile(file) 22 | val raw = try { src.mkString } finally { src.close() } 23 | implicit val config = Configuration.default.withDefaults 24 | decode[List[ABI]](raw) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/it/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ${stdoutEncoderPattern} 9 | 10 | 11 | 12 | 13 | ${user.home}/.mantis/logs/mantis.log 14 | true 15 | 16 | ${user.home}/.mantis/logs/mantis.%i.log.zip 17 | 1 18 | 10 19 | 20 | 21 | 10MB 22 | 23 | 24 | ${fileEncoderPattern} 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/it/resources/txExecTest/chainDump.conf: -------------------------------------------------------------------------------- 1 | node = "enode://9e56c4eb31089d9b6b40c183f0e549ca5be049dbb22f4b0e25f4955e19d580915ddc32ec26ff38693cbf6954ff743478e42a532b37e3c7a87415067d81c019d5@192.168.1.207:30303" 2 | genesisHash = "c2503fa5d31cc3daf8a97ea57a15d2bee8e867252e2d8d6fdb84eedc17309e55" 3 | networkId = 146 4 | startBlock = 0 5 | maxBlocks = 20 -------------------------------------------------------------------------------- /src/it/resources/txExecTest/documentation/ForksTestContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.0; 2 | 3 | contract ForksTestContract { 4 | 5 | uint256 aVar = 0; 6 | 7 | function ForksTestContract() payable { 8 | } 9 | 10 | function selfDestruct(address refundAddr) { 11 | selfdestruct(refundAddr); 12 | } 13 | 14 | function exp() { 15 | aVar = 4 ** 5; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/it/resources/txExecTest/documentation/keys/Morden/UTC--2017-03-30T13-06-44Z--a9d65fec-d670-1470-9ba1-72b7c3d662f8: -------------------------------------------------------------------------------- 1 | {"id":"a9d65fec-d670-1470-9ba1-72b7c3d662f8","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"ce5d070e8ceb057fcde28536b9e96826"},"ciphertext":"9a6301d7583b04f21272f890ad38a637f547829e74bf006f18ade848b7f5b1d9","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"3d9bde9e4ab273e44ff9c7eebf26d9b65022e9241e9a8b7b1ca9ea7d9f9127b8"},"mac":"423cc3186751237296ac4089012f2d312f4924abb5c4189cbf5061cdae9c012f"},"address":"004a44da31bb735cb20171aff69e60e3e50d26de","name":"","meta":"{}"} -------------------------------------------------------------------------------- /src/it/resources/txExecTest/documentation/keys/Morden/UTC--2017-03-30T15-27-28Z--301e308a-bd95-4334-9b13-b12bc21d2876: -------------------------------------------------------------------------------- 1 | {"id":"301e308a-bd95-4334-9b13-b12bc21d2876","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"454bbfcb17ef39a2b83dfd158a9113a8"},"ciphertext":"899bfb195e63ef1c3ec2e44f24f374ad615efe466a4064c087162700b7f42a97","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"e99f5f4bb0269081996f6258d7b6c18d924010a860a77c73114c78d8f3150796"},"mac":"3e2285bc45ba42a9b9485b44466c1e53f28aabb281c4dfb092e94362c68f2a0b"},"address":"71583ed3034345dd8224c491e2b4584f4d271ab8","name":"","meta":"{}"} -------------------------------------------------------------------------------- /src/it/resources/txExecTest/documentation/keys/Morden/UTC--2017-04-03T13-49-13Z--c703a1ec-96ea-305a-717f-3a65269c472d: -------------------------------------------------------------------------------- 1 | {"id":"c703a1ec-96ea-305a-717f-3a65269c472d","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"a16bff3b4d27241a1dc27ef2135cbce1"},"ciphertext":"ebf4ec9c8d652fbd76c022c04d972840508fbacbbac6ac524264abf115deb2f5","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"5bc70fb61eaf71e62cd7a48f551727e6e8cd741d3330a1ff9b27a7e6190044ca"},"mac":"5fdb35c3c63aeefca9436380f4acaaec994e79a6126901a2e51221035a1e2bc4"},"address":"b2d985ffa6999e8d1dd4c87290c316d0d5414275","name":"","meta":"{}"} -------------------------------------------------------------------------------- /src/it/resources/txExecTest/documentation/readme.md: -------------------------------------------------------------------------------- 1 | command for running parity and ethminer 2 | 3 | ``` 4 | parity -jw --jsonrpc-interface 127.0.0.1 --jsonrpc-port 8545 --author 004A44Da31Bb735cB20171AfF69E60E3e50d26De --identity parity_node --geth --chain path_to_private_chain_conf/prv.json --base-path /tmp/etc_prv --pruning archive 5 | ethminer -C -F 127.0.0.1:8545 6 | ``` 7 | example private network configuration is in `prv.json` 8 | 9 | address for private net: 10 | 11 | private key is included in keys folder and pass phrase is `rHmAnRF/u+K28QFv6#3Qs8t]J,QW` 12 | 13 | main 14 | 0x004A44Da31Bb735cB20171AfF69E60E3e50d26De 15 | 16 | seler 17 | 0xB2D985FFa6999E8D1Dd4c87290c316D0d5414275 18 | 19 | buyer 20 | 0x71583ed3034345DD8224c491e2b4584F4D271ab8 21 | 22 | deploy contracts with `Develop > Open Remix IDE` 23 | 24 | 25 | to start with empty chain: 26 | `rm -rf chains dapps network` in /tmp/etc_prv 27 | 28 | `rm -rf ~/.ethash` on every new chain start 29 | 30 | you can use `DumpChainApp` to dump part of block chain with mpt tree, you can configure it with `chainDump.conf` -------------------------------------------------------------------------------- /src/it/resources/txExecTest/ecip1017Test/contractTrees.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/src/it/resources/txExecTest/ecip1017Test/contractTrees.txt -------------------------------------------------------------------------------- /src/it/resources/txExecTest/ecip1017Test/evmCode.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/src/it/resources/txExecTest/ecip1017Test/evmCode.txt -------------------------------------------------------------------------------- /src/it/resources/txExecTest/forksTest/contractTrees.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/src/it/resources/txExecTest/forksTest/contractTrees.txt -------------------------------------------------------------------------------- /src/it/resources/txExecTest/forksTest/evmCode.txt: -------------------------------------------------------------------------------- 1 | fc8746388fbb2d5503b454c91622ecc89379068678febecc70a9f518e1976c25 606060405263ffffffff60e060020a6000350416633f5a0bdd8114602c578063ab60ffda146051575b6000565b34600057604f73ffffffffffffffffffffffffffffffffffffffff60043516605d565b005b34600057604f6079565b005b8073ffffffffffffffffffffffffffffffffffffffff16ff5b50565b6104006000555b5600a165627a7a723058205625d1ed8713ff622ca7baf3fb7cdcc9260b952f90a69875850e913da8e482da0029 2 | -------------------------------------------------------------------------------- /src/it/scala/io/iohk/ethereum/db/RocksDbDataSourceIntegrationSuite.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | import io.iohk.ethereum.db.dataSource.RocksDbConfig 6 | import io.iohk.ethereum.db.dataSource.RocksDbDataSource 7 | import io.iohk.ethereum.db.storage.Namespaces 8 | 9 | class RocksDbDataSourceIntegrationSuite extends AnyFlatSpec with DataSourceIntegrationTestBehavior { 10 | 11 | private def createDataSource(dataSourcePath: String) = RocksDbDataSource( 12 | new RocksDbConfig { 13 | override val createIfMissing: Boolean = true 14 | override val paranoidChecks: Boolean = true 15 | override val path: String = dataSourcePath 16 | override val maxThreads: Int = 1 17 | override val maxOpenFiles: Int = 32 18 | override val verifyChecksums: Boolean = true 19 | override val levelCompaction: Boolean = true 20 | override val blockSize: Long = 16384 21 | override val blockCacheSize: Long = 33554432 22 | }, 23 | Namespaces.nsSeq 24 | ) 25 | 26 | (it should behave).like(dataSource(createDataSource)) 27 | } 28 | -------------------------------------------------------------------------------- /src/it/scala/io/iohk/ethereum/sync/util/SyncCommonItSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.sync.util 2 | 3 | import java.net.InetSocketAddress 4 | import java.net.ServerSocket 5 | 6 | import io.iohk.ethereum.domain.Block 7 | import io.iohk.ethereum.domain.ChainWeight 8 | import io.iohk.ethereum.ledger.InMemoryWorldStateProxy 9 | 10 | object SyncCommonItSpec { 11 | val IdentityUpdate: (BigInt, InMemoryWorldStateProxy) => InMemoryWorldStateProxy = (_, world) => world 12 | 13 | def randomAddress(): InetSocketAddress = { 14 | val s = new ServerSocket(0) 15 | try new InetSocketAddress("localhost", s.getLocalPort) 16 | finally s.close() 17 | } 18 | 19 | final case class BlockchainState( 20 | bestBlock: Block, 21 | currentWorldState: InMemoryWorldStateProxy, 22 | currentWeight: ChainWeight 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /src/it/scala/io/iohk/ethereum/txExecTest/ScenarioSetup.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.txExecTest 2 | 3 | import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup 4 | import io.iohk.ethereum.domain.BlockchainImpl 5 | import io.iohk.ethereum.domain.BlockchainReader 6 | import io.iohk.ethereum.domain.BlockchainStorages 7 | import io.iohk.ethereum.domain.BlockchainWriter 8 | import io.iohk.ethereum.ledger.VMImpl 9 | 10 | trait ScenarioSetup extends EphemBlockchainTestSetup { 11 | protected val testBlockchainStorages: BlockchainStorages 12 | 13 | override lazy val blockchainReader: BlockchainReader = BlockchainReader(testBlockchainStorages) 14 | override lazy val blockchainWriter: BlockchainWriter = BlockchainWriter(testBlockchainStorages) 15 | override lazy val blockchain: BlockchainImpl = BlockchainImpl(testBlockchainStorages, blockchainReader) 16 | override lazy val vm: VMImpl = new VMImpl 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | include "conf/base.conf" 2 | -------------------------------------------------------------------------------- /src/main/resources/conf/app.conf: -------------------------------------------------------------------------------- 1 | # This is the base configuration file for the Mantis ETC client. 2 | 3 | # This where all the default settings are defined. 4 | # It should always go at the top. 5 | include "base.conf" 6 | -------------------------------------------------------------------------------- /src/main/resources/conf/chains/mordor-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "difficulty": "0x20000", 3 | "extraData": "0x70686f656e697820636869636b656e206162737572642062616e616e61", 4 | "gasLimit": "0x2fefd8", 5 | "nonce": "0x0000000000000000", 6 | "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 7 | "timestamp": "0x5d9676db", 8 | "coinbase": "0x0000000000000000000000000000000000000000", 9 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "alloc": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/conf/chains/pottery-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "difficulty": "0x400", 3 | "extraData": "0x70686f656e697820636869636b656e206162737572642062616e616e61", 4 | "gasLimit": "0x7A1200", 5 | "nonce": "0x0000000000000000", 6 | "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 7 | "timestamp": "0x5d9676db", 8 | "coinbase": "0x0000000000000000000000000000000000000000", 9 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "alloc": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/conf/etc.conf: -------------------------------------------------------------------------------- 1 | include "app.conf" 2 | 3 | mantis { 4 | blockchains { 5 | network = "etc" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/conf/eth.conf: -------------------------------------------------------------------------------- 1 | include "app.conf" 2 | 3 | mantis { 4 | blockchains { 5 | network = "eth" 6 | } 7 | 8 | pruning { 9 | mode = "inmemory" 10 | history = 64 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/conf/metrics.conf: -------------------------------------------------------------------------------- 1 | mantis.metrics { 2 | # Set to `true` if your deployment supports metrics collection. 3 | # We expose metrics using a Prometheus server 4 | # We default to `false` here because we do not expect all deployments to support metrics collection. 5 | enabled = false 6 | 7 | # The port for setting up a Prometheus server over localhost. 8 | port = 13798 9 | } 10 | 11 | kamon.instrumentation.akka.filters { 12 | 13 | actors.track { 14 | includes = [ "mantis_system/user/*" ] 15 | } 16 | 17 | dispatchers { 18 | includes = ["**"] 19 | } 20 | 21 | routers { 22 | includes = ["**"] 23 | } 24 | 25 | groups { 26 | worker-actors { 27 | includes = [ "mantis_system/user/*" ] 28 | } 29 | } 30 | } 31 | 32 | kanela.show-banner = false 33 | -------------------------------------------------------------------------------- /src/main/resources/conf/mordor.conf: -------------------------------------------------------------------------------- 1 | include "app.conf" 2 | 3 | mantis { 4 | blockchains { 5 | network = "mordor" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/conf/sagano.conf: -------------------------------------------------------------------------------- 1 | include "testnet-internal-nomad.conf" -------------------------------------------------------------------------------- /src/main/resources/conf/testmode.conf: -------------------------------------------------------------------------------- 1 | include "app.conf" 2 | 3 | mantis { 4 | 5 | testmode = true 6 | 7 | sync.do-fast-sync = false 8 | 9 | network.discovery { 10 | discovery-enabled = false 11 | } 12 | 13 | pruning.mode = "archive" 14 | 15 | blockchains { 16 | network = "test" 17 | 18 | test { 19 | chain-id = 1 20 | 21 | frontier-block-number = 0 22 | 23 | homestead-block-number = 0 24 | 25 | eip106-block-number = 0 26 | 27 | eip150-block-number = 0 28 | 29 | eip155-block-number = 0 30 | 31 | eip160-block-number = 0 32 | 33 | eip161-block-number = 0 34 | 35 | byzantium-block-number = 0 36 | 37 | constantinople-block-number = 0 38 | 39 | istanbul-block-number = 0 40 | 41 | atlantis-block-number = 0 42 | 43 | agharta-block-number = 0 44 | 45 | phoenix-block-number = 0 46 | 47 | petersburg-block-number = 0 48 | } 49 | } 50 | 51 | network { 52 | rpc.apis = "eth,web3,net,personal,mantis,test,iele,debug,qa,checkpointing" 53 | automatic-port-forwarding = false 54 | } 55 | 56 | } 57 | 58 | akka.http.server.request-timeout = 30.seconds 59 | -------------------------------------------------------------------------------- /src/main/resources/conf/testnet-internal-nomad.conf: -------------------------------------------------------------------------------- 1 | include "base-testnet.conf" 2 | 3 | mantis { 4 | blockchains { 5 | network = "testnet-internal-nomad" 6 | } 7 | 8 | network { 9 | discovery { 10 | discovery-enabled = true 11 | } 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/mallet.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | # to enable logging use: ["akka.event.slf4j.Slf4jLogger"] 3 | loggers = [] 4 | 5 | loglevel = OFF 6 | 7 | ssl-config { 8 | trustManager = { 9 | stores = [ 10 | # TODO: move to Wiki maybe? 11 | # When running Mantis with a self signed certificate as described in https://github.com/input-output-hk/mantis/wiki/Configuring-HTTPS-for-JSON-RPC, 12 | # we need to mark the public version of the certificate as trusted for mallet. To do that run: 13 | # 14 | # keytool -export -v \ 15 | # -alias mantis \ 16 | # -file path/to/mantis.crt \ 17 | # -keypass:env PW \ 18 | # -storepass:env PW \ 19 | # -keystore path/to/mantisCA.jks \ 20 | # -rfc 21 | # 22 | # and uncomment the entry below, adjusting the path: 23 | # 24 | # { type = "PEM", path = "path/to/mantis.crt" } 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/KeyTool.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | object KeyTool { 4 | 5 | def main(args: Array[String]): Unit = sun.security.tools.keytool.Main.main(args) 6 | } 7 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/Mantis.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import java.util.logging.LogManager 4 | 5 | import org.rocksdb 6 | 7 | import io.iohk.ethereum.nodebuilder.StdNode 8 | import io.iohk.ethereum.nodebuilder.TestNode 9 | import io.iohk.ethereum.utils.Config 10 | import io.iohk.ethereum.utils.Logger 11 | 12 | object Mantis extends Logger { 13 | def main(args: Array[String]): Unit = { 14 | LogManager.getLogManager().reset(); // disable java.util.logging, ie. in legacy parts of jupnp 15 | 16 | val node = 17 | if (Config.testmode) { 18 | log.info("Starting Mantis in test mode") 19 | deleteRocksDBFiles() 20 | new TestNode 21 | } else new StdNode 22 | 23 | log.info("Mantis app {}", Config.clientVersion) 24 | log.info("Using network {}", Config.blockchains.network) 25 | 26 | node.start() 27 | } 28 | 29 | private def deleteRocksDBFiles(): Unit = { 30 | log.warn("Deleting previous database {}", Config.Db.RocksDb.path) 31 | rocksdb.RocksDB.destroyDB(Config.Db.RocksDb.path, new rocksdb.Options()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/blockchain/data/genesis.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.blockchain.data 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.UInt256 6 | 7 | case class PrecompiledAccountConfig(name: String) 8 | 9 | case class GenesisAccount( 10 | precompiled: Option[PrecompiledAccountConfig], 11 | balance: UInt256, 12 | code: Option[ByteString], 13 | nonce: Option[UInt256], 14 | storage: Option[Map[UInt256, UInt256]] 15 | ) 16 | 17 | case class GenesisData( 18 | nonce: ByteString, 19 | mixHash: Option[ByteString], 20 | difficulty: String, 21 | extraData: ByteString, 22 | gasLimit: String, 23 | coinbase: ByteString, 24 | timestamp: String, 25 | alloc: Map[String, GenesisAccount] 26 | ) 27 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/blockchain/sync/PeerComparator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.blockchain 2 | 3 | import io.iohk.ethereum.network.EtcPeerManagerActor.PeerInfo 4 | 5 | object PeerComparator { 6 | 7 | def doPeersHaveSameBestBlock(peerInfo1: PeerInfo, peerInfo2: PeerInfo): Boolean = 8 | peerInfo1.bestBlockHash == peerInfo2.bestBlockHash 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/blockchain/sync/SyncProtocol.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.blockchain.sync 2 | import io.iohk.ethereum.domain.Block 3 | 4 | object SyncProtocol { 5 | sealed trait SyncProtocolMsg 6 | case object Start extends SyncProtocolMsg 7 | case object GetStatus extends SyncProtocolMsg 8 | case class MinedBlock(block: Block) extends SyncProtocolMsg 9 | 10 | sealed trait Status { 11 | def syncing: Boolean = this match { 12 | case Status.Syncing(_, _, _) => true 13 | case Status.NotSyncing => false 14 | case Status.SyncDone => false 15 | } 16 | 17 | def notSyncing: Boolean = !syncing 18 | } 19 | object Status { 20 | case class Progress(current: BigInt, target: BigInt) { 21 | val isEmpty: Boolean = current == 0 && target == 0 22 | val nonEmpty: Boolean = !isEmpty 23 | } 24 | object Progress { 25 | val empty: Progress = Progress(0, 0) 26 | } 27 | case class Syncing( 28 | startingBlockNumber: BigInt, 29 | blocksProgress: Progress, 30 | stateNodesProgress: Option[Progress] // relevant only in fast sync, but is required by RPC spec 31 | ) extends Status 32 | 33 | case object NotSyncing extends Status 34 | case object SyncDone extends Status 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/blockchain/sync/regular/BlockImportResult.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.blockchain.sync.regular 2 | 3 | import io.iohk.ethereum.domain.Block 4 | import io.iohk.ethereum.domain.ChainWeight 5 | import io.iohk.ethereum.ledger.BlockData 6 | import io.iohk.ethereum.mpt.MerklePatriciaTrie.MissingNodeException 7 | 8 | sealed trait BlockImportResult 9 | 10 | case class BlockImportedToTop(blockImportData: List[BlockData]) extends BlockImportResult 11 | 12 | case object BlockEnqueued extends BlockImportResult 13 | 14 | case object DuplicateBlock extends BlockImportResult 15 | 16 | case class ChainReorganised( 17 | oldBranch: List[Block], 18 | newBranch: List[Block], 19 | weights: List[ChainWeight] 20 | ) extends BlockImportResult 21 | 22 | case class BlockImportFailed(error: String) extends BlockImportResult 23 | 24 | case class BlockImportFailedDueToMissingNode(reason: MissingNodeException) extends BlockImportResult 25 | 26 | case object UnknownParent extends BlockImportResult 27 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/cli/CliLauncher.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.cli 2 | 3 | import scala.collection.immutable.ArraySeq 4 | 5 | import com.monovore.decline._ 6 | 7 | //scalastyle:off 8 | object CliLauncher extends App { 9 | 10 | private val arguments: Seq[String] = PlatformApp.ambientArgs.getOrElse(ArraySeq.unsafeWrapArray(args)) 11 | CliCommands.api.map(println).parse(arguments, sys.env) match { 12 | case Left(help) => System.err.println(help) 13 | case Right(_) => () 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/blocks/BlockTimestampProvider.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.blocks 2 | 3 | import java.time.Instant 4 | 5 | trait BlockTimestampProvider { 6 | def getEpochSecond: Long 7 | } 8 | 9 | object DefaultBlockTimestampProvider extends BlockTimestampProvider { 10 | override def getEpochSecond: Long = Instant.now.getEpochSecond 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/blocks/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus 2 | 3 | import io.iohk.ethereum.domain.Block 4 | import io.iohk.ethereum.domain.Receipt 5 | import io.iohk.ethereum.ledger.InMemoryWorldStateProxy 6 | 7 | package object blocks { 8 | case class PendingBlock(block: Block, receipts: Seq[Receipt]) 9 | case class PendingBlockAndState(pendingBlock: PendingBlock, worldState: InMemoryWorldStateProxy) 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/difficulty/DifficultyCalculator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.difficulty 2 | 3 | import io.iohk.ethereum.consensus.pow.difficulty.EthashDifficultyCalculator 4 | import io.iohk.ethereum.consensus.pow.difficulty.TargetTimeDifficultyCalculator 5 | import io.iohk.ethereum.domain.BlockHeader 6 | import io.iohk.ethereum.utils.BlockchainConfig 7 | 8 | trait DifficultyCalculator { 9 | def calculateDifficulty(blockNumber: BigInt, blockTimestamp: Long, parent: BlockHeader)(implicit 10 | blockchainConfig: BlockchainConfig 11 | ): BigInt 12 | } 13 | 14 | object DifficultyCalculator extends DifficultyCalculator { 15 | 16 | def calculateDifficulty(blockNumber: BigInt, blockTimestamp: Long, parent: BlockHeader)(implicit 17 | blockchainConfig: BlockchainConfig 18 | ): BigInt = 19 | (blockchainConfig.powTargetTime match { 20 | case Some(targetTime) => new TargetTimeDifficultyCalculator(targetTime) 21 | case None => EthashDifficultyCalculator 22 | }).calculateDifficulty(blockNumber, blockTimestamp, parent) 23 | 24 | val DifficultyBoundDivision: Int = 2048 25 | val FrontierTimestampDiffLimit: Int = -99 26 | val MinimumDifficulty: BigInt = 131072 27 | } 28 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/mining/FullMiningConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | case class FullMiningConfig[C <: AnyRef /*Product*/ ]( 4 | generic: MiningConfig, 5 | specific: C 6 | ) { 7 | final def miningEnabled: Boolean = generic.miningEnabled 8 | } 9 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/mining/MiningConfigBuilder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | import io.iohk.ethereum.utils.Config 4 | 5 | trait MiningConfigBuilder { 6 | protected def buildMiningConfig(): MiningConfig = MiningConfig(Config.config) 7 | 8 | lazy val miningConfig: MiningConfig = buildMiningConfig() 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/mining/MiningMetrics.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | import io.micrometer.core.instrument.Timer 4 | 5 | import io.iohk.ethereum.metrics.MetricsContainer 6 | 7 | object MiningMetrics extends MetricsContainer { 8 | final private val blockGenTimer = "mining.blocks.generate.timer" 9 | final val PoWBlockGeneratorTiming: Timer = metrics.timer(blockGenTimer, "class", "PoWBlockGenerator") 10 | final val RestrictedPoWBlockGeneratorTiming: Timer = 11 | metrics.timer(blockGenTimer, "class", "RestrictedPoWBlockGenerator") 12 | final val NoOmmersBlockGeneratorTiming: Timer = metrics.timer(blockGenTimer, "class", "NoOmmersBlockGenerator") 13 | 14 | final val MinedBlockEvaluationTimer: Timer = metrics.timer("mining.minedblocks.evaluation.timer") 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/mining/TestMiningBuilder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | import io.iohk.ethereum.nodebuilder._ 4 | import io.iohk.ethereum.security.SecureRandomBuilder 5 | import io.iohk.ethereum.utils.Logger 6 | 7 | /** A [[MiningBuilder]] that builds a [[TestMining]] 8 | */ 9 | trait TestMiningBuilder { self: StdMiningBuilder => 10 | protected def buildTestMining(): TestMining = 11 | buildMining().asInstanceOf[TestMining] // we are in tests, so if we get an exception, so be it 12 | } 13 | 14 | /** A standard [[TestMiningBuilder]] cake. */ 15 | trait StdTestMiningBuilder 16 | extends StdMiningBuilder 17 | with TestMiningBuilder 18 | with VmBuilder 19 | with VmConfigBuilder 20 | with ActorSystemBuilder 21 | with BlockchainBuilder 22 | with BlockQueueBuilder 23 | with ConsensusBuilder 24 | with StorageBuilder 25 | with BlockchainConfigBuilder 26 | with NodeKeyBuilder 27 | with SecureRandomBuilder 28 | with SyncConfigBuilder 29 | with MiningConfigBuilder 30 | with ShutdownHookBuilder 31 | with Logger 32 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/KeccakCalculation.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.crypto.kec256 6 | import io.iohk.ethereum.crypto.kec256PoW 7 | import io.iohk.ethereum.utils.ByteUtils 8 | 9 | object KeccakCalculation { 10 | 11 | final val difficultyNumerator: BigInt = BigInt(2).pow(256) 12 | 13 | /** Computation of mixHash = keccak256(keccak256(rlp(unsealed header)), nonce) 14 | * @param hashHeader the rlp(unsealed header) 15 | * @return KeccakProofOWork containing the computed mixHash 16 | */ 17 | def hash(hashHeader: Array[Byte], nonce: BigInt): KeccakMixHash = { 18 | val preHash = ByteString(kec256(hashHeader)).toArray 19 | val nonceBytes = ByteUtils.bigIntToUnsignedByteArray(nonce) 20 | val mixHash = kec256PoW(preHash, nonceBytes) 21 | 22 | KeccakMixHash(mixHash = ByteString(mixHash)) 23 | } 24 | 25 | /** Validates if mixHash <= 2^256 / difficulty 26 | * @param mixHash 27 | * @param difficulty 28 | * @return boolean indicating whether PoW is valid or not 29 | */ 30 | def isMixHashValid(mixHash: ByteString, difficulty: BigInt): Boolean = { 31 | val mixHashInt = BigInt.apply(mixHash.toArray) 32 | val threshold = difficultyNumerator / difficulty 33 | mixHashInt <= threshold 34 | } 35 | 36 | final case class KeccakMixHash(mixHash: ByteString) 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/blocks/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow 2 | 3 | import io.iohk.ethereum.domain.BlockHeader 4 | import io.iohk.ethereum.domain.BlockHeaderImplicits._ 5 | import io.iohk.ethereum.rlp.RLPEncodeable 6 | import io.iohk.ethereum.rlp.RLPList 7 | import io.iohk.ethereum.rlp.RLPSerializable 8 | 9 | package object blocks { 10 | 11 | /** This is type `X` in `BlockGenerator`. 12 | * 13 | * @see [[io.iohk.ethereum.consensus.pow.blocks.PoWBlockGenerator EthashBlockGenerator]], 14 | * [[io.iohk.ethereum.consensus.blocks.BlockGenerator.X BlockGenerator{ type X}]] 15 | */ 16 | final type Ommers = Seq[BlockHeader] 17 | 18 | implicit class OmmersSeqEnc(blockHeaders: Seq[BlockHeader]) extends RLPSerializable { 19 | override def toRLPEncodable: RLPEncodeable = RLPList(blockHeaders.map(_.toRLPEncodable): _*) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/miners/MinerProtocol.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow.miners 2 | 3 | import akka.actor.typed.ActorRef 4 | import akka.util.ByteString 5 | 6 | import io.iohk.ethereum.consensus.pow.PoWMiningCoordinator.CoordinatorProtocol 7 | import io.iohk.ethereum.domain.Block 8 | 9 | trait MinerProtocol 10 | 11 | object MinerProtocol { 12 | case object StartMining extends MinerProtocol 13 | case object StopMining extends MinerProtocol 14 | final case class ProcessMining(currentBestBlock: Block, replyTo: ActorRef[CoordinatorProtocol]) extends MinerProtocol 15 | 16 | sealed trait MiningResult { 17 | def triedHashes: Int 18 | } 19 | case class MiningSuccessful(triedHashes: Int, mixHash: ByteString, nonce: ByteString) extends MiningResult 20 | case class MiningUnsuccessful(triedHashes: Int) extends MiningResult 21 | } 22 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/validators/KeccakBlockHeaderValidator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow.validators 2 | 3 | import io.iohk.ethereum.consensus.pow.KeccakCalculation 4 | import io.iohk.ethereum.consensus.validators.BlockHeaderError 5 | import io.iohk.ethereum.consensus.validators.BlockHeaderError.HeaderPoWError 6 | import io.iohk.ethereum.consensus.validators.BlockHeaderValid 7 | import io.iohk.ethereum.domain.BlockHeader 8 | 9 | object KeccakBlockHeaderValidator { 10 | 11 | /** Validates [[io.iohk.ethereum.domain.BlockHeader.nonce]] and [[io.iohk.ethereum.domain.BlockHeader.mixHash]] are correct 12 | * @param blockHeader 13 | * @return BlockHeaderValid if valid or an BlockHeaderError.HeaderPoWError otherwise 14 | */ 15 | def validateHeader(blockHeader: BlockHeader): Either[BlockHeaderError, BlockHeaderValid] = { 16 | val rlpEncodedHeader = BlockHeader.getEncodedWithoutNonce(blockHeader) 17 | val expectedHash = KeccakCalculation.hash(rlpEncodedHeader, BigInt(blockHeader.nonce.toArray)) 18 | 19 | lazy val isDifficultyValid = KeccakCalculation.isMixHashValid(blockHeader.mixHash, blockHeader.difficulty) 20 | 21 | if (expectedHash.mixHash == blockHeader.mixHash && isDifficultyValid) Right(BlockHeaderValid) 22 | else Left(HeaderPoWError) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/validators/MockedPowBlockHeaderValidator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow 2 | package validators 3 | 4 | import io.iohk.ethereum.consensus.validators.BlockHeaderError 5 | import io.iohk.ethereum.consensus.validators.BlockHeaderValid 6 | import io.iohk.ethereum.consensus.validators.BlockHeaderValidatorSkeleton 7 | import io.iohk.ethereum.domain.BlockHeader 8 | import io.iohk.ethereum.utils.BlockchainConfig 9 | 10 | object MockedPowBlockHeaderValidator extends BlockHeaderValidatorSkeleton { 11 | 12 | override def validateEvenMore(blockHeader: BlockHeader)(implicit 13 | blockchainConfig: BlockchainConfig 14 | ): Either[BlockHeaderError, BlockHeaderValid] = 15 | Right(BlockHeaderValid) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/validators/PoWBlockHeaderValidator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow.validators 2 | 3 | import io.iohk.ethereum.consensus.validators.BlockHeaderError 4 | import io.iohk.ethereum.consensus.validators.BlockHeaderValid 5 | import io.iohk.ethereum.consensus.validators.BlockHeaderValidatorSkeleton 6 | import io.iohk.ethereum.domain.BlockHeader 7 | import io.iohk.ethereum.utils.BlockchainConfig 8 | 9 | object PoWBlockHeaderValidator extends BlockHeaderValidatorSkeleton { 10 | 11 | /** A hook where even more mining-specific validation can take place. 12 | * For example, PoW validation is done here. 13 | */ 14 | override protected[validators] def validateEvenMore( 15 | blockHeader: BlockHeader 16 | )(implicit blockchainConfig: BlockchainConfig): Either[BlockHeaderError, BlockHeaderValid] = 17 | if (isKeccak(blockHeader.number)) KeccakBlockHeaderValidator.validateHeader(blockHeader) 18 | else EthashBlockHeaderValidator.validateHeader(blockHeader) 19 | 20 | private def isKeccak(currentBlockNumber: BigInt)(implicit blockchainConfig: BlockchainConfig): Boolean = 21 | blockchainConfig.forkBlockNumbers.ecip1049BlockNumber match { 22 | case Some(keccakBlock) => currentBlockNumber >= keccakBlock 23 | case None => false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/pow/validators/StdValidatorsExecutor.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.pow.validators 2 | 3 | import io.iohk.ethereum.consensus.validators.BlockHeaderValidator 4 | import io.iohk.ethereum.consensus.validators.BlockValidator 5 | import io.iohk.ethereum.consensus.validators.SignedTransactionValidator 6 | 7 | /** Implements validators that adhere to the PoW-specific 8 | * [[io.iohk.ethereum.consensus.pow.validators.ValidatorsExecutor]] 9 | * interface. 10 | */ 11 | final class StdValidatorsExecutor private[validators] ( 12 | val blockValidator: BlockValidator, 13 | val blockHeaderValidator: BlockHeaderValidator, 14 | val signedTransactionValidator: SignedTransactionValidator, 15 | val ommersValidator: OmmersValidator 16 | ) extends ValidatorsExecutor 17 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/consensus/validators/BlockValidator.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.validators 2 | 3 | import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockError 4 | import io.iohk.ethereum.consensus.validators.std.StdBlockValidator.BlockValid 5 | import io.iohk.ethereum.domain.BlockBody 6 | import io.iohk.ethereum.domain.BlockHeader 7 | import io.iohk.ethereum.domain.Receipt 8 | 9 | trait BlockValidator { 10 | def validateHeaderAndBody(blockHeader: BlockHeader, blockBody: BlockBody): Either[BlockError, BlockValid] 11 | 12 | def validateBlockAndReceipts(blockHeader: BlockHeader, receipts: Seq[Receipt]): Either[BlockError, BlockValid] 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/crypto/ECDSASignatureImplicits.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.crypto 2 | 3 | import akka.util.ByteString 4 | 5 | object ECDSASignatureImplicits { 6 | 7 | import io.iohk.ethereum.rlp.RLPImplicitConversions._ 8 | import io.iohk.ethereum.rlp.RLPImplicits._ 9 | import io.iohk.ethereum.rlp._ 10 | 11 | implicit val ecdsaSignatureDec: RLPDecoder[ECDSASignature] = new RLPDecoder[ECDSASignature] { 12 | override def decode(rlp: RLPEncodeable): ECDSASignature = rlp match { 13 | case RLPList(r, s, v) => ECDSASignature(r: ByteString, s: ByteString, v) 14 | case _ => throw new RuntimeException("Cannot decode ECDSASignature") 15 | } 16 | } 17 | 18 | implicit class ECDSASignatureEnc(ecdsaSignature: ECDSASignature) extends RLPSerializable { 19 | override def toRLPEncodable: RLPEncodeable = 20 | RLPList(ecdsaSignature.r, ecdsaSignature.s, ecdsaSignature.v) 21 | } 22 | 23 | implicit val ECDSASignatureOrdering: Ordering[ECDSASignature] = Ordering.by(sig => (sig.r, sig.s, sig.v)) 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/crypto/EcKeyGen.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.crypto 2 | 3 | import io.iohk.ethereum.security.SecureRandomBuilder 4 | 5 | /** A simple tool to generate ECDSA key pairs. Takes an optional positional argument [n] - number of key pairs 6 | * to generate (default is 1). 7 | * The key pairs will be printed in the format: 8 | * priv-key-hex (32 bytes) 9 | * pub-key-hex (64 bytes) 10 | * 11 | * Run: 12 | * ./eckeygen [n] > mantis-datadir/node.key 13 | * 14 | * to generate the private key for the node. Note that only the private key will be read upon Mantis boot, 15 | * and the second line is equivalent to node ID. 16 | * The tool can also be used to generate keys for an Ethereum account. 17 | */ 18 | object EcKeyGen extends App with SecureRandomBuilder { 19 | val numOfKeys: Int = args.headOption.map(_.toInt).getOrElse(1) 20 | 21 | val keyPairs: IndexedSeq[(String, String)] = for (_ <- 1 to numOfKeys) yield newRandomKeyPairAsStrings(secureRandom) 22 | 23 | //scalastyle:off 24 | println(keyPairs.map { case (prv, pub) => s"$prv\n$pub\n" }.mkString("\n")) 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/cache/AppCaches.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.cache 2 | 3 | import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded 4 | import io.iohk.ethereum.db.storage.NodeStorage.NodeHash 5 | import io.iohk.ethereum.utils.Config 6 | 7 | trait AppCaches extends CacheComponent { 8 | val caches: Caches = new Caches { 9 | override val nodeCache: Cache[NodeHash, NodeEncoded] = MapCache.createCache(Config.NodeCacheConfig) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/cache/Cache.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.cache 2 | 3 | import io.iohk.ethereum.common.SimpleMap 4 | 5 | trait Cache[K, V] extends SimpleMap[K, V, Cache[K, V]] { 6 | def getValues: Seq[(K, V)] 7 | def clear(): Unit 8 | def shouldPersist: Boolean 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/cache/CacheComponent.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.cache 2 | 3 | import io.iohk.ethereum.db.storage.NodeStorage 4 | 5 | trait CacheComponent { 6 | val caches: Caches 7 | 8 | trait Caches { 9 | val nodeCache: Cache[NodeStorage.NodeHash, NodeStorage.NodeEncoded] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/components/DataSourceComponent.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.components 2 | 3 | import io.iohk.ethereum.db.dataSource.DataSource 4 | 5 | trait DataSourceComponent { 6 | val dataSource: DataSource 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/components/EphemDataSourceComponent.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.components 2 | 3 | import io.iohk.ethereum.db.dataSource.EphemDataSource 4 | 5 | trait EphemDataSourceComponent extends DataSourceComponent { 6 | val dataSource: EphemDataSource = EphemDataSource() 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/components/RocksDbDataSourceComponent.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.components 2 | 3 | import io.iohk.ethereum.db.dataSource.RocksDbDataSource 4 | import io.iohk.ethereum.db.storage.Namespaces 5 | import io.iohk.ethereum.utils.Config 6 | 7 | trait RocksDbDataSourceComponent extends DataSourceComponent { 8 | 9 | lazy val dataSource: RocksDbDataSource = RocksDbDataSource(Config.Db.RocksDb, Namespaces.nsSeq) 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/components/StoragesComponent.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.components 2 | 3 | import io.iohk.ethereum.db.storage._ 4 | import io.iohk.ethereum.db.storage.pruning.PruningMode 5 | import io.iohk.ethereum.domain.BlockchainStorages 6 | 7 | trait StoragesComponent { 8 | 9 | val storages: Storages 10 | 11 | trait Storages extends BlockchainStorages { 12 | 13 | val blockHeadersStorage: BlockHeadersStorage 14 | 15 | val blockBodiesStorage: BlockBodiesStorage 16 | 17 | val blockNumberMappingStorage: BlockNumberMappingStorage 18 | 19 | val receiptStorage: ReceiptStorage 20 | 21 | val nodeStorage: NodeStorage 22 | 23 | val evmCodeStorage: EvmCodeStorage 24 | 25 | val chainWeightStorage: ChainWeightStorage 26 | 27 | val appStateStorage: AppStateStorage 28 | 29 | val fastSyncStateStorage: FastSyncStateStorage 30 | 31 | val transactionMappingStorage: TransactionMappingStorage 32 | 33 | val knownNodesStorage: KnownNodesStorage 34 | 35 | val pruningMode: PruningMode 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/dataSource/DataSourceBatchUpdate.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.dataSource 2 | 3 | import scala.collection.immutable.ArraySeq 4 | 5 | case class DataSourceBatchUpdate(dataSource: DataSource, updates: Array[DataUpdate] = Array.empty) { 6 | 7 | def and(that: DataSourceBatchUpdate): DataSourceBatchUpdate = { 8 | require( 9 | this.dataSource eq that.dataSource, 10 | "Transactional storage updates must be performed on the same data source" 11 | ) 12 | DataSourceBatchUpdate(dataSource, this.updates ++ that.updates) 13 | } 14 | 15 | def commit(): Unit = 16 | dataSource.update(ArraySeq.unsafeWrapArray(updates)) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/ArchiveNodeStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import io.iohk.ethereum.db.storage.NodeStorage.NodeEncoded 4 | import io.iohk.ethereum.db.storage.NodeStorage.NodeHash 5 | import io.iohk.ethereum.mpt.NodesKeyValueStorage 6 | 7 | /** This class is used to store Nodes (defined in mpt/Node.scala), by using: 8 | * Key: hash of the RLP encoded node 9 | * Value: the RLP encoded node 10 | */ 11 | class ArchiveNodeStorage(nodeStorage: NodesStorage) extends NodesKeyValueStorage { 12 | 13 | override def update(toRemove: Seq[NodeHash], toUpsert: Seq[(NodeHash, NodeEncoded)]): NodesKeyValueStorage = { 14 | nodeStorage.update(Nil, toUpsert) 15 | this 16 | } 17 | 18 | override def get(key: NodeHash): Option[NodeEncoded] = nodeStorage.get(key) 19 | 20 | override def persist(): Unit = {} 21 | } 22 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/BlockNumberMappingStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import java.math.BigInteger 4 | 5 | import akka.util.ByteString 6 | 7 | import scala.collection.immutable.ArraySeq 8 | 9 | import io.iohk.ethereum.db.dataSource.DataSource 10 | import io.iohk.ethereum.db.storage.BlockHeadersStorage.BlockHeaderHash 11 | 12 | class BlockNumberMappingStorage(val dataSource: DataSource) 13 | extends TransactionalKeyValueStorage[BigInt, BlockHeaderHash] { 14 | override val namespace: IndexedSeq[Byte] = Namespaces.HeightsNamespace 15 | 16 | override def keySerializer: (BigInt) => IndexedSeq[Byte] = index => ArraySeq.unsafeWrapArray(index.toByteArray) 17 | 18 | override def keyDeserializer: IndexedSeq[Byte] => BigInt = bytes => new BigInt(new BigInteger(bytes.toArray)) 19 | 20 | override def valueSerializer: (BlockHeaderHash) => IndexedSeq[Byte] = identity 21 | 22 | override def valueDeserializer: (IndexedSeq[Byte]) => BlockHeaderHash = arr => ByteString(arr.toArray[Byte]) 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/CachedKeyValueStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import io.iohk.ethereum.common.SimpleMap 4 | import io.iohk.ethereum.db.cache.Cache 5 | 6 | trait CachedKeyValueStorage[K, V, T <: CachedKeyValueStorage[K, V, T]] extends SimpleMap[K, V, T] { 7 | type I <: KeyValueStorage[K, V, I] 8 | protected val storage: I 9 | protected val cache: Cache[K, V] 10 | def apply(cache: Cache[K, V], storage: I): T 11 | 12 | def get(key: K): Option[V] = cache.get(key).orElse(storage.get(key)) 13 | 14 | def update(toRemove: Seq[K], toUpsert: Seq[(K, V)]): T = { 15 | cache.update(toRemove, toUpsert) 16 | apply(cache, storage) 17 | } 18 | 19 | def updateCond(toRemove: Seq[K], toUpsert: Seq[(K, V)], inMemory: Boolean): T = { 20 | if (inMemory) 21 | cache.update(toRemove, toUpsert) 22 | else 23 | storage.update(toRemove, toUpsert) 24 | 25 | apply(cache, storage) 26 | } 27 | 28 | def forcePersist(): Unit = { 29 | storage.update(Nil, cache.getValues) 30 | cache.clear() 31 | } 32 | 33 | // TODO EC-491 Consider other persist strategy like sliding window (save and clear only old stuff which survived long enough) 34 | def persist(): Boolean = 35 | if (cache.shouldPersist) { 36 | forcePersist() 37 | true 38 | } else { 39 | false 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/ChainWeightStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import akka.util.ByteString 4 | 5 | import boopickle.Default._ 6 | 7 | import io.iohk.ethereum.db.dataSource.DataSource 8 | import io.iohk.ethereum.db.storage.ChainWeightStorage._ 9 | import io.iohk.ethereum.domain.ChainWeight 10 | import io.iohk.ethereum.utils.ByteUtils.byteSequenceToBuffer 11 | import io.iohk.ethereum.utils.ByteUtils.compactPickledBytes 12 | 13 | /** This class is used to store the ChainWeight of blocks, by using: 14 | * Key: hash of the block 15 | * Value: ChainWeight 16 | */ 17 | class ChainWeightStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[BlockHash, ChainWeight] { 18 | val namespace: IndexedSeq[Byte] = Namespaces.ChainWeightNamespace 19 | val keySerializer: BlockHash => ByteString = identity 20 | val keyDeserializer: IndexedSeq[Byte] => BlockHash = bytes => ByteString(bytes: _*) 21 | val valueSerializer: ChainWeight => IndexedSeq[Byte] = (Pickle.intoBytes[ChainWeight] _).andThen(compactPickledBytes) 22 | val valueDeserializer: IndexedSeq[Byte] => ChainWeight = 23 | (byteSequenceToBuffer _).andThen(Unpickle[ChainWeight].fromBytes) 24 | } 25 | 26 | object ChainWeightStorage { 27 | type BlockHash = ByteString 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/EvmCodeStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import akka.util.ByteString 4 | 5 | import monix.reactive.Observable 6 | 7 | import io.iohk.ethereum.db.dataSource.DataSource 8 | import io.iohk.ethereum.db.dataSource.RocksDbDataSource.IterationError 9 | import io.iohk.ethereum.db.storage.EvmCodeStorage._ 10 | 11 | /** This class is used to store the EVM Code, by using: 12 | * Key: hash of the code 13 | * Value: the code 14 | */ 15 | class EvmCodeStorage(val dataSource: DataSource) extends TransactionalKeyValueStorage[CodeHash, Code] { 16 | val namespace: IndexedSeq[Byte] = Namespaces.CodeNamespace 17 | def keySerializer: CodeHash => IndexedSeq[Byte] = identity 18 | def keyDeserializer: IndexedSeq[Byte] => CodeHash = k => ByteString.fromArrayUnsafe(k.toArray) 19 | def valueSerializer: Code => IndexedSeq[Byte] = identity 20 | def valueDeserializer: IndexedSeq[Byte] => Code = (code: IndexedSeq[Byte]) => ByteString(code.toArray) 21 | 22 | // overriding to avoid going through IndexedSeq[Byte] 23 | override def storageContent: Observable[Either[IterationError, (CodeHash, Code)]] = 24 | dataSource.iterate(namespace).map { result => 25 | result.map { case (key, value) => (ByteString.fromArrayUnsafe(key), ByteString.fromArrayUnsafe(value)) } 26 | } 27 | } 28 | 29 | object EvmCodeStorage { 30 | type CodeHash = ByteString 31 | type Code = ByteString 32 | } 33 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/Namespaces.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | object Namespaces { 4 | val ReceiptsNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('r'.toByte) 5 | val HeaderNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('h'.toByte) 6 | val BodyNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('b'.toByte) 7 | val NodeNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('n'.toByte) 8 | val CodeNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('c'.toByte) 9 | val ChainWeightNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('w'.toByte) 10 | val AppStateNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('s'.toByte) 11 | val KnownNodesNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('k'.toByte) 12 | val HeightsNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('i'.toByte) 13 | val FastSyncStateNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('f'.toByte) 14 | val TransactionMappingNamespace: IndexedSeq[Byte] = IndexedSeq[Byte]('l'.toByte) 15 | 16 | val nsSeq: Seq[IndexedSeq[Byte]] = Seq( 17 | ReceiptsNamespace, 18 | HeaderNamespace, 19 | BodyNamespace, 20 | NodeNamespace, 21 | CodeNamespace, 22 | ChainWeightNamespace, 23 | AppStateNamespace, 24 | KnownNodesNamespace, 25 | HeightsNamespace, 26 | FastSyncStateNamespace, 27 | TransactionMappingNamespace 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/StorageStringCharset.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | import java.nio.charset.Charset 4 | 5 | object StorageStringCharset { 6 | val UTF8Charset: Charset = Charset.forName("UTF-8") 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/db/storage/pruning/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.storage 2 | 3 | package object pruning { 4 | 5 | sealed trait PruningMode 6 | case object ArchivePruning extends PruningMode 7 | case class BasicPruning(history: Int) extends PruningMode 8 | case class InMemoryPruning(history: Int) extends PruningMode 9 | 10 | trait PruneSupport { 11 | 12 | /** Remove unused data for the given block number 13 | * @param blockNumber BlockNumber to prune 14 | * @param nodeStorage NodeStorage 15 | */ 16 | def prune(blockNumber: BigInt, nodeStorage: NodesStorage, inMemory: Boolean): Unit 17 | 18 | /** Rollbacks blocknumber changes 19 | * @param blockNumber BlockNumber to rollback 20 | * @param nodeStorage NodeStorage 21 | */ 22 | def rollback(blockNumber: BigInt, nodeStorage: NodesStorage, inMemory: Boolean): Unit 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/ChainWeight.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | object ChainWeight { 4 | //FIXME: a shorter name? 5 | def totalDifficultyOnly(td: BigInt): ChainWeight = 6 | ChainWeight(0, td) 7 | 8 | val zero: ChainWeight = 9 | ChainWeight(0, 0) 10 | } 11 | 12 | case class ChainWeight( 13 | lastCheckpointNumber: BigInt, 14 | totalDifficulty: BigInt 15 | ) extends Ordered[ChainWeight] { 16 | 17 | override def compare(that: ChainWeight): Int = 18 | this.asTuple.compare(that.asTuple) 19 | 20 | def increase(header: BlockHeader): ChainWeight = { 21 | val isNewerCheckpoint = header.hasCheckpoint && header.number > lastCheckpointNumber 22 | val checkpointNum = if (isNewerCheckpoint) header.number else lastCheckpointNumber 23 | ChainWeight(checkpointNum, totalDifficulty + header.difficulty) 24 | } 25 | 26 | def asTuple: (BigInt, BigInt) = 27 | ChainWeight.unapply(this).get 28 | 29 | //Test API 30 | 31 | def increaseTotalDifficulty(td: BigInt): ChainWeight = 32 | copy(totalDifficulty = totalDifficulty + td) 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/Checkpoint.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import io.iohk.ethereum.crypto.ECDSASignature 4 | import io.iohk.ethereum.rlp._ 5 | 6 | case class Checkpoint(signatures: Seq[ECDSASignature]) 7 | 8 | object Checkpoint { 9 | 10 | import io.iohk.ethereum.crypto.ECDSASignatureImplicits._ 11 | 12 | implicit val checkpointRLPEncoder: RLPEncoder[Checkpoint] = { checkpoint => 13 | RLPList(checkpoint.signatures.map(_.toRLPEncodable): _*) 14 | } 15 | 16 | implicit val checkpointRLPDecoder: RLPDecoder[Checkpoint] = { 17 | case signatures: RLPList => 18 | Checkpoint( 19 | signatures.items.map(ecdsaSignatureDec.decode) 20 | ) 21 | case _ => throw new RuntimeException("Cannot decode Checkpoint") 22 | } 23 | 24 | def empty: Checkpoint = Checkpoint(Nil) 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/HeadersSeq.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | object HeadersSeq { 4 | def lastNumber(headers: HeadersSeq): Option[BigInt] = headers.lastOption.map(_.number) 5 | 6 | def areChain(headers: HeadersSeq): Boolean = 7 | if (headers.length > 1) 8 | headers.zip(headers.tail).forall { case (parent, child) => 9 | parent.hash == child.parentHash && parent.number + 1 == child.number 10 | } 11 | else 12 | headers.nonEmpty 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/TransactionOutcome.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import akka.util.ByteString 4 | 5 | sealed trait TransactionOutcome 6 | 7 | case class HashOutcome(stateHash: ByteString) extends TransactionOutcome 8 | 9 | case object SuccessOutcome extends TransactionOutcome 10 | 11 | case object FailureOutcome extends TransactionOutcome 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/TxLogEntry.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import akka.util.ByteString 4 | 5 | import org.bouncycastle.util.encoders.Hex 6 | 7 | case class TxLogEntry(loggerAddress: Address, logTopics: Seq[ByteString], data: ByteString) { 8 | override def toString: String = 9 | s"${getClass.getSimpleName}(" + 10 | s"loggerAddress: $loggerAddress" + 11 | s"logTopics: ${logTopics.map(e => Hex.toHexString(e.toArray[Byte]))}" + 12 | s"data: ${Hex.toHexString(data.toArray[Byte])}" + ")" 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/appstate/BlockInfo.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain.appstate 2 | 3 | import akka.util.ByteString 4 | 5 | case class BlockInfo(hash: ByteString, number: BigInt) 6 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/domain/branch/Branch.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain.branch 2 | 3 | import akka.util.ByteString 4 | 5 | sealed trait Branch 6 | 7 | case class BestBranch(tipBlockHash: ByteString, tipBlockNumber: BigInt) extends Branch 8 | 9 | case object EmptyBranch extends Branch 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/extvm/ApiVersionProvider.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.extvm 2 | 3 | import scala.io.Source 4 | 5 | object ApiVersionProvider { 6 | private val ResourcePath = "extvm/VERSION" 7 | 8 | lazy val version: String = { 9 | val source = Source.fromResource(ResourcePath) 10 | try source.getLines().next() 11 | finally source.close() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/extvm/Implicits.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.extvm 2 | 3 | import akka.util.ByteString 4 | 5 | import com.google.protobuf.{ByteString => GByteString} 6 | 7 | import io.iohk.ethereum.domain.Address 8 | import io.iohk.ethereum.domain.UInt256 9 | 10 | import language.implicitConversions 11 | 12 | object Implicits { 13 | implicit def byteString2GByteString(b: ByteString): GByteString = 14 | GByteString.copyFrom(b.toArray) 15 | 16 | implicit def address2GByteString(a: Address): GByteString = 17 | GByteString.copyFrom(a.toArray) 18 | 19 | implicit def uint256ToGByteString(u: UInt256): GByteString = 20 | u.toBigInt 21 | 22 | implicit def bigintToGByteString(b: BigInt): GByteString = 23 | GByteString.copyFrom(b.toByteArray) 24 | 25 | implicit def byteStringFromGByteString(gb: GByteString): ByteString = 26 | ByteString(gb.toByteArray) 27 | 28 | implicit def addressFromGByteString(gb: GByteString): Address = 29 | Address(gb.toByteArray) 30 | 31 | implicit def uint256FromGByteString(gb: GByteString): UInt256 = 32 | UInt256(gb: BigInt) 33 | 34 | implicit def bigintFromGByteString(gb: GByteString): BigInt = 35 | BigInt(gb.toByteArray) 36 | } 37 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/extvm/Storage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.extvm 2 | 3 | import io.iohk.ethereum.domain.Address 4 | import io.iohk.ethereum.vm 5 | 6 | class Storage(val address: Address, val storage: Map[BigInt, BigInt], cache: StorageCache) extends vm.Storage[Storage] { 7 | 8 | def store(offset: BigInt, value: BigInt): Storage = 9 | new Storage(address, storage + (offset -> value), cache) 10 | 11 | def load(offset: BigInt): BigInt = 12 | storage.getOrElse(offset, cache.getStorageData(address, offset)) 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/extvm/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | package object extvm { 4 | val QueueBufferSize: Int = 16 * 1024 5 | val LengthPrefixSize: Int = 4 6 | } 7 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/Faucet.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet 2 | 3 | import io.iohk.ethereum.faucet.jsonrpc.FaucetServer 4 | import io.iohk.ethereum.utils.Logger 5 | 6 | object Faucet extends Logger { 7 | 8 | def main(args: Array[String]): Unit = 9 | (new FaucetServer).start() 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/SupervisorConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet 2 | 3 | import scala.concurrent.duration.FiniteDuration 4 | import scala.concurrent.duration._ 5 | 6 | import com.typesafe.config.Config 7 | 8 | case class SupervisorConfig( 9 | minBackoff: FiniteDuration, 10 | maxBackoff: FiniteDuration, 11 | randomFactor: Double, 12 | autoReset: FiniteDuration, 13 | attempts: Int, 14 | delay: FiniteDuration 15 | ) 16 | object SupervisorConfig { 17 | def apply(typesafeConfig: Config): SupervisorConfig = { 18 | val supervisorConfig = typesafeConfig.getConfig("supervisor") 19 | 20 | SupervisorConfig( 21 | supervisorConfig.getDuration("min-backoff").toMillis.millis, 22 | supervisorConfig.getDuration("max-backoff").toMillis.millis, 23 | supervisorConfig.getDouble("random-factor"), 24 | supervisorConfig.getDuration("auto-reset").toMillis.millis, 25 | supervisorConfig.getInt("attempts"), 26 | supervisorConfig.getDuration("delay").toMillis.millis 27 | ) 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetDomain.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet.jsonrpc 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.Address 6 | import io.iohk.ethereum.faucet.FaucetStatus 7 | 8 | object FaucetDomain { 9 | 10 | case class SendFundsRequest(address: Address) 11 | case class SendFundsResponse(txId: ByteString) 12 | case class StatusRequest() 13 | case class StatusResponse(status: FaucetStatus) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetHandlerSelector.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet.jsonrpc 2 | 3 | import akka.actor.ActorRef 4 | import akka.actor.ActorSystem 5 | import akka.pattern.RetrySupport 6 | import akka.util.Timeout 7 | 8 | import monix.eval.Task 9 | 10 | import io.iohk.ethereum.faucet.FaucetConfigBuilder 11 | import io.iohk.ethereum.faucet.FaucetHandler 12 | import io.iohk.ethereum.faucet.FaucetSupervisor 13 | 14 | trait FaucetHandlerSelector { 15 | self: FaucetConfigBuilder with RetrySupport => 16 | 17 | val handlerPath: String = s"user/${FaucetSupervisor.name}/${FaucetHandler.name}" 18 | lazy val attempts = faucetConfig.supervisor.attempts 19 | lazy val delay = faucetConfig.supervisor.delay 20 | 21 | lazy val handlerTimeout: Timeout = Timeout(faucetConfig.handlerTimeout) 22 | 23 | def selectFaucetHandler()(implicit system: ActorSystem): Task[ActorRef] = 24 | Task.deferFuture( 25 | retry(() => system.actorSelection(handlerPath).resolveOne(handlerTimeout.duration), attempts, delay)( 26 | system.dispatcher, 27 | system.scheduler 28 | ) 29 | ) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/jsonrpc/FaucetJsonRpcHealthCheck.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet.jsonrpc 2 | 3 | import monix.eval.Task 4 | 5 | import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.StatusRequest 6 | import io.iohk.ethereum.healthcheck.HealthcheckResponse 7 | import io.iohk.ethereum.jsonrpc.JsonRpcHealthChecker 8 | import io.iohk.ethereum.jsonrpc.JsonRpcHealthcheck 9 | 10 | class FaucetJsonRpcHealthCheck(faucetRpcService: FaucetRpcService) extends JsonRpcHealthChecker { 11 | 12 | protected def mainService: String = "faucet health" 13 | 14 | final val statusHC: Task[JsonRpcHealthcheck[FaucetDomain.StatusResponse]] = 15 | JsonRpcHealthcheck.fromServiceResponse("status", faucetRpcService.status(StatusRequest())) 16 | 17 | override def healthCheck(): Task[HealthcheckResponse] = { 18 | val statusF = statusHC.map(_.toResult) 19 | val responseF = statusF.map(check => HealthcheckResponse(List(check))) 20 | 21 | handleResponse(responseF) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/jsonrpc/WalletRpcClient.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.faucet.jsonrpc 2 | 3 | import javax.net.ssl.SSLContext 4 | 5 | import akka.actor.ActorSystem 6 | import akka.http.scaladsl.model.Uri 7 | import akka.util.ByteString 8 | 9 | import monix.eval.Task 10 | 11 | import scala.concurrent.ExecutionContext 12 | import scala.concurrent.duration.Duration 13 | 14 | import io.circe.syntax._ 15 | 16 | import io.iohk.ethereum.domain.Address 17 | import io.iohk.ethereum.jsonrpc.client.RpcClient 18 | import io.iohk.ethereum.jsonrpc.client.RpcClient.RpcError 19 | import io.iohk.ethereum.security.SSLError 20 | import io.iohk.ethereum.utils.Logger 21 | 22 | class WalletRpcClient(node: Uri, timeout: Duration, getSSLContext: () => Either[SSLError, SSLContext])(implicit 23 | system: ActorSystem, 24 | ec: ExecutionContext 25 | ) extends RpcClient(node, timeout, getSSLContext) 26 | with Logger { 27 | import io.iohk.ethereum.jsonrpc.client.CommonJsonCodecs._ 28 | 29 | def getNonce(address: Address): Task[Either[RpcError, BigInt]] = 30 | doRequest[BigInt]("eth_getTransactionCount", List(address.asJson, "latest".asJson)) 31 | 32 | def sendTransaction(rawTx: ByteString): Task[Either[RpcError, ByteString]] = 33 | doRequest[ByteString]("eth_sendRawTransaction", List(rawTx.asJson)) 34 | } 35 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/faucet/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | package object faucet { 4 | sealed trait FaucetStatus 5 | object FaucetStatus { 6 | case object FaucetUnavailable extends FaucetStatus 7 | case object WalletAvailable extends FaucetStatus 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/healthcheck/HealthcheckResponse.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.healthcheck 2 | 3 | final case class HealthcheckResponse(checks: List[HealthcheckResult]) { 4 | lazy val isOK: Boolean = checks.forall(_.isOK) 5 | } 6 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/healthcheck/HealthcheckResult.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.healthcheck 2 | 3 | final case class HealthcheckResult private ( 4 | name: String, 5 | status: String, 6 | info: Option[String] 7 | ) { 8 | 9 | def isOK: Boolean = status == HealthcheckStatus.OK 10 | } 11 | 12 | object HealthcheckResult { 13 | 14 | def ok(name: String, info: Option[String] = None): HealthcheckResult = 15 | new HealthcheckResult( 16 | name = name, 17 | status = HealthcheckStatus.OK, 18 | info = info 19 | ) 20 | 21 | def error(name: String, error: String): HealthcheckResult = 22 | new HealthcheckResult( 23 | name = name, 24 | status = HealthcheckStatus.ERROR, 25 | info = Some(error) 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/healthcheck/HealthcheckStatus.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.healthcheck 2 | 3 | object HealthcheckStatus { 4 | final val OK = "OK" 5 | final val ERROR = "ERROR" 6 | } 7 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/AkkaTaskOps.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import akka.actor.Actor 4 | import akka.actor.ActorRef 5 | import akka.pattern.ask 6 | import akka.util.Timeout 7 | 8 | import monix.eval.Task 9 | 10 | import scala.reflect.ClassTag 11 | 12 | object AkkaTaskOps { 13 | implicit class TaskActorOps(val to: ActorRef) extends AnyVal { 14 | 15 | def askFor[A]( 16 | message: Any 17 | )(implicit timeout: Timeout, classTag: ClassTag[A], sender: ActorRef = Actor.noSender): Task[A] = 18 | Task 19 | .deferFuture((to ? message).mapTo[A]) 20 | .timeout(timeout.duration) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/DebugJsonMethodsImplicits.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import org.json4s.JsonAST.JArray 4 | import org.json4s.JsonAST.JString 5 | import org.json4s.JsonAST.JValue 6 | 7 | import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoRequest 8 | import io.iohk.ethereum.jsonrpc.DebugService.ListPeersInfoResponse 9 | import io.iohk.ethereum.jsonrpc.serialization.JsonEncoder 10 | import io.iohk.ethereum.jsonrpc.serialization.JsonMethodCodec 11 | import io.iohk.ethereum.jsonrpc.serialization.JsonMethodDecoder.NoParamsMethodDecoder 12 | 13 | object DebugJsonMethodsImplicits extends JsonMethodsImplicits { 14 | 15 | implicit val debug_listPeersInfo: JsonMethodCodec[ListPeersInfoRequest, ListPeersInfoResponse] = 16 | new NoParamsMethodDecoder(ListPeersInfoRequest()) with JsonEncoder[ListPeersInfoResponse] { 17 | def encodeJson(t: ListPeersInfoResponse): JValue = 18 | JArray(t.peers.map(a => JString(a.toString))) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcControllerMetrics.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import java.time.Duration 4 | 5 | import io.micrometer.core.instrument.Counter 6 | 7 | import io.iohk.ethereum.metrics.MetricsContainer 8 | 9 | case object JsonRpcControllerMetrics extends MetricsContainer { 10 | 11 | /** Counts attempts to call non-existing methods. 12 | */ 13 | final val NotFoundMethodsCounter: Counter = metrics.counter("json.rpc.notfound.calls.counter") 14 | 15 | final val MethodsSuccessCounter: Counter = metrics.counter("json.rpc.methods.success.counter") 16 | final val MethodsExceptionCounter: Counter = metrics.counter("json.rpc.methods.exception.counter") 17 | final val MethodsErrorCounter: Counter = metrics.counter("json.rpc.methods.error.counter") 18 | 19 | final val HealhcheckErrorCounter: Counter = metrics.counter("json.rpc.healthcheck.error.counter") 20 | 21 | final val MethodsTimerName = "json.rpc.methods.timer" 22 | 23 | def recordMethodTime(method: String, time: Duration): Unit = 24 | metrics.timer("json.rpc.methods.timer", "method", method).record(time) 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcHealthChecker.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import monix.eval.Task 4 | 5 | import io.iohk.ethereum.healthcheck.HealthcheckResponse 6 | 7 | trait JsonRpcHealthChecker { 8 | def healthCheck(): Task[HealthcheckResponse] 9 | 10 | def handleResponse(responseF: Task[HealthcheckResponse]): Task[HealthcheckResponse] = 11 | responseF 12 | .map { 13 | case response if !response.isOK => 14 | JsonRpcControllerMetrics.HealhcheckErrorCounter.increment() 15 | response 16 | case response => response 17 | } 18 | .onErrorHandleWith { t => 19 | JsonRpcControllerMetrics.HealhcheckErrorCounter.increment() 20 | Task.raiseError(t) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcRequest.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import org.json4s.DefaultFormats 4 | import org.json4s.Formats 5 | import org.json4s.JsonAST.JArray 6 | import org.json4s.JsonAST.JValue 7 | import org.json4s.native.Serialization.write 8 | 9 | //TODO: work on a more elegant solution 10 | trait SensitiveInformationToString { 11 | val method: String 12 | 13 | def toStringWithSensitiveInformation: String = 14 | if (!method.contains("personal")) 15 | toString 16 | else "sensitive information" 17 | } 18 | 19 | case class JsonRpcRequest(jsonrpc: String, method: String, params: Option[JArray], id: Option[JValue]) 20 | extends SensitiveInformationToString { 21 | 22 | def inspect: String = { 23 | implicit val formats: Formats = DefaultFormats 24 | "JsonRpcRequest" + (jsonrpc, method, params.map(write(_)), id.map(write(_))).toString 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/JsonRpcResponse.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import org.json4s.DefaultFormats 4 | import org.json4s.Formats 5 | import org.json4s.JsonAST.JValue 6 | import org.json4s.native.Serialization.write 7 | 8 | case class JsonRpcResponse(jsonrpc: String, result: Option[JValue], error: Option[JsonRpcError], id: JValue) { 9 | def inspect: String = { 10 | implicit val formats: Formats = DefaultFormats 11 | "JsonRpcResponse" + (jsonrpc, result.map(write(_)), error.map(write(_))).toString 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/RawTransactionCodec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.SignedTransaction 6 | import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.SignedTransactions.SignedTransactionEnc 7 | import io.iohk.ethereum.rlp 8 | 9 | object RawTransactionCodec { 10 | 11 | def asRawTransaction(e: SignedTransaction): ByteString = 12 | ByteString(rlp.encode(e.toRLPEncodable)) 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/Web3Service.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import akka.util.ByteString 4 | 5 | import monix.eval.Task 6 | 7 | import io.iohk.ethereum.crypto 8 | import io.iohk.ethereum.utils.Config 9 | 10 | object Web3Service { 11 | case class Sha3Request(data: ByteString) 12 | case class Sha3Response(data: ByteString) 13 | 14 | case class ClientVersionRequest() 15 | case class ClientVersionResponse(value: String) 16 | } 17 | 18 | class Web3Service { 19 | import Web3Service._ 20 | 21 | def sha3(req: Sha3Request): ServiceResponse[Sha3Response] = 22 | Task(Right(Sha3Response(crypto.kec256(req.data)))) 23 | 24 | def clientVersion(req: ClientVersionRequest): ServiceResponse[ClientVersionResponse] = 25 | Task(Right(ClientVersionResponse(Config.clientVersion))) 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import monix.eval.Task 4 | 5 | package object jsonrpc { 6 | type ServiceResponse[T] = Task[Either[JsonRpcError, T]] 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodCodec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc.serialization 2 | import org.json4s.JArray 3 | 4 | trait JsonMethodCodec[Req, Res] extends JsonMethodDecoder[Req] with JsonEncoder[Res] 5 | object JsonMethodCodec { 6 | import scala.language.implicitConversions 7 | 8 | implicit def decoderWithEncoderIntoCodec[Req, Res]( 9 | decEnc: JsonMethodDecoder[Req] with JsonEncoder[Res] 10 | ): JsonMethodCodec[Req, Res] = new JsonMethodCodec[Req, Res] { 11 | def decodeJson(params: Option[JArray]) = decEnc.decodeJson(params) 12 | def encodeJson(t: Res) = decEnc.encodeJson(t) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/jsonrpc/serialization/JsonMethodDecoder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc.serialization 2 | 3 | import org.json4s.JsonAST.JArray 4 | 5 | import io.iohk.ethereum.jsonrpc.JsonRpcError 6 | import io.iohk.ethereum.jsonrpc.JsonRpcError.InvalidParams 7 | 8 | trait JsonMethodDecoder[T] { 9 | def decodeJson(params: Option[JArray]): Either[JsonRpcError, T] 10 | } 11 | object JsonMethodDecoder { 12 | class NoParamsMethodDecoder[T](request: => T) extends JsonMethodDecoder[T] { 13 | def decodeJson(params: Option[JArray]): Either[JsonRpcError, T] = 14 | params match { 15 | case None | Some(JArray(Nil)) => Right(request) 16 | case _ => Left(InvalidParams(s"No parameters expected")) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/keystore/Wallet.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.keystore 2 | 3 | import akka.util.ByteString 4 | 5 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair 6 | 7 | import io.iohk.ethereum.crypto._ 8 | import io.iohk.ethereum.domain.Address 9 | import io.iohk.ethereum.domain.LegacyTransaction 10 | import io.iohk.ethereum.domain.SignedTransaction 11 | import io.iohk.ethereum.domain.SignedTransactionWithSender 12 | 13 | case class Wallet(address: Address, prvKey: ByteString) { 14 | lazy val keyPair: AsymmetricCipherKeyPair = keyPairFromPrvKey(prvKey.toArray) 15 | 16 | def signTx(tx: LegacyTransaction, chainId: Option[Byte]): SignedTransactionWithSender = 17 | SignedTransactionWithSender(SignedTransaction.sign(tx, keyPair, chainId), Address(keyPair)) 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/BlockData.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | import io.iohk.ethereum.domain.Block 4 | import io.iohk.ethereum.domain.ChainWeight 5 | import io.iohk.ethereum.domain.Receipt 6 | 7 | case class BlockData(block: Block, receipts: Seq[Receipt], weight: ChainWeight) 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/BlockResult.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | import io.iohk.ethereum.domain.Receipt 4 | 5 | case class BlockResult(worldState: InMemoryWorldStateProxy, gasUsed: BigInt = 0, receipts: Seq[Receipt] = Nil) 6 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/LocalVM.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | import io.iohk.ethereum.vm.VM 4 | 5 | object LocalVM extends VM[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] 6 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/PreparedBlock.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.Block 6 | 7 | case class PreparedBlock( 8 | block: Block, 9 | blockResult: BlockResult, 10 | stateRootHash: ByteString, 11 | updatedWorld: InMemoryWorldStateProxy 12 | ) 13 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/TxResult.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.TxLogEntry 6 | import io.iohk.ethereum.vm.ProgramError 7 | 8 | case class TxResult( 9 | worldState: InMemoryWorldStateProxy, 10 | gasUsed: BigInt, 11 | logs: Seq[TxLogEntry], 12 | vmReturnData: ByteString, 13 | vmError: Option[ProgramError] 14 | ) 15 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/ledger/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import io.iohk.ethereum.vm.ProgramContext 4 | import io.iohk.ethereum.vm.ProgramResult 5 | import io.iohk.ethereum.vm.VM 6 | 7 | package object ledger { 8 | type VMImpl = VM[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] 9 | type PC = ProgramContext[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] 10 | type PR = ProgramResult[InMemoryWorldStateProxy, InMemoryWorldStateProxyStorage] 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/AppJmxConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | import io.micrometer.jmx.JmxConfig 4 | 5 | class AppJmxConfig extends JmxConfig { 6 | override def get(key: String): String = null 7 | 8 | override def prefix(): String = Metrics.MetricsPrefix 9 | 10 | override def domain(): String = prefix() 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/DeltaSpikeGauge.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean 4 | import java.util.concurrent.atomic.AtomicInteger 5 | 6 | /** A gauge that starts at `0` and can be triggered to go to `1`. 7 | * Next time it is sampled, it goes back to `0`. 8 | * This is normally used for either one-off signals (e.g. when an application starts) 9 | * or slowly re-appearing signals. Specifically, the sampling rate must be greater 10 | * than the rate the signal is triggered. 11 | */ 12 | class DeltaSpikeGauge(name: String, metrics: Metrics) { 13 | final private[this] val isTriggeredRef = new AtomicBoolean(false) 14 | final private[this] val valueRef = new AtomicInteger(0) 15 | 16 | private[this] def getValue(): Double = 17 | if (isTriggeredRef.compareAndSet(true, false)) { 18 | valueRef.getAndSet(0) 19 | } else { 20 | valueRef.get() 21 | } 22 | 23 | metrics.gauge(name, () => getValue()) 24 | 25 | def trigger(): Unit = 26 | if (isTriggeredRef.compareAndSet(false, true)) { 27 | valueRef.set(1) 28 | // Let one of the exporting metric registries pick up the `1`. 29 | // As soon as that happens, `getValue` will make sure that we go back to `0`. 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/MetricsAlreadyConfiguredError.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | case class MetricsAlreadyConfiguredError(previous: Metrics, current: Metrics) extends Exception 4 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/MetricsConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | import com.typesafe.config.{Config => TypesafeConfig} 4 | 5 | final case class MetricsConfig( 6 | enabled: Boolean, 7 | port: Int 8 | ) 9 | 10 | object MetricsConfig { 11 | object Keys { 12 | final val Metrics = "metrics" 13 | 14 | final val Enabled = "enabled" 15 | final val Port = "port" 16 | } 17 | 18 | def apply(config: TypesafeConfig): MetricsConfig = { 19 | val metricsConfig = config.getConfig(Keys.Metrics) 20 | 21 | val enabled = metricsConfig.getBoolean(Keys.Enabled) 22 | val port = metricsConfig.getInt(Keys.Port) 23 | 24 | MetricsConfig( 25 | enabled = enabled, 26 | port = port 27 | ) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/MetricsContainer.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | /** An object that contains metrics, typically owned by an application component. 4 | * We also use it as a marker trait, so that subclasses can easily give us an idea 5 | * of what metrics we implement across the application. 6 | */ 7 | trait MetricsContainer { 8 | final lazy val metrics: Metrics = Metrics.get() 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/metrics/MetricsUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.metrics 2 | 3 | object MetricsUtils { 4 | 5 | def mkNameWithPrefix(prefix: String)(name: String): String = { 6 | val metricsPrefix = prefix + "." 7 | if (name.startsWith(metricsPrefix)) name else metricsPrefix + name 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/mpt/HashByteArraySerializable.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.mpt 2 | 3 | import io.iohk.ethereum.crypto.kec256 4 | 5 | case class HashByteArraySerializable[T](tSerializer: ByteArrayEncoder[T]) extends ByteArrayEncoder[T] { 6 | override def toBytes(input: T): Array[Byte] = kec256(tSerializer.toBytes(input)) 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/mpt/MptVisitors/MptVisitor.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.mpt.MptVisitors 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.mpt.BranchNode 6 | import io.iohk.ethereum.mpt.ExtensionNode 7 | import io.iohk.ethereum.mpt.HashNode 8 | import io.iohk.ethereum.mpt.LeafNode 9 | import io.iohk.ethereum.mpt.MptNode 10 | 11 | sealed abstract class HashNodeResult[T] { 12 | def next(visitor: MptVisitor[T])(f: (MptNode, MptVisitor[T]) => T): T = this match { 13 | case Result(value) => value 14 | case ResolveResult(node) => f(node, visitor) 15 | } 16 | } 17 | case class Result[T](t: T) extends HashNodeResult[T] 18 | case class ResolveResult[T](mptNode: MptNode) extends HashNodeResult[T] 19 | 20 | abstract class MptVisitor[T] { 21 | def visitLeaf(value: LeafNode): T 22 | def visitExtension(value: ExtensionNode): ExtensionVisitor[T] 23 | def visitBranch(value: BranchNode): BranchVisitor[T] 24 | def visitHash(value: HashNode): HashNodeResult[T] 25 | def visitNull(): T 26 | } 27 | 28 | abstract class BranchVisitor[T] { 29 | def visitChild(): MptVisitor[T] 30 | def visitChild(child: => T): Unit 31 | def visitTerminator(term: Option[ByteString]): Unit 32 | def done(): T 33 | } 34 | 35 | abstract class ExtensionVisitor[T] { 36 | def visitNext(): MptVisitor[T] 37 | def visitNext(value: => T): Unit 38 | def done(): T 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/mpt/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.db.storage.EvmCodeStorage.Code 6 | 7 | package object mpt { 8 | 9 | trait ByteArrayEncoder[T] { 10 | def toBytes(input: T): Array[Byte] 11 | } 12 | 13 | trait ByteArrayDecoder[T] { 14 | def fromBytes(bytes: Array[Byte]): T 15 | } 16 | 17 | trait ByteArraySerializable[T] extends ByteArrayEncoder[T] with ByteArrayDecoder[T] 18 | 19 | implicit val byteStringSerializer: ByteArraySerializable[ByteString] = new ByteArraySerializable[ByteString] { 20 | override def toBytes(input: Code): Array[Byte] = input.toArray[Byte] 21 | override def fromBytes(bytes: Array[Byte]): Code = ByteString(bytes) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/ForkResolver.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network 2 | 3 | import io.iohk.ethereum.domain.BlockHeader 4 | import io.iohk.ethereum.utils.DaoForkConfig 5 | 6 | trait ForkResolver { 7 | type Fork <: ForkResolver.Fork 8 | 9 | def forkBlockNumber: BigInt 10 | def recognizeFork(blockHeader: BlockHeader): Fork 11 | def isAccepted(fork: Fork): Boolean 12 | } 13 | 14 | object ForkResolver { 15 | 16 | trait Fork 17 | 18 | class EtcForkResolver(daoForkConfig: DaoForkConfig) extends ForkResolver { 19 | sealed trait Fork extends ForkResolver.Fork 20 | case object AcceptedFork extends Fork 21 | case object RejectedFork extends Fork 22 | 23 | override def forkBlockNumber: BigInt = daoForkConfig.forkBlockNumber 24 | 25 | override def recognizeFork(blockHeader: BlockHeader): Fork = 26 | if (blockHeader.hash == daoForkConfig.forkBlockHash) AcceptedFork 27 | else RejectedFork 28 | 29 | override def isAccepted(fork: Fork): Boolean = fork == AcceptedFork 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/Peer.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network 2 | 3 | import java.net.InetSocketAddress 4 | 5 | import akka.NotUsed 6 | import akka.actor.ActorRef 7 | import akka.stream.scaladsl.Source 8 | import akka.util.ByteString 9 | 10 | import io.iohk.ethereum.blockchain.sync.Blacklist.BlacklistId 11 | import io.iohk.ethereum.network.p2p.Message 12 | 13 | final case class PeerId(value: String) extends BlacklistId 14 | 15 | object PeerId { 16 | def fromRef(ref: ActorRef): PeerId = PeerId(ref.path.name) 17 | } 18 | 19 | final case class Peer( 20 | id: PeerId, 21 | remoteAddress: InetSocketAddress, 22 | ref: ActorRef, 23 | incomingConnection: Boolean, 24 | source: Source[Message, NotUsed] = Source.empty, 25 | nodeId: Option[ByteString] = None, 26 | createTimeMillis: Long = System.currentTimeMillis 27 | ) 28 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/PeerStat.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network 2 | 3 | import cats._ 4 | import cats.implicits._ 5 | 6 | case class PeerStat( 7 | responsesReceived: Int, 8 | requestsReceived: Int, 9 | firstSeenTimeMillis: Option[Long], 10 | lastSeenTimeMillis: Option[Long] 11 | ) 12 | object PeerStat { 13 | val empty: PeerStat = PeerStat(0, 0, None, None) 14 | 15 | private def mergeOpt[A, B](x: A, y: A)(f: A => Option[B])(g: (B, B) => B): Option[B] = { 16 | val (mx, my) = (f(x), f(y)) 17 | (mx, my).mapN(g).orElse(mx).orElse(my) 18 | } 19 | 20 | implicit val monoid: Monoid[PeerStat] = 21 | Monoid.instance( 22 | empty, 23 | (a, b) => 24 | PeerStat( 25 | responsesReceived = a.responsesReceived + b.responsesReceived, 26 | requestsReceived = a.requestsReceived + b.requestsReceived, 27 | firstSeenTimeMillis = mergeOpt(a, b)(_.firstSeenTimeMillis)(math.min), 28 | lastSeenTimeMillis = mergeOpt(a, b)(_.lastSeenTimeMillis)(math.max) 29 | ) 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/p2p/Message.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network.p2p 2 | 3 | import cats.implicits._ 4 | 5 | import io.iohk.ethereum.utils.Logger 6 | 7 | trait Message { 8 | def code: Int 9 | def toShortString: String 10 | } 11 | 12 | trait MessageSerializable extends Message { 13 | def toBytes: Array[Byte] 14 | def underlyingMsg: Message 15 | } 16 | 17 | @FunctionalInterface 18 | trait MessageDecoder extends Logger { self => 19 | import MessageDecoder._ 20 | 21 | def fromBytes(`type`: Int, payload: Array[Byte]): Either[DecodingError, Message] 22 | 23 | def orElse(otherMessageDecoder: MessageDecoder): MessageDecoder = new MessageDecoder { 24 | override def fromBytes(`type`: Int, payload: Array[Byte]): Either[DecodingError, Message] = 25 | self.fromBytes(`type`, payload).leftFlatMap { err => 26 | log.debug(err.getLocalizedMessage()) 27 | otherMessageDecoder.fromBytes(`type`, payload) 28 | } 29 | } 30 | } 31 | 32 | object MessageDecoder { 33 | type DecodingError = Throwable // TODO: Replace Throwable with an ADT when feasible 34 | } 35 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/p2p/MessageSerializableImplicit.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network.p2p 2 | 3 | /** Helper class 4 | */ 5 | //FIXME: msg is redundant since `MessageSerializable` already exposes `underlyingMessage` 6 | abstract class MessageSerializableImplicit[T <: Message](val msg: T) extends MessageSerializable { 7 | 8 | override def equals(that: Any): Boolean = that match { 9 | case that: MessageSerializableImplicit[T] => that.msg.equals(msg) 10 | case _ => false 11 | } 12 | 13 | override def hashCode(): Int = msg.hashCode() 14 | 15 | override def toShortString: String = msg.toShortString 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/p2p/messages/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network.p2p 2 | 3 | package object messages { 4 | 5 | val SubProtocolOffset = 0x10 6 | 7 | object Codes { 8 | val StatusCode: Int = SubProtocolOffset + 0x00 9 | val NewBlockHashesCode: Int = SubProtocolOffset + 0x01 10 | val SignedTransactionsCode: Int = SubProtocolOffset + 0x02 11 | val GetBlockHeadersCode: Int = SubProtocolOffset + 0x03 12 | val BlockHeadersCode: Int = SubProtocolOffset + 0x04 13 | val GetBlockBodiesCode: Int = SubProtocolOffset + 0x05 14 | val BlockBodiesCode: Int = SubProtocolOffset + 0x06 15 | val NewBlockCode: Int = SubProtocolOffset + 0x07 16 | // This message is removed in ETH62 and this code is reused in ETH65 with different msg type 17 | val BlockHashesFromNumberCode: Int = SubProtocolOffset + 0x08 18 | val GetNodeDataCode: Int = SubProtocolOffset + 0x0d 19 | val NodeDataCode: Int = SubProtocolOffset + 0x0e 20 | val GetReceiptsCode: Int = SubProtocolOffset + 0x0f 21 | val ReceiptsCode: Int = SubProtocolOffset + 0x10 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/rlpx/AuthInitiateEcdsaCodec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network.rlpx 2 | 3 | import akka.util.ByteString 4 | 5 | import org.bouncycastle.util.BigIntegers.asUnsignedByteArray 6 | 7 | import io.iohk.ethereum.crypto.ECDSASignature 8 | import io.iohk.ethereum.crypto.ECDSASignature.RLength 9 | import io.iohk.ethereum.crypto.ECDSASignature.SLength 10 | 11 | trait AuthInitiateEcdsaCodec { 12 | 13 | def encodeECDSA(sig: ECDSASignature): ByteString = { 14 | import sig._ 15 | 16 | val recoveryId: Byte = (v - 27).toByte 17 | 18 | ByteString( 19 | asUnsignedByteArray(r.bigInteger).reverse.padTo(RLength, 0.toByte).reverse ++ 20 | asUnsignedByteArray(s.bigInteger).reverse.padTo(SLength, 0.toByte).reverse ++ 21 | Array(recoveryId) 22 | ) 23 | } 24 | 25 | def decodeECDSA(input: Array[Byte]): ECDSASignature = { 26 | val SIndex = 32 27 | val VIndex = 64 28 | 29 | val r = input.take(RLength) 30 | val s = input.slice(SIndex, SIndex + SLength) 31 | val v = input(VIndex) + 27 32 | ECDSASignature(BigInt(1, r), BigInt(1, s), v.toByte) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/network/rlpx/AuthResponseMessage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.network.rlpx 2 | 3 | import akka.util.ByteString 4 | 5 | import org.bouncycastle.math.ec.ECPoint 6 | 7 | import io.iohk.ethereum.crypto._ 8 | 9 | object AuthResponseMessage { 10 | 11 | private val PublicKeyLength = 64 12 | private val NonceLength = 32 13 | private val KnownPeerLength = 1 14 | 15 | val EncodedLength: Int = PublicKeyLength + NonceLength + KnownPeerLength 16 | 17 | def decode(input: Array[Byte]): AuthResponseMessage = 18 | AuthResponseMessage( 19 | ephemeralPublicKey = 20 | curve.getCurve.decodePoint(ECDSASignature.UncompressedIndicator +: input.take(PublicKeyLength)), 21 | nonce = ByteString(input.slice(PublicKeyLength, PublicKeyLength + NonceLength)), 22 | knownPeer = input(PublicKeyLength + NonceLength) == 1 23 | ) 24 | } 25 | 26 | case class AuthResponseMessage(ephemeralPublicKey: ECPoint, nonce: ByteString, knownPeer: Boolean) { 27 | 28 | lazy val encoded: ByteString = ByteString( 29 | ephemeralPublicKey.getEncoded(false).drop(1) ++ 30 | nonce ++ 31 | Array(if (knownPeer) 1.toByte else 0.toByte) 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/nodebuilder/tooling/StorageConsistencyChecker.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.nodebuilder.tooling 2 | 3 | import com.typesafe.scalalogging.Logger 4 | 5 | import io.iohk.ethereum.db.storage.BlockHeadersStorage 6 | import io.iohk.ethereum.db.storage.BlockNumberMappingStorage 7 | 8 | object StorageConsistencyChecker { 9 | type ShutdownOp = () => Unit 10 | 11 | val DefaultStep = 1000 12 | 13 | def checkStorageConsistency( 14 | bestBlockNumber: BigInt, 15 | blockNumberMappingStorage: BlockNumberMappingStorage, 16 | blockHeadersStorage: BlockHeadersStorage, 17 | shutdown: ShutdownOp, 18 | step: Int = DefaultStep 19 | )(implicit log: Logger): Unit = 20 | Range(0, bestBlockNumber.intValue, step).foreach { idx => 21 | (for { 22 | hash <- blockNumberMappingStorage.get(idx) 23 | _ <- blockHeadersStorage.get(hash) 24 | } yield ()).fold { 25 | log.error("Database seems to be in inconsistent state, shutting down") 26 | shutdown() 27 | }(_ => ()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/rlp/UInt256RLPImplicits.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.rlp 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.UInt256 6 | import io.iohk.ethereum.rlp.RLP._ 7 | 8 | object UInt256RLPImplicits { 9 | 10 | implicit class UInt256Enc(obj: UInt256) extends RLPSerializable { 11 | override def toRLPEncodable: RLPEncodeable = 12 | RLPValue(if (obj.equals(UInt256.Zero)) byteToByteArray(0: Byte) else obj.bytes.dropWhile(_ == 0).toArray[Byte]) 13 | } 14 | 15 | implicit class UInt256Dec(val bytes: ByteString) extends AnyVal { 16 | def toUInt256: UInt256 = UInt256RLPEncodableDec(rawDecode(bytes.toArray)).toUInt256 17 | } 18 | 19 | implicit class UInt256RLPEncodableDec(val rLPEncodeable: RLPEncodeable) extends AnyVal { 20 | def toUInt256: UInt256 = rLPEncodeable match { 21 | case RLPValue(b) => UInt256(b) 22 | case _ => throw RLPException("src is not an RLPValue") 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/security/FileUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.security 2 | 3 | import java.io.File 4 | import java.io.FileInputStream 5 | 6 | import scala.io.BufferedSource 7 | import scala.io.Source 8 | import scala.util.Try 9 | 10 | import io.iohk.ethereum.utils.Logger 11 | 12 | trait FileUtils extends Logger { 13 | 14 | def exist(pathName: String): Boolean = new File(pathName).isFile 15 | 16 | def createFileInputStream(pathName: String): Either[Throwable, FileInputStream] = 17 | Try(new FileInputStream(pathName)).toEither match { 18 | case Right(fileInputStream) => 19 | Option(fileInputStream).map(Right(_)).getOrElse { 20 | log.error("empty fileInputStream") 21 | Left(new IllegalStateException("empty fileInputStream")) 22 | } 23 | case Left(error) => 24 | log.error("create file input stream failed", error) 25 | Left(error) 26 | } 27 | 28 | def getReader(file: String): BufferedSource = Source.fromFile(file) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/security/SSLConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.security 2 | 3 | import com.typesafe.config.Config 4 | 5 | case class SSLConfig( 6 | keyStorePath: String, 7 | keyStoreType: String, 8 | passwordFile: String 9 | ) 10 | 11 | object SSLConfig { 12 | 13 | val key = "certificate" 14 | 15 | def apply(config: Config): Option[SSLConfig] = 16 | if (config.getIsNull(key)) 17 | None 18 | else { 19 | val certificateConfig = config.getConfig(key) 20 | Some( 21 | SSLConfig( 22 | keyStorePath = certificateConfig.getString("keystore-path"), 23 | keyStoreType = certificateConfig.getString("keystore-type"), 24 | passwordFile = certificateConfig.getString("password-file") 25 | ) 26 | ) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/security/SSLContextBuilder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.security 2 | import javax.net.ssl.SSLContext 3 | 4 | import com.typesafe.config.ConfigFactory 5 | 6 | case class SSLError(reason: String) 7 | 8 | trait SSLContextBuilder { self: SecureRandomBuilder => 9 | 10 | def sslContext(key: String): Either[SSLError, SSLContext] = 11 | SSLConfig(ConfigFactory.load().getConfig(key)) 12 | .toRight(SSLError("No SSL config present")) 13 | .flatMap(SSLContextFactory().createSSLContext(_, secureRandom)) match { 14 | case Right(sslConfig) => 15 | log.debug("Loaded ssl config successful") 16 | Right(sslConfig) 17 | case Left(error) => 18 | log.error(s"Loaded ssl config failure - $error") 19 | Left(error) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/security/SecureRandomBuilder.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.security 2 | 3 | import java.security.SecureRandom 4 | 5 | import scala.util.Failure 6 | import scala.util.Success 7 | import scala.util.Try 8 | 9 | import com.typesafe.config.Config 10 | import com.typesafe.config.ConfigFactory 11 | 12 | import io.iohk.ethereum.utils.Logger 13 | 14 | trait SecureRandomBuilder extends Logger { 15 | 16 | private lazy val rawMantisConfig: Config = ConfigFactory.load().getConfig("mantis") 17 | 18 | private val secureRandomAlgo: Option[String] = 19 | if (rawMantisConfig.hasPath("secure-random-algo")) Some(rawMantisConfig.getString("secure-random-algo")) 20 | else None 21 | 22 | lazy val secureRandom: SecureRandom = 23 | secureRandomAlgo 24 | .flatMap(name => 25 | Try(SecureRandom.getInstance(name)) match { 26 | case Failure(exception) => 27 | log.error( 28 | s"Couldn't create SecureRandom instance using algorithm $name. Falling-back to default one", 29 | exception 30 | ) 31 | None 32 | case Success(value) => 33 | Some(value) 34 | } 35 | ) 36 | .getOrElse(new SecureRandom()) 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/testmode/SealEngineType.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.testmode 2 | 3 | sealed trait SealEngineType 4 | 5 | object SealEngineType { 6 | // Do not check `nonce` and `mixhash` field in blockHeaders 7 | object NoProof extends SealEngineType 8 | // Do not check `nonce` and `mixhash` field in blockHeaders + Do not check mining reward (block + uncle headers) 9 | object NoReward extends SealEngineType 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/transactions/TransactionPicker.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.transactions 2 | 3 | import akka.actor.ActorRef 4 | import akka.util.Timeout 5 | 6 | import monix.eval.Task 7 | 8 | import scala.concurrent.duration.FiniteDuration 9 | 10 | import io.iohk.ethereum.jsonrpc.AkkaTaskOps.TaskActorOps 11 | import io.iohk.ethereum.transactions.PendingTransactionsManager 12 | import io.iohk.ethereum.transactions.PendingTransactionsManager.PendingTransactionsResponse 13 | import io.iohk.ethereum.utils.Logger 14 | 15 | trait TransactionPicker extends Logger { 16 | 17 | protected def pendingTransactionsManager: ActorRef 18 | protected def getTransactionFromPoolTimeout: FiniteDuration 19 | 20 | implicit val timeout: Timeout = Timeout(getTransactionFromPoolTimeout) 21 | 22 | def getTransactionsFromPool: Task[PendingTransactionsResponse] = 23 | pendingTransactionsManager 24 | .askFor[PendingTransactionsResponse](PendingTransactionsManager.GetPendingTransactions) 25 | .onErrorHandle { ex => 26 | log.error("Failed to get transactions, mining block with empty transactions list", ex) 27 | PendingTransactionsResponse(Nil) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/BigIntExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import io.iohk.ethereum.domain.UInt256 4 | 5 | object BigIntExtensionMethods { 6 | implicit class BigIntAsUnsigned(val srcBigInteger: BigInt) extends AnyVal { 7 | def toUnsignedByteArray: Array[Byte] = 8 | ByteUtils.bigIntToUnsignedByteArray(srcBigInteger) 9 | 10 | def u256: UInt256 = UInt256(srcBigInteger) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/FunctorOps.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import cats.Functor 4 | 5 | import scala.language.implicitConversions 6 | 7 | class FunctorOps[A, F[_]: Functor](f: F[A]) { 8 | def tap[B](cb: A => Unit): F[A] = 9 | Functor[F].map(f) { a => 10 | cb(a) 11 | a 12 | } 13 | } 14 | object FunctorOps { 15 | implicit def functorToFunctorOps[A, F[_]: Functor](f: F[A]): FunctorOps[A, F] = new FunctorOps(f) 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/LoadFromApplicationConfiguration.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import ch.qos.logback.core.joran.action.Action 4 | import ch.qos.logback.core.joran.spi.InterpretationContext 5 | import com.typesafe.config.ConfigFactory 6 | import org.xml.sax.Attributes 7 | 8 | /** Make properties defined in application.conf available to logback 9 | */ 10 | class LoadFromApplicationConfiguration extends Action { 11 | 12 | val config = ConfigFactory.load 13 | override def begin(ic: InterpretationContext, body: String, attributes: Attributes): Unit = 14 | ic.addSubstitutionProperty(attributes.getValue("as"), config.getString(attributes.getValue("key"))) 15 | override def end(ic: InterpretationContext, body: String): Unit = () 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/Logger.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import com.typesafe.scalalogging 4 | import org.slf4j.LoggerFactory 5 | import org.slf4j.MDC 6 | 7 | trait Logger { 8 | protected val log: scalalogging.Logger = com.typesafe.scalalogging.Logger(LoggerFactory.getLogger(getClass)) 9 | } 10 | 11 | trait LazyLogger { 12 | protected lazy val log: scalalogging.Logger = com.typesafe.scalalogging.Logger(LoggerFactory.getLogger(getClass)) 13 | } 14 | 15 | trait LoggingContext { 16 | val asParameterMap: Map[String, String] 17 | } 18 | 19 | object LoggingContext { 20 | implicit class ContextLoggerOps[T <: scalalogging.Logger](log: T) { 21 | def withContext(context: LoggingContext)(doLog: T => Unit): Unit = { 22 | context.asParameterMap.foreach { case (key, value) => MDC.put(key, value) } 23 | doLog(log) 24 | MDC.clear() 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/LoggerUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | object LoggingUtils { 4 | 5 | def getClassName(cls: Class[_]): String = cls.getName.split("\\.").last 6 | 7 | def getClassName(o: Object): String = getClassName(o.getClass) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/NodeStatus.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import java.net.InetSocketAddress 4 | 5 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair 6 | import org.bouncycastle.crypto.params.ECPublicKeyParameters 7 | 8 | import io.iohk.ethereum.network._ 9 | 10 | sealed trait ServerStatus 11 | object ServerStatus { 12 | case object NotListening extends ServerStatus 13 | case class Listening(address: InetSocketAddress) extends ServerStatus 14 | } 15 | 16 | case class NodeStatus(key: AsymmetricCipherKeyPair, serverStatus: ServerStatus, discoveryStatus: ServerStatus) { 17 | 18 | val nodeId: Array[Byte] = key.getPublic.asInstanceOf[ECPublicKeyParameters].toNodeId 19 | } 20 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/NumericUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | object NumericUtils { 4 | 5 | def parseHexOrDecNumber(s: String): BigInt = 6 | if (s.startsWith("0x")) 7 | BigInt(s.drop(2), 16) 8 | else 9 | BigInt(s) 10 | 11 | def parseHexNumber(s: String): BigInt = 12 | BigInt(s.replaceFirst("^0x", ""), 16) 13 | } 14 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/Ref.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import java.util.concurrent.atomic.AtomicReference 4 | 5 | /** An [[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html AtomicReference]] that can be set once. 6 | */ 7 | class Ref[T <: AnyRef] { 8 | final private[this] val ref = new AtomicReference[Option[T]](None) 9 | 10 | // set once (but not necessarily compute once) 11 | final def setOnce(t: => T): Boolean = ref.get().isEmpty && ref.compareAndSet(None, Some(t)) 12 | 13 | final def isDefined: Boolean = ref.get().isDefined 14 | final def isEmpty: Boolean = ref.get().isEmpty 15 | 16 | final def map[U](f: T => U): Option[U] = ref.get().map(f) 17 | final def foreach[U](f: T => U): Unit = map(f) 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/StringUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | object StringUtils { 4 | 5 | def drop0x(s: String): String = 6 | if (s.startsWith("0x")) s.substring(2) else s 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/TryWithResources.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import scala.util.control.NonFatal 4 | 5 | object TryWithResources { 6 | 7 | // try-with-resources, source: https://github.com/dkomanov/stuff/blob/master/src/com/komanov/io/package.scala 8 | def withResources[R <: AutoCloseable, T](r: => R)(f: R => T): T = { 9 | val resource: R = r 10 | require(resource != null, "resource is null") 11 | var exception: Throwable = null 12 | try f(resource) 13 | catch { 14 | case NonFatal(e) => 15 | exception = e 16 | throw e 17 | } finally closeAndAddSuppressed(exception, resource) 18 | } 19 | 20 | private def closeAndAddSuppressed(e: Throwable, resource: AutoCloseable): Unit = 21 | if (e != null) { 22 | try resource.close() 23 | catch { 24 | case NonFatal(suppressed) => 25 | e.addSuppressed(suppressed) 26 | } 27 | } else { 28 | resource.close() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/utils/ValidationUtils.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | object ValidationUtils { 4 | 5 | /** This function combines multiple validations on object. 6 | * 7 | * @param obj object to return if all validations pass . 8 | * @param eithers list of required validations. 9 | * @return object if all validations pass, else non-empty set of errors. 10 | */ 11 | def combineValidations[A, B](obj: B, eithers: Either[A, B]*): Either[Set[A], B] = { 12 | val errors = eithers.collect { case Left(e) => e } 13 | if (errors.isEmpty) Right(obj) else Left(errors.toSet) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/vm/InternalTransaction.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.Address 6 | 7 | /** This class may be used for tracing any internal calls (*CALL*, CREATE) during code execution. 8 | * Currently it's only in Ethereum Test Suite (ets) 9 | * 10 | * @param opcode - the opcode that caused the internal TX 11 | * @param from - the account that executes the opcode 12 | * @param to - the account to which the call was made 13 | * @param gasLimit - gas available to the sub-execution 14 | * @param data - call data 15 | * @param value - call value 16 | */ 17 | case class InternalTransaction( 18 | opcode: OpCode, 19 | from: Address, 20 | to: Option[Address], 21 | gasLimit: BigInt, 22 | data: ByteString, 23 | value: BigInt 24 | ) 25 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/vm/ProgramError.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.domain.UInt256 4 | 5 | /** Marker trait for errors that may occur during program execution 6 | */ 7 | sealed trait ProgramError { 8 | val useWholeGas = true 9 | } 10 | case class InvalidOpCode(code: Byte) extends ProgramError { 11 | override def toString: String = 12 | f"${getClass.getSimpleName}(0x${code.toInt & 0xff}%02x)" 13 | } 14 | case class OpCodeNotAvailableInStaticContext(code: Byte) extends ProgramError { 15 | override def toString: String = 16 | f"${getClass.getSimpleName}(0x${code.toInt & 0xff}%02x)" 17 | } 18 | case object OutOfGas extends ProgramError 19 | case class InvalidJump(dest: UInt256) extends ProgramError { 20 | override def toString: String = 21 | f"${getClass.getSimpleName}(${dest.toHexString})" 22 | } 23 | 24 | sealed trait StackError extends ProgramError 25 | case object StackOverflow extends StackError 26 | case object StackUnderflow extends StackError 27 | 28 | case object InvalidCall extends ProgramError 29 | case object PreCompiledContractFail extends ProgramError 30 | 31 | case object RevertOccurs extends ProgramError { 32 | override val useWholeGas: Boolean = false 33 | } 34 | 35 | case object ReturnDataOverflow extends ProgramError 36 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/vm/ProgramResult.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.domain.Address 6 | import io.iohk.ethereum.domain.TxLogEntry 7 | 8 | /** Represenation of the result of execution of a contract 9 | * 10 | * @param returnData bytes returned by the executed contract (set by [[RETURN]] opcode) 11 | * @param gasRemaining amount of gas remaining after execution 12 | * @param world represents changes to the world state 13 | * @param addressesToDelete list of addresses of accounts scheduled to be deleted 14 | * @param internalTxs list of internal transactions (for debugging/tracing) if enabled in config 15 | * @param error defined when the program terminated abnormally 16 | */ 17 | case class ProgramResult[W <: WorldStateProxy[W, S], S <: Storage[S]]( 18 | returnData: ByteString, 19 | gasRemaining: BigInt, 20 | world: W, 21 | addressesToDelete: Set[Address], 22 | logs: Seq[TxLogEntry], 23 | internalTxs: Seq[InternalTransaction], 24 | gasRefund: BigInt, 25 | error: Option[ProgramError], 26 | accessedAddresses: Set[Address], 27 | accessedStorageKeys: Set[(Address, BigInt)] 28 | ) 29 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/vm/Storage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | /** Account's storage representation. Implementation should be immutable and only keep track of changes to the storage 4 | */ 5 | trait Storage[S <: Storage[S]] { 6 | def store(offset: BigInt, value: BigInt): S 7 | def load(offset: BigInt): BigInt 8 | } 9 | -------------------------------------------------------------------------------- /src/main/scala/io/iohk/ethereum/vm/package.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import io.iohk.ethereum.domain.UInt256 4 | 5 | package object vm { 6 | 7 | /** Number of 32-byte UInt256s required to hold n bytes (~= math.ceil(n / 32)) 8 | */ 9 | def wordsForBytes(n: BigInt): BigInt = 10 | if (n == 0) 0 else (n - 1) / UInt256.Size + 1 11 | } 12 | -------------------------------------------------------------------------------- /src/rpcTest/resources/patch-mantis: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | MANTIS_DIR=$1 4 | SCRIPT_DIR="$( cd "$(dirname "$0")" ; pwd -P )" 5 | KEYSTORE_PATH=~/.mantis-rpc-test/rpc-test-private/keystore/ 6 | 7 | if [[ -z "$MANTIS_DIR" ]]; then 8 | echo "Path to Mantis dir must be passed as the first argument" 9 | exit 1 10 | fi 11 | 12 | if [[ ! -d "$MANTIS_DIR" ]]; then 13 | echo "$MANTIS_DIR doesn't exist" 14 | exit 1 15 | fi 16 | 17 | echo "Patching Mantis at $MANTIS_DIR with configuration for JSON-RPC tests" 18 | 19 | cp -R ${SCRIPT_DIR}/privateNetConfig/conf/* ${MANTIS_DIR}/conf/ 20 | 21 | mkdir -p ${KEYSTORE_PATH} 22 | cp -R ${SCRIPT_DIR}/privateNetConfig/keystore/* ${KEYSTORE_PATH} 23 | -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/conf/application.ini: -------------------------------------------------------------------------------- 1 | -Dconfig.file=./conf/rpc-test-private.conf -Dlogback.configurationFile=./conf/rpc-test-logback.xml -J-Xss10M 2 | -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/conf/rpc-test-private-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraData": "0x00", 3 | "nonce": "0x0000000000000042", 4 | "gasLimit": "0xffffffffff", 5 | "difficulty": "0x400", 6 | "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 7 | "timestamp": "0x00", 8 | "coinbase": "0x0000000000000000000000000000000000000000", 9 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "alloc": { 11 | "316158e265fa708c623cc3094b2bb5889e0f5ca5": { 12 | "balance": "100000000000000000000" 13 | }, 14 | "b9ec69316a8810db91c36de79c4f1e785f2c35fc": { 15 | "balance": "100000000000000000000" 16 | }, 17 | "488c10c91771d3b3c25f63b6414309b119baacb5": { 18 | "balance": "100000000000000000000" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/conf/rpc-test-private.conf: -------------------------------------------------------------------------------- 1 | include "app.conf" 2 | 3 | mantis { 4 | 5 | datadir = ${user.home}"/.mantis-rpc-test/"${mantis.blockchains.network} 6 | 7 | blockchains { 8 | 9 | network = "rpc-test-private" 10 | 11 | rpc-test-private = ${mantis.blockchains.etc} 12 | rpc-test-private { 13 | dao = null 14 | custom-genesis-file = ./conf/rpc-test-private-genesis.json 15 | 16 | monetary-policy { 17 | } 18 | 19 | bootstrap-nodes = [] 20 | } 21 | } 22 | 23 | mining { 24 | # Miner's coinbase address 25 | coinbase = "0011223344556677889900112233445566778899" 26 | mining-enabled = false 27 | } 28 | 29 | 30 | network { 31 | server-address { 32 | interface = "127.0.0.1" 33 | } 34 | 35 | discovery { 36 | discovery-enabled = false 37 | } 38 | 39 | peer { 40 | max-incoming-peers = 0 41 | max-pending-peers = 0 42 | } 43 | 44 | rpc { 45 | http { 46 | mode = "http" 47 | enabled = true 48 | interface = "localhost" 49 | port = 8546 50 | 51 | certificate = null 52 | 53 | cors-allowed-origins = "*" 54 | } 55 | 56 | ipc { 57 | enabled = false 58 | } 59 | } 60 | } 61 | 62 | sync { 63 | do-fast-sync = false 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/keystore/UTC--2018-05-30T07-16-33.631Z--316158e265fa708c623cc3094b2bb5889e0f5ca5: -------------------------------------------------------------------------------- 1 | { 2 | "id":"dc060941-7cd7-43b7-be4c-30b0a15adf91", 3 | "address":"316158e265fa708c623cc3094b2bb5889e0f5ca5", 4 | "version":3, 5 | "crypto":{ 6 | "cipher":"aes-128-ctr", 7 | "ciphertext":"cb16be037ac531bdb4cd20c1ee7e236138e2a3fd88ee0526d443ebd50e9473e6", 8 | "cipherparams":{ 9 | "iv":"b2c02f533242329533f25640a3898ab3" 10 | }, 11 | "kdf":"scrypt", 12 | "kdfparams":{ 13 | "salt":"b8c1046088ee5bd862f4b03b726d6a3a25c4adc6b6fca4a0438a5c813bb8dfa9", 14 | "n":262144, 15 | "r":8, 16 | "p":1, 17 | "dklen":32 18 | }, 19 | "mac":"9c8a7e7e82b76b67d3d3d3a6886866f492b87b71ea3a02069fae517b5c6b0fa6" 20 | } 21 | } -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/keystore/UTC--2018-05-30T07-16-58.64Z--b9ec69316a8810db91c36de79c4f1e785f2c35fc: -------------------------------------------------------------------------------- 1 | { 2 | "id":"5ba0d644-e20a-4fab-8ca8-1d820421868f", 3 | "address":"b9ec69316a8810db91c36de79c4f1e785f2c35fc", 4 | "version":3, 5 | "crypto":{ 6 | "cipher":"aes-128-ctr", 7 | "ciphertext":"1a47abcf9defd64cdc68d6ec074f9d2810f476088c5aee43b72e092fe8f1c213fd", 8 | "cipherparams":{ 9 | "iv":"a5fa7a685f8820e2e01d3c39cb1d706c" 10 | }, 11 | "kdf":"scrypt", 12 | "kdfparams":{ 13 | "salt":"6be6992b61c1d41d7b7d1fea712e391649c8ebb5ddbe07a96d361fbc1872b123", 14 | "n":262144, 15 | "r":8, 16 | "p":1, 17 | "dklen":32 18 | }, 19 | "mac":"e8c9acd27a751a30943cdc256088ec78e96e5ac7658437b16642d266da8b8ecf" 20 | } 21 | } -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/keystore/UTC--2018-05-30T07-17-03.455Z--488c10c91771d3b3c25f63b6414309b119baacb5: -------------------------------------------------------------------------------- 1 | { 2 | "id":"30c29bef-4eab-4766-88c1-fd75b04562da", 3 | "address":"488c10c91771d3b3c25f63b6414309b119baacb5", 4 | "version":3, 5 | "crypto":{ 6 | "cipher":"aes-128-ctr", 7 | "ciphertext":"878c10372c41636eaef09a067dba80cd4eecb3a4814a432a7cb95b2328c4e3bfbd", 8 | "cipherparams":{ 9 | "iv":"d9f4b8a6ce6836236218b543ec7711d3" 10 | }, 11 | "kdf":"scrypt", 12 | "kdfparams":{ 13 | "salt":"a862ad858df5866c59d3cc7c836ef8794b5072a68002cb46e43cfd5912a77695", 14 | "n":262144, 15 | "r":8, 16 | "p":1, 17 | "dklen":32 18 | }, 19 | "mac":"964b7bbb76ed862b78d93a6c23ebf824e449b024062950c94f651a6a575983ed" 20 | } 21 | } -------------------------------------------------------------------------------- /src/rpcTest/resources/privateNetConfig/keystore/UTC--2018-06-01T10-10-01.852779Z--03010360ebbb7f49362a2c650a67661d464e2089: -------------------------------------------------------------------------------- 1 | {"id":"6d999d9b-e7ad-46d8-bea2-78df42a13f56","address":"03010360ebbb7f49362a2c650a67661d464e2089","crypto":{"cipher":"aes-128-ctr","ciphertext":"aabdd9539af22e7c69e04d258a43e39af55ed29b594affcc4d56b0dd19b0ae32","cipherparams":{"iv":"c03ba07d5304bbd953d7aa5adde0ee91"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ebabcf3194ff904867d3405854060cf7e47323b63d9b15240880c79e34ecff6f"},"mac":"d7f4d4929770cc1698118d445457112892e77e89124b9979c39a992fdb52a827"},"version":3} -------------------------------------------------------------------------------- /src/rpcTest/resources/test.conf: -------------------------------------------------------------------------------- 1 | # Default port at which mantis listen for rpc connections 2 | mantisUrl="http://localhost:8546/" 3 | 4 | # Used to sign transaction (must be the same as mantis/conf/storage.conf) 5 | privatenetDatadir=${user.home}"/.mantis-rpc-test/rpc-test-private" 6 | keystoreDir=${privatenetDatadir}"/keystore" 7 | -------------------------------------------------------------------------------- /src/rpcTest/scala/io/iohk/ethereum/rpcTest/RpcTestConfig.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.rpcTest 2 | 3 | import com.typesafe.config.ConfigFactory 4 | 5 | case class RpcTestConfig(mantisUrl: String, privateNetDataDir: String, keystoreDir: String) 6 | 7 | object RpcTestConfig { 8 | def apply(confName: String): RpcTestConfig = { 9 | val config = ConfigFactory.load(confName) 10 | val mantisUrl = config.getString("mantisUrl") 11 | val dataDir = config.getString("privatenetDatadir") 12 | val keystoreDir = config.getString("keystoreDir") 13 | new RpcTestConfig(mantisUrl, dataDir, keystoreDir) 14 | } 15 | } -------------------------------------------------------------------------------- /src/rpcTest/scala/io/iohk/ethereum/rpcTest/Tags.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.rpcTest 2 | 3 | import org.scalatest.Tag 4 | 5 | object Tags { 6 | object MainNet extends Tag("MainNet") 7 | object PrivNet extends Tag("PrivNet") 8 | object PrivNetNoMining extends Tag("PrivNetNoMining") 9 | } 10 | -------------------------------------------------------------------------------- /src/test/resources/downloadtest.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/src/test/resources/downloadtest.zip -------------------------------------------------------------------------------- /src/test/resources/explicit-scheduler.conf: -------------------------------------------------------------------------------- 1 | include "application.conf" 2 | 3 | akka.scheduler.implementation = "akka.testkit.ExplicitlyTriggeredScheduler" 4 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d{HH:mm:ss.SSS} %-5level %logger{36} %X{akkaSource} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/rnd.sh: -------------------------------------------------------------------------------- 1 | # Simple script to randomly kill running mantis instance 2 | # Just copy it to unzipped mantis cli dir and call ./rnd.sh 3 | 4 | signal=KILL 5 | 6 | sleep_a_while () { 7 | sleep $[ ( $RANDOM % 600 ) + 120 ]s 8 | } 9 | 10 | sleep_some () { 11 | sleep $[ ( 120 ) ]s 12 | } 13 | 14 | while true; do 15 | # Note: command launched in background: 16 | bin/mantis & 17 | 18 | # Save PID of command just launched: 19 | last_pid=$! 20 | 21 | # Sleep for a while: 22 | sleep_a_while 23 | 24 | # See if the command is still running, and kill it and sleep more if it is: 25 | if jps| grep 'mantis'; then 26 | kill -$signal $last_pid 2> /dev/null 27 | sleep_some 28 | fi 29 | 30 | # Go back to the beginning and launch the command again 31 | done 32 | -------------------------------------------------------------------------------- /src/test/resources/test-genesis-treasury.json: -------------------------------------------------------------------------------- 1 | { 2 | "difficulty": "0x0400", 3 | "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", 4 | "gasLimit": "0xff1388", 5 | "nonce": "0x0000000000000042", 6 | "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 7 | "timestamp": "0x0", 8 | "coinbase": "0x0000000000000000000000000000000000000000", 9 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "alloc": { 11 | "d7a681378321f472adffb9fdded2712f677e0ba9": {"balance": "1000000000000000000000000000000000000000000"}, 12 | "0000000000000000000000000000000000eeeeee": {"balance": "10"}, 13 | "0000000000000000000000000000000000000123": {"balance": "20"} 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/test-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "difficulty": "0x0400", 3 | "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", 4 | "gasLimit": "0xff1388", 5 | "nonce": "0x0000000000000042", 6 | "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 7 | "timestamp": "0x0", 8 | "coinbase": "0x0000000000000000000000000000000000000000", 9 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "alloc": { 11 | "d7a681378321f472adffb9fdded2712f677e0ba9": {"balance": "1000000000000000000000000000000000000000000"} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/SuperSlow.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import com.typesafe.config.ConfigFactory 4 | 5 | trait SuperSlow { 6 | private lazy val skip = ConfigFactory.load().getBoolean("skip-super-slow-tests") 7 | 8 | /** Some assertions may be prohibitively slow and shouldn't run on every CI run. Use this method when that's the case. 9 | * 10 | * @param f slow tests 11 | */ 12 | def superSlow[T](f: => T): Option[T] = 13 | if (skip) None else Some(f) 14 | } 15 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/Timeouts.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import scala.concurrent.duration._ 4 | 5 | object Timeouts { 6 | 7 | val shortTimeout: FiniteDuration = 500.millis 8 | val normalTimeout: FiniteDuration = 3.seconds 9 | val longTimeout: FiniteDuration = 10.seconds 10 | val veryLongTimeout: FiniteDuration = 30.seconds 11 | val miningTimeout: FiniteDuration = 20.minutes 12 | } 13 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/WithActorSystemShutDown.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum 2 | 3 | import akka.actor.ActorSystem 4 | import akka.testkit.TestKit 5 | 6 | import org.scalatest.BeforeAndAfterAll 7 | import org.scalatest.Suite 8 | 9 | trait WithActorSystemShutDown extends BeforeAndAfterAll { this: Suite => 10 | implicit val system: ActorSystem 11 | 12 | override def afterAll(): Unit = 13 | TestKit.shutdownActorSystem(system, verifySystemShutdown = true) 14 | } 15 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/blockchain/sync/EphemBlockchainTestSetup.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.blockchain.sync 2 | 3 | import io.iohk.ethereum.db.components.EphemDataSourceComponent 4 | import io.iohk.ethereum.db.components.Storages 5 | import io.iohk.ethereum.db.storage.pruning.ArchivePruning 6 | import io.iohk.ethereum.db.storage.pruning.PruningMode 7 | import io.iohk.ethereum.ledger.VMImpl 8 | import io.iohk.ethereum.nodebuilder.PruningConfigBuilder 9 | 10 | trait EphemBlockchainTestSetup extends ScenarioSetup { 11 | 12 | trait LocalPruningConfigBuilder extends PruningConfigBuilder { 13 | override lazy val pruningMode: PruningMode = ArchivePruning 14 | } 15 | 16 | //+ cake overrides 17 | override lazy val vm: VMImpl = new VMImpl 18 | override lazy val storagesInstance 19 | : EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = 20 | new EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages 21 | //- cake overrides 22 | 23 | def getNewStorages: EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages = 24 | new EphemDataSourceComponent with LocalPruningConfigBuilder with Storages.DefaultStorages 25 | } 26 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/checkpointing/CheckpointingTestHelpers.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.checkpointing 2 | 3 | import akka.util.ByteString 4 | 5 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair 6 | 7 | import io.iohk.ethereum.crypto.ECDSASignature 8 | import io.iohk.ethereum.crypto.ECDSASignatureImplicits.ECDSASignatureOrdering 9 | 10 | object CheckpointingTestHelpers { 11 | 12 | def createCheckpointSignatures( 13 | keys: Seq[AsymmetricCipherKeyPair], 14 | hash: ByteString 15 | ): Seq[ECDSASignature] = 16 | keys.map { k => 17 | ECDSASignature.sign(hash.toArray, k) 18 | }.sorted 19 | } 20 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/consensus/mining/MiningConfigs.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.Timeouts 6 | import io.iohk.ethereum.consensus.pow.EthashConfig 7 | import io.iohk.ethereum.domain.Address 8 | 9 | /** Provides utility values used throughout tests */ 10 | object MiningConfigs { 11 | final val blockCacheSize = 30 12 | final val coinbaseAddressNum = 42 13 | final val coinbase: Address = Address(coinbaseAddressNum) 14 | 15 | //noinspection ScalaStyle 16 | final val ethashConfig = new EthashConfig( 17 | ommersPoolSize = 30, 18 | ommerPoolQueryTimeout = Timeouts.normalTimeout, 19 | ethashDir = "~/.ethash", 20 | mineRounds = 100000 21 | ) 22 | 23 | final val miningConfig: MiningConfig = new MiningConfig( 24 | protocol = Protocol.PoW, 25 | coinbase = coinbase, 26 | headerExtraData = ByteString.empty, 27 | blockCacheSize = blockCacheSize, 28 | miningEnabled = false 29 | ) 30 | 31 | final val fullMiningConfig: FullMiningConfig[EthashConfig] = FullMiningConfig(miningConfig, ethashConfig) 32 | } 33 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/consensus/mining/MiningSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.consensus.mining 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class MiningSpec extends AnyFlatSpec with Matchers { 7 | 8 | "KnownProtocols" should "have unique names" in { 9 | val protocols = Protocol.KnownProtocols 10 | val names = Protocol.KnownProtocolNames 11 | 12 | protocols.size shouldBe names.size 13 | } 14 | 15 | it should "contain ethash" in { 16 | Protocol.find(Protocol.PoW.name).isDefined shouldBe true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/db/dataSource/RocksDbDataSourceTest.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.db.dataSource 2 | 3 | import java.nio.file.Files 4 | 5 | import org.scalatest.flatspec.AnyFlatSpec 6 | 7 | import io.iohk.ethereum.db.storage.Namespaces 8 | 9 | class RocksDbDataSourceTest extends AnyFlatSpec with DataSourceTestBehavior { 10 | 11 | private def createDataSource(path: String): RocksDbDataSource = { 12 | val dbPath: String = Files.createTempDirectory("temp-test-rocksdb").toAbsolutePath.toString 13 | 14 | RocksDbDataSource( 15 | new RocksDbConfig { 16 | override val createIfMissing: Boolean = true 17 | override val paranoidChecks: Boolean = true 18 | override val path: String = dbPath 19 | override val maxThreads: Int = 1 20 | override val maxOpenFiles: Int = 32 21 | override val verifyChecksums: Boolean = true 22 | override val levelCompaction: Boolean = true 23 | override val blockSize: Long = 16384 24 | override val blockCacheSize: Long = 33554432 25 | }, 26 | Namespaces.nsSeq 27 | ) 28 | } 29 | 30 | (it should behave).like(dataSource(createDataSource)) 31 | } 32 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/domain/BlockSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | import io.iohk.ethereum.Fixtures.Blocks._ 7 | 8 | class BlockSpec extends AnyFlatSpec with Matchers { 9 | "Block size" should "be correct" in { 10 | assert(Block.size(Genesis.block) == Genesis.size) 11 | assert(Block.size(Block3125369.block) == Block3125369.size) 12 | assert(Block.size(DaoForkBlock.block) == DaoForkBlock.size) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/domain/BlockchainReaderSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import org.bouncycastle.util.encoders.Hex 4 | import org.scalatest.flatspec.AnyFlatSpec 5 | import org.scalatest.matchers.should.Matchers 6 | import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks 7 | 8 | import io.iohk.ethereum.ObjectGenerators 9 | import io.iohk.ethereum.blockchain.sync.EphemBlockchainTestSetup 10 | import io.iohk.ethereum.network.p2p.messages.BaseETH6XMessages.NewBlock 11 | import io.iohk.ethereum.security.SecureRandomBuilder 12 | 13 | class BlockchainReaderSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks with SecureRandomBuilder { 14 | 15 | val chainId: Option[Byte] = Hex.decode("3d").headOption 16 | 17 | "BlockchainReader" should "be able to get the best block after it was stored by BlockchainWriter" in new EphemBlockchainTestSetup { 18 | forAll(ObjectGenerators.newBlockGen(secureRandom, chainId)) { case NewBlock(block, weight) => 19 | blockchainWriter.save(block, Nil, ChainWeight(0, weight), true) 20 | 21 | blockchainReader.getBestBlock() shouldBe Some(block) 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/domain/SignedTransactionWithAccessListSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.domain 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | 5 | import io.iohk.ethereum.vm.Generators 6 | 7 | class SignedTransactionWithAccessListSpec extends AnyFlatSpec with SignedTransactionBehavior { 8 | 9 | private def allowedPointSigns(chainId: Byte) = Set(0.toByte, 1.toByte) 10 | 11 | ("Signed TransactionWithAccessList" should behave).like( 12 | SignedTransactionBehavior(Generators.typedTransactionGen, allowedPointSigns) 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/jsonrpc/ProofServiceDummy.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.jsonrpc 2 | 3 | import monix.eval.Task 4 | 5 | import io.iohk.ethereum.domain.Account 6 | import io.iohk.ethereum.domain.Address 7 | import io.iohk.ethereum.domain.UInt256 8 | import io.iohk.ethereum.jsonrpc.ProofService.GetProofRequest 9 | import io.iohk.ethereum.jsonrpc.ProofService.GetProofResponse 10 | import io.iohk.ethereum.jsonrpc.ProofService.ProofAccount 11 | 12 | object ProofServiceDummy extends ProofService { 13 | 14 | val EmptyAddress: Address = Address(Account.EmptyCodeHash) 15 | val EmptyProofAccount: ProofAccount = ProofAccount( 16 | EmptyAddress, 17 | Seq.empty, 18 | BigInt(42), 19 | Account.EmptyCodeHash, 20 | UInt256.Zero, 21 | Account.EmptyStorageRootHash, 22 | Seq.empty 23 | ) 24 | val EmptyProofResponse: GetProofResponse = GetProofResponse(EmptyProofAccount) 25 | 26 | override def getProof(req: GetProofRequest): ServiceResponse[GetProofResponse] = 27 | Task.now(Right(EmptyProofResponse)) 28 | } 29 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/ledger/BlockRewardCalculatorOps.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.ledger 2 | 3 | object BlockRewardCalculatorOps { 4 | 5 | implicit class BlockRewardCalculatorWithMinerReward(calculator: BlockRewardCalculator) { 6 | def calculateMiningReward(blockNumber: BigInt, numberOfOmmers: Int): BigInt = { 7 | val rewardForBlock = calculator.calculateMiningRewardForBlock(blockNumber) 8 | val rewardForOmmers = calculator.calculateMiningRewardForOmmers(blockNumber, numberOfOmmers) 9 | rewardForBlock + rewardForOmmers 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/rlp/RLPSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.rlp 2 | 3 | import org.scalacheck.Arbitrary 4 | import org.scalacheck.Gen 5 | import org.scalatest.flatspec.AnyFlatSpec 6 | import org.scalatest.matchers.should.Matchers 7 | import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks 8 | 9 | import io.iohk.ethereum.domain.Transaction 10 | 11 | class RLPSpec extends AnyFlatSpec with ScalaCheckPropertyChecks with Matchers { 12 | 13 | "PrefixedRLPEncodable" should "reject invalid transaction type outside of [0, 0x7f]" in { 14 | forAll(Arbitrary.arbitrary[Byte].suchThat(b => b < Transaction.MinAllowedType || b > Transaction.MaxAllowedType)) { 15 | transactionType => 16 | an[RuntimeException] shouldBe thrownBy(PrefixedRLPEncodable(transactionType, RLPList())) 17 | } 18 | 19 | } 20 | 21 | "PrefixedRLPEncodable" should "accept valid transaction type [0, 0x7f]" in { 22 | forAll(Gen.choose[Byte](Transaction.MinAllowedType, Transaction.MaxAllowedType)) { transactionType => 23 | PrefixedRLPEncodable(transactionType, RLPList()) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/testing/ActorsTesting.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.testing 2 | import akka.actor.ActorRef 3 | import akka.testkit.TestActor.AutoPilot 4 | 5 | object ActorsTesting { 6 | def simpleAutoPilot(makeResponse: PartialFunction[Any, Any]): AutoPilot = 7 | new AutoPilot { 8 | def run(sender: ActorRef, msg: Any) = { 9 | val response = makeResponse.lift(msg) 10 | response match { 11 | case Some(value) => sender ! value 12 | case _ => () 13 | } 14 | this 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/utils/ConfigSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class ConfigSpec extends AnyFlatSpec with Matchers { 7 | "clientId" should "by default come from VersionInfo" in { 8 | Config.clientId shouldBe VersionInfo.nodeName() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/utils/ConfigUtilsSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import com.typesafe.config.ConfigFactory 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.wordspec.AnyWordSpec 6 | 7 | class ConfigUtilsSpec extends AnyWordSpec with Matchers { 8 | "keys" should { 9 | "return top-level keys of given config instance" in { 10 | val config = ConfigFactory.parseString("""{ 11 | foo { 12 | bar { 13 | a = a 14 | } 15 | } 16 | baz = baz 17 | }""") 18 | 19 | ConfigUtils.keys(config) shouldBe Set("foo", "baz") 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/utils/GenOps.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | import org.scalacheck.Gen 3 | 4 | object GenOps { 5 | implicit class GenOps[T](gen: Gen[T]) { 6 | def pickValue: T = 7 | Iterator 8 | .continually(gen) 9 | .map(_.sample) 10 | .collectFirst { case Some(value) => 11 | value 12 | } 13 | .get 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/utils/MockClock.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import java.time.Clock 4 | import java.time.Instant 5 | import java.time.ZoneId 6 | 7 | class MockClock( 8 | private var currentTimeMillis: Long = System.currentTimeMillis, 9 | zoneId: ZoneId = ZoneId.of("UTC") 10 | ) extends Clock { 11 | def windByMillis(by: Long): Unit = 12 | currentTimeMillis = currentTimeMillis + by 13 | 14 | override def instant(): Instant = Instant.ofEpochMilli(currentTimeMillis) 15 | // The following are implemented for completness' sake but not used: 16 | override def getZone(): ZoneId = zoneId 17 | override def withZone(x: ZoneId): Clock = new MockClock(currentTimeMillis, zoneId) 18 | } 19 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/utils/VersionInfoSpec.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.utils 2 | 3 | import org.scalatest.flatspec.AnyFlatSpec 4 | import org.scalatest.matchers.should.Matchers 5 | 6 | class VersionInfoSpec extends AnyFlatSpec with Matchers { 7 | behavior.of("nodeName") 8 | 9 | it should "match ethstats expected structure and preserve major and minor Java version" in { 10 | (VersionInfo 11 | .nodeName() should fullyMatch) 12 | .regex("""mantis/v\d(\.\d+)*(-SNAPSHOT)?-[a-z0-9]{7}/[^/]+-[^/]+/[^/]+-.[^/]+-java-\d+\.\d+[._0-9]*""") 13 | } 14 | 15 | it should "augment the name with an identity" in { 16 | val name = VersionInfo.nodeName(Some("iohk")) 17 | name should startWith("mantis/iohk/v") 18 | name.count(_ == '/') shouldBe 4 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/vm/Assembly.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import akka.util.ByteString 4 | 5 | object Assembly { 6 | 7 | sealed trait ByteCode { 8 | def bytes: ByteString 9 | } 10 | 11 | implicit class OpCodeAsByteCode(val op: OpCode) extends ByteCode { 12 | def bytes: ByteString = ByteString(op.code) 13 | } 14 | 15 | implicit class IntAsByteCode(val i: Int) extends ByteCode { 16 | def bytes: ByteString = ByteString(i.toByte) 17 | } 18 | 19 | implicit class ByteAsByteCode(val byte: Byte) extends ByteCode { 20 | def bytes: ByteString = ByteString(byte) 21 | } 22 | 23 | implicit class ByteStringAsByteCode(val bytes: ByteString) extends ByteCode 24 | } 25 | 26 | import Assembly._ 27 | 28 | case class Assembly(byteCode: ByteCode*) { 29 | val code: ByteString = byteCode.foldLeft(ByteString.empty)(_.bytes ++ _.bytes) 30 | 31 | val program: Program = Program(code) 32 | 33 | def linearConstGas(config: EvmConfig): BigInt = byteCode.foldLeft(BigInt(0)) { 34 | case (g, b: OpCodeAsByteCode) => g + b.op.baseGasFn(config.feeSchedule) 35 | case (g, _) => g 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/vm/Fixtures.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | object Fixtures { 4 | 5 | val ConstantinopleBlockNumber = 200 6 | val PetersburgBlockNumber = 400 7 | val PhoenixBlockNumber = 600 8 | val IstanbulBlockNumber = 600 9 | val MagnetoBlockNumber = 700 10 | val BerlinBlockNumber = 700 11 | 12 | val blockchainConfig: BlockchainConfigForEvm = BlockchainConfigForEvm( 13 | // block numbers are irrelevant 14 | frontierBlockNumber = 0, 15 | homesteadBlockNumber = 0, 16 | eip150BlockNumber = 0, 17 | eip160BlockNumber = 0, 18 | eip161BlockNumber = 0, 19 | byzantiumBlockNumber = 0, 20 | constantinopleBlockNumber = ConstantinopleBlockNumber, 21 | istanbulBlockNumber = IstanbulBlockNumber, 22 | maxCodeSize = None, 23 | accountStartNonce = 0, 24 | atlantisBlockNumber = 0, 25 | aghartaBlockNumber = 0, 26 | petersburgBlockNumber = PetersburgBlockNumber, 27 | phoenixBlockNumber = PhoenixBlockNumber, 28 | magnetoBlockNumber = MagnetoBlockNumber, 29 | berlinBlockNumber = BerlinBlockNumber, 30 | chainId = 0x3d.toByte 31 | ) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/vm/MockStorage.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm 2 | 3 | import io.iohk.ethereum.domain.UInt256 4 | 5 | object MockStorage { 6 | val Empty: MockStorage = MockStorage() 7 | 8 | def fromSeq(words: Seq[UInt256]): MockStorage = { 9 | val map = words.zipWithIndex.map { case (w, i) => BigInt(i) -> w.toBigInt }.toMap 10 | MockStorage(map) 11 | } 12 | } 13 | 14 | case class MockStorage(data: Map[BigInt, BigInt] = Map()) extends Storage[MockStorage] { 15 | def store(offset: BigInt, value: BigInt): MockStorage = { 16 | val updated = 17 | if (UInt256(value) == UInt256.Zero) 18 | data - offset 19 | else 20 | data + (offset -> value) 21 | 22 | copy(data = updated) 23 | } 24 | 25 | def load(addr: BigInt): BigInt = 26 | data.getOrElse(addr, UInt256.Zero) 27 | 28 | def isEmpty: Boolean = 29 | data.isEmpty 30 | } 31 | -------------------------------------------------------------------------------- /src/test/scala/io/iohk/ethereum/vm/utils/MockVmInput.scala: -------------------------------------------------------------------------------- 1 | package io.iohk.ethereum.vm.utils 2 | 3 | import akka.util.ByteString 4 | 5 | import io.iohk.ethereum.Fixtures.{Blocks => BlockFixtures} 6 | import io.iohk.ethereum.crypto.ECDSASignature 7 | import io.iohk.ethereum.domain.Address 8 | import io.iohk.ethereum.domain.BlockHeader 9 | import io.iohk.ethereum.domain.LegacyTransaction 10 | import io.iohk.ethereum.domain.SignedTransaction 11 | 12 | object MockVmInput { 13 | 14 | class MockTransaction( 15 | tx: LegacyTransaction, 16 | senderAddress: Address, 17 | pointSign: Byte = 0, 18 | signatureRandom: BigInt = 0, 19 | signature: BigInt = 0 20 | ) extends SignedTransaction( 21 | tx, 22 | ECDSASignature(v = pointSign, r = signatureRandom.bigInteger, s = signature.bigInteger) 23 | ) 24 | 25 | val defaultGasPrice: BigInt = 1000 26 | 27 | def transaction( 28 | senderAddress: Address, 29 | payload: ByteString, 30 | value: BigInt, 31 | gasLimit: BigInt, 32 | gasPrice: BigInt = defaultGasPrice, 33 | receivingAddress: Option[Address] = None, 34 | nonce: BigInt = 0 35 | ): SignedTransaction = 36 | new MockTransaction(LegacyTransaction(nonce, gasPrice, gasLimit, receivingAddress, value, payload), senderAddress) 37 | 38 | def blockHeader: BlockHeader = BlockFixtures.ValidBlock.header 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/universal/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Input Output 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/universal/bin/eckeygen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR/.. 5 | exec ./bin/mantis -- eckeygen "$@" 6 | -------------------------------------------------------------------------------- /src/universal/bin/eckeygen.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "%~dp0\.." 4 | 5 | call bin\mantis.bat eckeygen %* 6 | -------------------------------------------------------------------------------- /src/universal/bin/faucet-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR/.. 5 | exec ./bin/mantis -Dconfig.file=./conf/faucet.conf "$@" -- faucet 6 | -------------------------------------------------------------------------------- /src/universal/bin/faucet-server.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "%~dp0\.." 4 | 5 | call bin\mantis.bat faucet %* 6 | -------------------------------------------------------------------------------- /src/universal/bin/mantis-launcher: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR/.. 5 | 6 | CONFIG_FILE="./conf/$1.conf" 7 | if [ -f "$CONFIG_FILE" ]; then 8 | shift 9 | CHAIN_PARAM="-Dconfig.file=$CONFIG_FILE" 10 | elif [ -z "$1" ]; then 11 | CHAIN_PARAM="-Dconfig.file=./conf/etc.conf" 12 | fi 13 | 14 | exec ./bin/mantis ${CHAIN_PARAM:+"$CHAIN_PARAM"} "$@" 15 | -------------------------------------------------------------------------------- /src/universal/bin/mantis-launcher.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "%~dp0\.." 4 | 5 | set "CONFIG_FILE=conf\%1.conf" 6 | set "RESTVAR=%*" 7 | 8 | if exist %CONFIG_FILE% goto :set_chain_param 9 | 10 | if "%1"=="" set "CHAIN_PARAM=-Dconfig.file=conf\etc.conf" 11 | goto :launch 12 | 13 | :set_chain_param 14 | set "CHAIN_PARAM=-Dconfig.file=%CONFIG_FILE%" 15 | set RESTVAR= 16 | shift 17 | :loop 18 | if "%1"=="" goto :launch 19 | set RESTVAR=%RESTVAR% %1 20 | shift 21 | goto :loop 22 | 23 | :launch 24 | call bin\mantis.bat %CHAIN_PARAM% %RESTVAR% 25 | -------------------------------------------------------------------------------- /src/universal/bin/mantis-vm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR/.. 5 | 6 | exec ./bin/mantis vm-server "$@" 7 | -------------------------------------------------------------------------------- /src/universal/bin/mantis-vm.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "%~dp0\.." 4 | 5 | call bin\mantis.bat vm-server %* 6 | -------------------------------------------------------------------------------- /src/universal/bin/signatureValidator: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR/.. 5 | exec ./bin/mantis -- signature-validator "$@" 6 | -------------------------------------------------------------------------------- /src/universal/bin/signatureValidator.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd "%~dp0\.." 4 | 5 | call bin\mantis.bat signature-validator %* 6 | -------------------------------------------------------------------------------- /src/universal/conf/application.ini: -------------------------------------------------------------------------------- 1 | -J-Xmx4g -J-Xss10M 2 | -------------------------------------------------------------------------------- /src/universal/conf/mallet.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | # to enable logging use: ["akka.event.slf4j.Slf4jLogger"] 3 | loggers = [] 4 | 5 | loglevel = OFF 6 | } 7 | -------------------------------------------------------------------------------- /src/universal/mantis_config.txt: -------------------------------------------------------------------------------- 1 | -Dconfig.file=.\conf\mantis.conf 2 | -Dlogback.configurationFile=.\conf\logback.xml 3 | -Xss10M 4 | -------------------------------------------------------------------------------- /test-ets.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git submodule init 4 | git submodule update 5 | 6 | echo "booting Mantis and waiting for RPC API to be up" 7 | $SBT -Dconfig.file=./src/main/resources/conf/testmode.conf run &> mantis-log.txt & 8 | 9 | while ! nc -z localhost 8546; do 10 | sleep 0.1 11 | done 12 | 13 | final_exit_code=0 14 | 15 | function run_and_annotate { 16 | echo "running retesteth $1" 17 | timeout 15m ets/retesteth -t "$1" -- --verbosity 3 &> "retesteth-$1-log.txt" 18 | exit_code=$? 19 | echo "retesteth $1 exit code: $exit_code" 20 | 21 | style="info" 22 | if [[ "$exit_code" -gt "0" ]]; then 23 | final_exit_code="$exit_code" 24 | style="error" 25 | fi 26 | 27 | summary=$(sed -n '/Total Tests Run/,$p' "retesteth-$1-log.txt") 28 | if [[ -z "$summary" ]]; then 29 | summary="retesteth crashed; check the artifacts" 30 | fi 31 | passed=$(grep -oP 'Total Tests Run: \d+' "retesteth-$1-log.txt") 32 | failed=$(grep -oP 'TOTAL ERRORS DETECTED: \d+' "retesteth-$1-log.txt") 33 | 34 | cat < 36 | retesteth: $1 -- $passed -- $failed 37 |

38 | $summary
39 | 
40 | 41 | EOF 42 | } 43 | 44 | run_and_annotate "GeneralStateTests" 45 | run_and_annotate "BlockchainTests" 46 | 47 | echo "shutting down mantis" 48 | kill %1 49 | 50 | exit $final_exit_code 51 | -------------------------------------------------------------------------------- /tls/gen-cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo `dirname $0` 4 | cd `dirname $0` 5 | 6 | export PW=`pwgen -Bs 10 1` 7 | echo $PW > ./password 8 | 9 | rm ./mantisCA.p12 10 | 11 | keytool -genkeypair \ 12 | -keystore mantisCA.p12 \ 13 | -storetype PKCS12 \ 14 | -dname "CN=127.0.0.1" \ 15 | -ext "san=ip:127.0.0.1,dns:localhost" \ 16 | -keypass:env PW \ 17 | -storepass:env PW \ 18 | -keyalg RSA \ 19 | -keysize 4096 \ 20 | -validity 9999 \ 21 | -ext KeyUsage:critical="keyCertSign" \ 22 | -ext BasicConstraints:critical="ca:true" 23 | -------------------------------------------------------------------------------- /tls/mantisCA.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/mantis/dc484239a83af9d600b5ce510094dd3b232cfead/tls/mantisCA.p12 -------------------------------------------------------------------------------- /tls/password: -------------------------------------------------------------------------------- 1 | gJWA4qV4P4 2 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | // NOTE: This is replaced with `sed` during release, 2 | // but it could also be removed, and be determined 3 | // based on `git` tags by https://github.com/dwijnand/sbt-dynver, 4 | // which is a dependency of `sbt-ci-release`. 5 | 6 | (ThisBuild / version) := "3.4.0-SNAPSHOT" 7 | --------------------------------------------------------------------------------