Skip to content

Commit

Permalink
feat(bungee-hermes): viewProof & ethereum strategy
Browse files Browse the repository at this point in the history
* Views have new attribute viewProof
* This attribute has the roots of all state proofs and transaction
proofs in the view
* Added new endpoint to verify integrity of view proofs
* Created strategy for bungee-hermes to support the ethereum-connector
* Created new test for the strategy-ethereum, and altered the API test
to test the new viewProof endpoint
* Updated documentation to reflect new changes.

Co-authored-by: André Augusto <[email protected]>
Co-authored-by: Rafael Belchior <[email protected]>

Signed-off-by: eduv09 <[email protected]>
  • Loading branch information
eduv09 committed Apr 8, 2024
1 parent afce155 commit 103bf8c
Show file tree
Hide file tree
Showing 22 changed files with 1,284 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@
"lmify",
"LOCALMSPID",
"mailru",
"Merkle",
"merkletreejs",
"miekg",
"mitchellh",
"MSPCONFIGPATH",
Expand Down
36 changes: 35 additions & 1 deletion packages/cactus-plugin-bungee-hermes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ Know how to use the following plugins of the project:

- [cactus-plugin-ledger-connector-fabric](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-fabric)
- [cactus-plugin-ledger-connector-besu](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-besu)
- [cactus-plugin-ledger-connector-ethereum](https://github.com/hyperledger/cactus/tree/main/packages/cactus-plugin-ledger-connector-ethereum)


## Architecture

The plugin interacts with a cactus ledger connector, using strategies with custom logic for each different network.

Note that, so far, only strategies for Fabric and Besu networks were implemented. Smart-contracts in Fabric and Besu must implement the interface provided in the files ITraceableContract.ts and ITraceableContract.sol, in the test directory
Note that, so far, only strategies for Fabric, Besu and Ethereum networks were implemented. Smart-contracts for Fabric and EVM based chains must implement the interface provided in the files ITraceableContract.ts and ITraceableContract.sol, in the test directory

The plugin stands _behind_ a cacti-ledger-connector, which is used to fetch information from the ledger to create the snapshot.
```typescript
Expand Down Expand Up @@ -70,10 +71,12 @@ Endpoints exposed:
- CreateViewV1
- GetPublicKey
- GetAvailableStrategies
- VerifyMerkleRoot


## Running the tests
- **besu-test-basic.test.ts**: A test using strategy-besu and a besu connector, testing creating views for different timeframes and states.
- **ethereum-test-basic.test.ts**: A test using strategy-ethereum and a ethereum connector, testing creating views for different timeframes and states.
- **fabric-test-basic.test.ts**: A test using strategy-fabric and a fabric connector, testing creating views for different timeframes and states.
- **besu-test-pruning.test.ts**: A test using strategy-besu and a besu connector, testing creating views for specific timeframes.
- **fabric-test-pruning.test.ts**: A test using strategy-fabric and a fabric connector, testing creating views for specific timeframes.
Expand Down Expand Up @@ -149,6 +152,37 @@ Note that each strategy can be used to query different ledgers (ledgers of the s
Each strategy implements the logic to query information from each different ledger (i.e. capture set of asset states), while bungee-hermes plugin handles the snapshot and view creation.


'View' object contains a 'viewProof'. viewProof is composed by two merkle trees, one for stateProofs and another for transactionProofs.
One can check if the content of a view has no inconsistencies, by querying the VerifyMerkleRoot endpoint with the appropriate input:

```typescript
//using a previously created View object

const stateProofs = view?.getSnapshot()
.getStateBins()
.map((x) => JSON.stringify(x.getStateProof()));
const transactionProofs: string[] = [];
view?.getSnapshot()
.getStateBins()
.forEach((state) =>
state
.getTransactions()
.forEach((t) => transactionProofs.push(JSON.stringify(t.getProof()))),
);
const verifyStateRoot = await bungeeApi.verifyMerkleRoot({
input: stateProofs?.reverse(), //check integrity, order should not matter
root: proof?.statesMerkleRoot,
});
expect(verifyStateRoot.data.result).toBeTrue();

const verifyTransactionsRoot = await bungeeApi.verifyMerkleRoot({
input: transactionProofs?.reverse(), //check integrity, order should not matter
root: proof?.transactionsMerkleRoot,
});
expect(verifyTransactionsRoot.data.result).toBeTrue();
```



## Contributing
We welcome contributions to Hyperledger Cactus in many forms, and there’s always plenty to do!
Expand Down
6 changes: 4 additions & 2 deletions packages/cactus-plugin-bungee-hermes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,21 @@
"@hyperledger/cactus-core-api": "2.0.0-alpha.2",
"@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2",
"@hyperledger/cactus-plugin-ledger-connector-besu": "2.0.0-alpha.2",
"@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.0.0-alpha.2",
"@hyperledger/cactus-plugin-ledger-connector-fabric": "2.0.0-alpha.2",
"@hyperledger/cactus-plugin-object-store-ipfs": "2.0.0-alpha.2",
"@hyperledger/cactus-test-tooling": "2.0.0-alpha.2",
"axios": "1.6.0",
"body-parser": "1.20.2",
"fs-extra": "10.1.0",
"key-encoder": "2.0.3",
"merkletreejs": "0.3.11",
"typescript-optional": "2.0.1",
"uuid": "9.0.1",
"web3": "1.6.1",
"web3-core": "1.6.1"
},
"devDependencies": {
"@hyperledger/cactus-test-geth-ledger": "2.0.0-alpha.2",
"@hyperledger/cactus-test-tooling": "2.0.0-alpha.2",
"@types/body-parser": "1.19.4",
"@types/crypto-js": "4.0.1",
"@types/express": "4.17.19",
Expand Down
70 changes: 70 additions & 0 deletions packages/cactus-plugin-bungee-hermes/src/main/json/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,34 @@
"type": "string",
"example": "strategy-fabric"
}
},
"VerifyMerkleRootRequest":{
"type": "object",
"description": "Set of transaction or state proofs and merkle tree root for verification",
"properties": {
"input":{
"nullable": false,
"type": "array",
"items":{
"type": "string",
"example": "transactionProof stringified"
}
},
"root":{
"nullable": false,
"type": "string"
}
}
},
"VerifyMerkleRootResponse": {
"type": "object",
"description": "true or false, wether input matched provided root",
"properties": {
"result":{
"type": "boolean",
"example": "true"
}
}
}
}
},
Expand Down Expand Up @@ -216,6 +244,48 @@
}
}
}
},

"/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root": {
"get": {
"x-hyperledger-cacti": {
"http": {
"verbLowerCase": "get",
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root"
}
},
"operationId": "verifyMerkleRoot",
"summary": "Checks validity of merkle tree root given an input",
"description": "",
"parameters": [],
"requestBody": {
"required": true,
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VerifyMerkleRootRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VerifyMerkleRootResponse"
},
"example": {"result": true}
}
}
},
"404": {
"description": "Could not complete request."
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ src/main/kotlin/org/openapitools/client/models/CreateViewRequest.kt
src/main/kotlin/org/openapitools/client/models/CreateViewRequestNetworkDetails.kt
src/main/kotlin/org/openapitools/client/models/CreateViewResponse.kt
src/main/kotlin/org/openapitools/client/models/GetPublicKeyResponse.kt
src/main/kotlin/org/openapitools/client/models/VerifyMerkleRootRequest.kt
src/main/kotlin/org/openapitools/client/models/VerifyMerkleRootResponse.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Class | Method | HTTP request | Description
*DefaultApi* | [**createViewV1**](docs/DefaultApi.md#createviewv1) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/create-view | Creates a Blockchain View.
*DefaultApi* | [**getAvailableStrategies**](docs/DefaultApi.md#getavailablestrategies) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-available-strategies | Queries plugin's available strategies for ledger capture
*DefaultApi* | [**getPublicKey**](docs/DefaultApi.md#getpublickey) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/get-public-key | Queries plugin's public key
*DefaultApi* | [**verifyMerkleRoot**](docs/DefaultApi.md#verifymerkleroot) | **GET** /api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root | Checks validity of merkle tree root given an input


<a id="documentation-for-models"></a>
Expand All @@ -56,6 +57,8 @@ Class | Method | HTTP request | Description
- [org.openapitools.client.models.CreateViewRequestNetworkDetails](docs/CreateViewRequestNetworkDetails.md)
- [org.openapitools.client.models.CreateViewResponse](docs/CreateViewResponse.md)
- [org.openapitools.client.models.GetPublicKeyResponse](docs/GetPublicKeyResponse.md)
- [org.openapitools.client.models.VerifyMerkleRootRequest](docs/VerifyMerkleRootRequest.md)
- [org.openapitools.client.models.VerifyMerkleRootResponse](docs/VerifyMerkleRootResponse.md)


<a id="documentation-for-authorization"></a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import okhttp3.HttpUrl
import org.openapitools.client.models.CreateViewRequest
import org.openapitools.client.models.CreateViewResponse
import org.openapitools.client.models.GetPublicKeyResponse
import org.openapitools.client.models.VerifyMerkleRootRequest
import org.openapitools.client.models.VerifyMerkleRootResponse

import com.squareup.moshi.Json

Expand Down Expand Up @@ -255,6 +257,78 @@ class DefaultApi(basePath: kotlin.String = defaultBasePath, client: OkHttpClient
)
}

/**
* Checks validity of merkle tree root given an input
*
* @param verifyMerkleRootRequest
* @return VerifyMerkleRootResponse
* @throws IllegalStateException If the request is not correctly configured
* @throws IOException Rethrows the OkHttp execute method exception
* @throws UnsupportedOperationException If the API returns an informational or redirection response
* @throws ClientException If the API returns a client error response
* @throws ServerException If the API returns a server error response
*/
@Suppress("UNCHECKED_CAST")
@Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class)
fun verifyMerkleRoot(verifyMerkleRootRequest: VerifyMerkleRootRequest) : VerifyMerkleRootResponse {
val localVarResponse = verifyMerkleRootWithHttpInfo(verifyMerkleRootRequest = verifyMerkleRootRequest)

return when (localVarResponse.responseType) {
ResponseType.Success -> (localVarResponse as Success<*>).data as VerifyMerkleRootResponse
ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
ResponseType.ClientError -> {
val localVarError = localVarResponse as ClientError<*>
throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
}
ResponseType.ServerError -> {
val localVarError = localVarResponse as ServerError<*>
throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
}
}
}

/**
* Checks validity of merkle tree root given an input
*
* @param verifyMerkleRootRequest
* @return ApiResponse<VerifyMerkleRootResponse?>
* @throws IllegalStateException If the request is not correctly configured
* @throws IOException Rethrows the OkHttp execute method exception
*/
@Suppress("UNCHECKED_CAST")
@Throws(IllegalStateException::class, IOException::class)
fun verifyMerkleRootWithHttpInfo(verifyMerkleRootRequest: VerifyMerkleRootRequest) : ApiResponse<VerifyMerkleRootResponse?> {
val localVariableConfig = verifyMerkleRootRequestConfig(verifyMerkleRootRequest = verifyMerkleRootRequest)

return request<VerifyMerkleRootRequest, VerifyMerkleRootResponse>(
localVariableConfig
)
}

/**
* To obtain the request config of the operation verifyMerkleRoot
*
* @param verifyMerkleRootRequest
* @return RequestConfig
*/
fun verifyMerkleRootRequestConfig(verifyMerkleRootRequest: VerifyMerkleRootRequest) : RequestConfig<VerifyMerkleRootRequest> {
val localVariableBody = verifyMerkleRootRequest
val localVariableQuery: MultiValueMap = mutableMapOf()
val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
localVariableHeaders["Content-Type"] = "application/json"
localVariableHeaders["Accept"] = "application/json"

return RequestConfig(
method = RequestMethod.GET,
path = "/api/v1/plugins/@hyperledger/cactus-plugin-bungee-hermes/verify-merkle-root",
query = localVariableQuery,
headers = localVariableHeaders,
requiresAuthentication = false,
body = localVariableBody
)
}


private fun encodeURIComponent(uriComponent: kotlin.String): kotlin.String =
HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
*
* Please note:
* This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* Do not edit this file manually.
*
*/

@file:Suppress(
"ArrayInDataClass",
"EnumEntryName",
"RemoveRedundantQualifierName",
"UnusedImport"
)

package org.openapitools.client.models


import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

/**
* Set of transaction or state proofs and merkle tree root for verification
*
* @param input
* @param root
*/


data class VerifyMerkleRootRequest (

@Json(name = "input")
val input: kotlin.collections.List<kotlin.String>? = null,

@Json(name = "root")
val root: kotlin.String? = null

)

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
*
* Please note:
* This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* Do not edit this file manually.
*
*/

@file:Suppress(
"ArrayInDataClass",
"EnumEntryName",
"RemoveRedundantQualifierName",
"UnusedImport"
)

package org.openapitools.client.models


import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

/**
* true or false, wether input matched provided root
*
* @param result
*/


data class VerifyMerkleRootResponse (

@Json(name = "result")
val result: kotlin.Boolean? = null

)

Loading

0 comments on commit 103bf8c

Please sign in to comment.