diff --git a/src/main/kotlin/org/ethereum/lists/chains/Main.kt b/src/main/kotlin/org/ethereum/lists/chains/Main.kt index e78b6153..8fb02d59 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Main.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Main.kt @@ -34,7 +34,7 @@ private fun createOutputFiles() { allChainFiles .map { Klaxon().parseJsonObject(it.reader()) } - .sortedBy { (it["chainId"] as Number).toLong() } + .sortedBy { (it["chainId"] as Number).toLong() } .forEach { jsonObject -> chainJSONArray.add(jsonObject) @@ -215,10 +215,28 @@ fun checkChain(chainFile: File, connectRPC: Boolean) { throw ParentMustBeObject() } - if (it.keys != mutableSetOf("chain", "type")) { + if (!it.keys.containsAll(setOf("chain", "type"))) { throw ParentMustHaveChainAndType() } + val extraFields = it.keys - setOf("chain", "type", "bridges") + if (extraFields.isNotEmpty()) { + throw ParentHasExtraFields(extraFields) + } + + val bridges = it["bridges"] + if (bridges != null && bridges !is List<*>) { + throw ParentBridgeNoArray() + } + (bridges as? JsonArray<*>)?.forEach { bridge -> + if (bridge !is JsonObject) { + throw BridgeNoObject() + } + if (bridge.keys.size != 1 || bridge.keys.first() != "url") { + throw BridgeOnlyURL() + } + } + if (!setOf("L2", "shard").contains(it["type"])) { throw ParentHasInvalidType(it["type"] as? String) } 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 ac92779d..e4af9a9b 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt @@ -19,4 +19,8 @@ class ExplorerStandardMustBeEIP3091: Exception("explorer standard must be EIP309 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 ParentHasExtraFields(fields: Set): Exception("parent has extra field: $fields") +class ParentBridgeNoArray: Exception("parent bridge must be array") +class BridgeNoObject: Exception("parent bridges must be array consisting of json objects") +class BridgeOnlyURL: Exception("parent bridge only contain an URL") 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 d34f090e..ef74c284 100644 --- a/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt +++ b/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt @@ -35,6 +35,20 @@ class TheChainChecker { checkChain(file, false) } + @Test + fun shouldPassForValidChainWithParentBridge() { + val file = getFile("valid/withparentbridge/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = BridgeNoObject::class) + fun shouldFailForParentBridgeElementNoObject() { + val file = getFile("invalid/withparentextrabridgeelementnoobject/eip155-2.json") + + checkChain(file, false) + } + @Test(expected = ParentMustBeObject::class) fun shouldFailForParentNoObject() { val file = getFile("invalid/withparentnobject/eip155-2.json") @@ -49,6 +63,33 @@ class TheChainChecker { checkChain(file, false) } + @Test(expected = ParentHasExtraFields::class) + fun shouldFailForParentWithExtraParentField() { + val file = getFile("invalid/withparentextrafield/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = ParentHasExtraFields::class) + fun shouldFailForParentWithExtraField() { + val file = getFile("invalid/withparentextrafield/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = BridgeOnlyURL::class) + fun shouldFailForParentWithExtraBridgesField() { + val file = getFile("invalid/withparentextrabridgesfield/eip155-2.json") + + checkChain(file, false) + } + + @Test(expected = ParentBridgeNoArray::class) + fun shouldFailForParentWithExtraBridgeNoArray() { + val file = getFile("invalid/withparentextrabridgesnoarray/eip155-2.json") + + checkChain(file, false) + } @Test(expected = ParentChainDoesNotExist::class) fun shouldFailIfParentChainDoesNotExist() { diff --git a/src/test/resources/test_chains/invalid/withparentextrabridgeelementnoobject/eip155-2.json b/src/test/resources/test_chains/invalid/withparentextrabridgeelementnoobject/eip155-2.json new file mode 100644 index 00000000..7cc1fd47 --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentextrabridgeelementnoobject/eip155-2.json @@ -0,0 +1,24 @@ +{ + "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", + "bridges": ["yolo"] + } +} diff --git a/src/test/resources/test_chains/invalid/withparentextrabridgesfield/eip155-2.json b/src/test/resources/test_chains/invalid/withparentextrabridgesfield/eip155-2.json new file mode 100644 index 00000000..e4007b5e --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentextrabridgesfield/eip155-2.json @@ -0,0 +1,24 @@ +{ + "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", + "bridges": [{"yolo":"yoooo"}] + } +} diff --git a/src/test/resources/test_chains/invalid/withparentextrabridgesnoarray/eip155-2.json b/src/test/resources/test_chains/invalid/withparentextrabridgesnoarray/eip155-2.json new file mode 100644 index 00000000..8fa85245 --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentextrabridgesnoarray/eip155-2.json @@ -0,0 +1,24 @@ +{ + "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", + "bridges": "yolo" + } +} diff --git a/src/test/resources/test_chains/invalid/withparentextrafield/eip155-2.json b/src/test/resources/test_chains/invalid/withparentextrafield/eip155-2.json new file mode 100644 index 00000000..0be4e23e --- /dev/null +++ b/src/test/resources/test_chains/invalid/withparentextrafield/eip155-2.json @@ -0,0 +1,24 @@ +{ + "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", + "yolo": "yooooo" + } +} diff --git a/src/test/resources/test_chains/valid/withparentbridge/eip155-1.json b/src/test/resources/test_chains/valid/withparentbridge/eip155-1.json new file mode 100644 index 00000000..457f8964 --- /dev/null +++ b/src/test/resources/test_chains/valid/withparentbridge/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/withparentbridge/eip155-2.json b/src/test/resources/test_chains/valid/withparentbridge/eip155-2.json new file mode 100644 index 00000000..e6aef8e4 --- /dev/null +++ b/src/test/resources/test_chains/valid/withparentbridge/eip155-2.json @@ -0,0 +1,26 @@ +{ + "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", + "bridges": [ + {"url": "https://bridge.foo.org"} + ] + } +}