diff --git a/src/main/kotlin/org/ethereum/lists/chains/Env.kt b/src/main/kotlin/org/ethereum/lists/chains/Env.kt index a1c92e40..74ef5bdf 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Env.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Env.kt @@ -21,7 +21,8 @@ val optionalFields = listOf( "slip44", "ens", "icon", - "explorers" + "explorers", + "parent" ) val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() diff --git a/src/main/kotlin/org/ethereum/lists/chains/Main.kt b/src/main/kotlin/org/ethereum/lists/chains/Main.kt index 9ff191ce..e51d8798 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Main.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Main.kt @@ -8,6 +8,7 @@ import org.ethereum.lists.chains.model.* import org.kethereum.erc55.isValid import org.kethereum.model.Address import org.kethereum.rpc.HttpEthereumRPC +import java.lang.IllegalArgumentException val parsedShortNames = mutableSetOf() val parsedNames = mutableSetOf() @@ -207,6 +208,25 @@ fun checkChain(chainFile: File, connectRPC: Boolean) { } } + jsonObject["parent"]?.let { + if (it !is JsonObject) { + throw ParentMustBeObject() + } + + if (it.keys != mutableSetOf("chain", "type")) { + throw ParentMustHaveChainAndType() + } + + if (!setOf("L2", "shard").contains(it["type"])) { + throw ParentHasInvalidType(it["type"] as? String) + } + + if (!File(chainFile.parentFile, it["chain"] as String + ".json").exists()) { + throw ParentChainDoesNotExist(it["chain"] as String) + } + + } + if (connectRPC) { if (jsonObject["rpc"] is List<*>) { (jsonObject["rpc"] as List<*>).forEach { diff --git a/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt b/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt index 82ea8c74..ac92779d 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt @@ -16,3 +16,7 @@ class ExplorersMustBeArray: Exception("explorers must be an array") class ExplorerMustHaveName: Exception("Explorer must have name") class ExplorerInvalidUrl: Exception("Explorer have url starting with https://") class ExplorerStandardMustBeEIP3091: Exception("explorer standard must be EIP3091 - currently the only one supported") +class ParentHasInvalidType(type: String?): Exception("Parent has invalid type $type - only L2 or shard allowed") +class ParentMustBeObject: Exception("parent must be an object") +class ParentMustHaveChainAndType: Exception("parent must have fields 'chain' and 'type'") +class ParentChainDoesNotExist(chain: String): Exception("Referenced parent chain ($chain) does not exist") \ No newline at end of file diff --git a/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt b/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt index cdbfff01..d34f090e 100644 --- a/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt +++ b/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt @@ -28,6 +28,35 @@ class TheChainChecker { checkChain(file, false) } + @Test + fun shouldPassForValidChainWithParent() { + val file = getFile("valid/withparent/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = ParentMustBeObject::class) + fun shouldFailForParentNoObject() { + val file = getFile("invalid/withparentnobject/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = ParentHasInvalidType::class) + fun shouldFailForParentWithInvalidType() { + val file = getFile("invalid/withparentinvalidtype/eip155-2.json") + + checkChain(file, false) + } + + + @Test(expected = ParentChainDoesNotExist::class) + fun shouldFailIfParentChainDoesNotExist() { + val file = getFile("invalid/withparentchaindoesnotexist/eip155-2.json") + + checkChain(file, false) + } + @Test(expected = FileNameMustMatchChainId::class) fun shouldFailForInvalidFilename() { val file = getFile("invalid/eip155-invalid_filename.json") diff --git a/src/test/resources/test_chains/invalid/withparentchaindoesnotexist/eip155-2.json b/src/test/resources/test_chains/invalid/withparentchaindoesnotexist/eip155-2.json new file mode 100644 index 00000000..165a4187 --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentchaindoesnotexist/eip155-2.json @@ -0,0 +1,23 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 2, + "networkId": 2, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "parent": { + "chain": "eip155-1", + "type": "L2" + } +} diff --git a/src/test/resources/test_chains/invalid/withparentinvalidtype/eip155-2.json b/src/test/resources/test_chains/invalid/withparentinvalidtype/eip155-2.json new file mode 100644 index 00000000..e6e90ddc --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentinvalidtype/eip155-2.json @@ -0,0 +1,23 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 2, + "networkId": 2, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "parent": { + "chain": "eip155-1", + "type": "yolo" + } +} diff --git a/src/test/resources/test_chains/invalid/withparentnobject/eip155-2.json b/src/test/resources/test_chains/invalid/withparentnobject/eip155-2.json new file mode 100644 index 00000000..decf6653 --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentnobject/eip155-2.json @@ -0,0 +1,20 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 2, + "networkId": 2, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "parent": "yolo" +} diff --git a/src/test/resources/test_chains/valid/withparent/eip155-1.json b/src/test/resources/test_chains/valid/withparent/eip155-1.json new file mode 100644 index 00000000..457f8964 --- /dev/null +++ b/src/test/resources/test_chains/valid/withparent/eip155-1.json @@ -0,0 +1,19 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + } +} diff --git a/src/test/resources/test_chains/valid/withparent/eip155-2.json b/src/test/resources/test_chains/valid/withparent/eip155-2.json new file mode 100644 index 00000000..165a4187 --- /dev/null +++ b/src/test/resources/test_chains/valid/withparent/eip155-2.json @@ -0,0 +1,23 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 2, + "networkId": 2, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "parent": { + "chain": "eip155-1", + "type": "L2" + } +}