Skip to content

Commit 54d8d99

Browse files
Merge branch 'feat/integrate-bg-router' into chore/introduce-submodule
* feat/integrate-bg-router: Update E2E_FEATURE_LIST.md [IBC] Implement ICS-23 CommitmentProof verification for the SMT (#845) [Utility] trustless relays servicer token validation (#803)
2 parents 8a3155b + bf96542 commit 54d8d99

28 files changed

Lines changed: 1222 additions & 82 deletions

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ test_persistence: ## Run all go unit tests in the Persistence module
411411
test_persistence_state_hash: ## Run all go unit tests in the Persistence module related to the state hash
412412
go test ${VERBOSE_TEST} -count=1 -tags=test -run TestStateHash ./persistence/...
413413

414+
.PHONY: test_servicer_relay
415+
test_servicer_relay: ## Run all go unit tests related to servicer relays
416+
go test ${VERBOSE_TEST} -count=1 -tags=test ./utility/servicer -run TestRelay
417+
414418
.PHONY: test_p2p
415419
test_p2p: ## Run all p2p related tests
416420
go test ${VERBOSE_TEST} -count=1 -tags=test ./p2p/...

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ module github.com/pokt-network/pocket
22

33
go 1.18
44

5+
// TECHDEBT: remove once upstream PR is merged (see: https://github.com/cosmos/ics23/pull/153)
6+
replace github.com/cosmos/ics23/go => github.com/h5law/ics23/go v0.0.0-20230619152251-56d948cafb83
7+
58
// TECHDEBT: remove once upstream PR is merged (see: https://github.com/regen-network/gocuke/pull/12)
69
replace github.com/regen-network/gocuke => github.com/pokt-network/gocuke v0.0.1
710

@@ -21,6 +24,7 @@ require (
2124

2225
require (
2326
github.com/benbjohnson/clock v1.3.0
27+
github.com/cosmos/ics23/go v0.10.0
2428
github.com/deepmap/oapi-codegen v1.12.4
2529
github.com/dgraph-io/badger/v3 v3.2103.2
2630
github.com/foxcpp/go-mockdns v1.0.0
@@ -37,7 +41,7 @@ require (
3741
github.com/manifoldco/promptui v0.9.0
3842
github.com/mitchellh/mapstructure v1.5.0
3943
github.com/multiformats/go-multiaddr v0.8.0
40-
github.com/pokt-network/smt v0.5.0
44+
github.com/pokt-network/smt v0.6.1
4145
github.com/quasilyte/go-ruleguard/dsl v0.3.21
4246
github.com/regen-network/gocuke v0.6.2
4347
github.com/rs/zerolog v1.27.0
@@ -87,6 +91,7 @@ require (
8791
github.com/cockroachdb/apd/v3 v3.1.0 // indirect
8892
github.com/containerd/cgroups v1.0.4 // indirect
8993
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
94+
github.com/cosmos/gogoproto v1.4.3 // indirect
9095
github.com/cucumber/common/messages/go/v19 v19.1.2 // indirect
9196
github.com/cucumber/gherkin/go/v26 v26.0.3 // indirect
9297
github.com/cucumber/messages/go/v21 v21.0.1 // indirect

go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
126126
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
127127
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
128128
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
129+
github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI=
130+
github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU=
129131
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
130132
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
131133
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -356,6 +358,8 @@ github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQ
356358
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
357359
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
358360
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
361+
github.com/h5law/ics23/go v0.0.0-20230619152251-56d948cafb83 h1:uG97IfYQttG5iVt/jHK2wnGZgKUxHUjnzAlWY6EDso8=
362+
github.com/h5law/ics23/go v0.0.0-20230619152251-56d948cafb83/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0=
359363
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
360364
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
361365
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -698,8 +702,8 @@ github.com/pokt-network/go-mockdns v0.0.1 h1:1Kb/kIFH6bNtY9F1bFhJyMRMCc7WyiqfGg0
698702
github.com/pokt-network/go-mockdns v0.0.1/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
699703
github.com/pokt-network/gocuke v0.0.1 h1:qJ/Ryf+hi5L6T9lsOZDNbiAclHkLlDio5/eVKQEYhgE=
700704
github.com/pokt-network/gocuke v0.0.1/go.mod h1:BowLKW4++696gTTU33teodtIhjjyaphEbhQT9D5Refw=
701-
github.com/pokt-network/smt v0.5.0 h1:rNTW3FB6i0pNMnafDqsBySgs0zpbjs0spP3p7ltVjAE=
702-
github.com/pokt-network/smt v0.5.0/go.mod h1:CWgC9UzDxXJNkL7TEADnJXutZVMYzK/+dmBb37RWkeQ=
705+
github.com/pokt-network/smt v0.6.1 h1:u5yTGNNND6edXv3vMQrAcjku1Ig4osehdu+EMYSXHUU=
706+
github.com/pokt-network/smt v0.6.1/go.mod h1:CWgC9UzDxXJNkL7TEADnJXutZVMYzK/+dmBb37RWkeQ=
703707
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
704708
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
705709
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=

ibc/docs/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- [Persistence](#persistence)
1010
- [Components](#components)
1111
- [ICS-24 Host Requirements](#ics-24-host-requirements)
12+
- [ICS-23 Vector Commitments](#ics-23-vector-commitments)
1213

1314
## Definitions
1415

@@ -106,6 +107,13 @@ The [IBC specification][ibc-spec] details numerous Interchain Standards (ICSs) t
106107

107108
See: [ICS-24](./ics24.md) for more details on the specifics of the ICS-24 implementation for Pocket.
108109

110+
### ICS-23 Vector Commitments
111+
112+
[ICS-23][ics23] defines the `CommitmentProof` type that is used to prove the membership/non-membership of a key-value pair in the IBC stores. As this type is serialisable the relayers can relay these proofs to a counterparty chain, as described above, for their ibc specific light client (of the source chain) to verify the proof and thus react accordingly. In order to implement ICS-23, the `cosmos/ics23` library was used, specifically its `CommitmentProof` type and its methods to verify the proofs in a way that does not require the tree itself.
113+
114+
See: [ICS-23](./ics23.md) for more details on the specifics of the ICS-23 implementation for Pocket.
115+
109116
[ibc-spec]: https://github.com/cosmos/ibc
110117
[ics24]: https://github.com/cosmos/ibc/blob/main/spec/core/ics-024-host-requirements/README.md
118+
[ics23]: https://github.com/cosmos/ibc/blob/main/spec/core/ics-023-vector-commitments/README.md
111119
[smt]: https://github.com/pokt-network/smt

ibc/docs/ics23.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# ICS-23 Vector Commitments <!-- omit in toc -->
2+
3+
- [Overview](#overview)
4+
- [Implementation](#implementation)
5+
- [Custom SMT `ProofSpec`](#custom-smt-proofspec)
6+
- [Converting `SparseMerkleProof` to `CommitmentProof`](#converting-sparsemerkleproof-to-commitmentproof)
7+
- [Proof Verification](#proof-verification)
8+
9+
## Overview
10+
11+
[ICS-23][ics23] defines the types and functions needed to verify membership of a key-value pair in a `CommitmentState`. As the Pocket IBC implementation uses the [SMT][smt] for its provable stores, this is referred to as the `CommitmentState` object. Cosmos has a library `cosmos/ics23` which is already SDK agnostic and defines many of the types necessary for ICS-23. This library was able to be used _mostly_ out of the box, with some minor adjustments detailed below.
12+
13+
## Implementation
14+
15+
The benefit of using `cosmos/ics23` over implementing similar types ourselves is twofold:
16+
17+
1. It is already SDK agnostic, so can be used by Pocket (a non-cosmos chain) without any issues or major changes.
18+
2. The functions defined for proof verification are decoupled from the underlying tree structure, meaning proof verification is tree agnostic.
19+
20+
However, there were some changes made specifically for Pocket's implementation of ICS-23.
21+
22+
See: [`cosmos/ics23` #152](https://github.com/cosmos/ics23/issues/152) and [`cosmos/ics23` #153](https://github.com/cosmos/ics23/pull/153ß) for the details of the changes made to allow for `ExclusionProof` verification.
23+
24+
### Custom SMT `ProofSpec`
25+
26+
The `ProofSpec` type in `cosmos/ics23` is used to define:
27+
28+
1. The steps needed to verify a proof
29+
2. The hash functions used
30+
3. Node prefixes
31+
4. Etc...
32+
33+
The `ProofSpec` is then passed into the verification functions in order to verify a proof instead of having to interact with the tree itself. This is useful as proofs must be verified via an (IBC) light client, and as such being able to verify a proof without reconstructing a tree is much more memory efficient.
34+
35+
As the SMT used by Pocket Network only stores hashed values by default, the IBC store uses the `WithValueHasher(nil)` option which stores the source value (as raw bytes) in the tree. The following `ProofSpec` was created to support this:
36+
37+
```go
38+
smtSpec *ics23.ProofSpec = &ics23.ProofSpec{
39+
LeafSpec: &ics23.LeafOp{
40+
Hash: ics23.HashOp_SHA256,
41+
PrehashKey: ics23.HashOp_SHA256,
42+
PrehashValue: ics23.HashOp_NO_HASH,
43+
Length: ics23.LengthOp_NO_PREFIX,
44+
Prefix: []byte{0},
45+
},
46+
InnerSpec: &ics23.InnerSpec{
47+
ChildOrder: []int32{0, 1},
48+
ChildSize: 32,
49+
MinPrefixLength: 1,
50+
MaxPrefixLength: 1,
51+
EmptyChild: make([]byte, 32),
52+
Hash: ics23.HashOp_SHA256,
53+
},
54+
MaxDepth: 256,
55+
PrehashKeyBeforeComparison: true,
56+
}
57+
```
58+
59+
The main difference from the `cosmos/ics23` `SmtSpec` object is that the `PrehashValue` field is set to not hash values before hashing the key-value pair.
60+
61+
### Converting `SparseMerkleProof` to `CommitmentProof`
62+
63+
In order to convert the proofs generated by the SMT into a serialisable proof used by `cosmos/ics23`, the `SideNodes` field of the `SparseMerkleProof` must be converted into a list of `InnerOp` types which define the order of the hashes. The order of the hashes is important as depending on whether the next hash is the left or right neighbour of the current hash, they will be hashed in a different order, ultimately creating a different root hash. This conversion allows the verification to produce the same root hash as the SMT would have produced when verifying the proof.
64+
65+
As `SparseMerkleProof` objects represent both inclusion and exclusion proofs as defined in the [JMT whitepaper][jmt]. The conversion step will convert the SMT proof into either an `ExistenceProof` or `ExclusionProof` as defined in `cosmos/ics23`.
66+
67+
### Proof Verification
68+
69+
Membership proofs are verified as follows:
70+
71+
1. Use the key-value pair to generate a leaf hash
72+
2. Hash the leaf with the `SideNodes` found in the `path` field of the `ExistenceProof` to generate the root hash
73+
3. Compare the root hash with the one provided and expect them to be identical
74+
75+
Non-membership proofs are verified as follows:
76+
77+
1. If the `ActualValueHash` field in the `ExclusionProof` is the SMT's placeholder value (`[32]byte`, i.e. the key is not set in the tree), then use the placeholder value as the leaf node hash and skip to step 3 below
78+
2. If the `ActualValueHash` field is not the placeholder value, then use the `ActualPath` and `ActualValueHash` fields (provided via `NonMembershipLeafData`) to generate the leaf node hash.
79+
- **IMPORTANT**: DO NOT hash these values before hashing the node as they are populated from the SMT proof's `NonMembershipLeafData` field and thus are already hashed
80+
3. Hash the leaf node hash with the `SideNodes` found in the `Path` field of the `ExclusionProof` to generate the root hash
81+
4. Compare the root hash with the one provided
82+
- if `computedRootHash == providedRootHash`
83+
- `key` not in tree -> `Proof` is valid -> exclusion QED
84+
- if `computedRootHash != providedRootHash`
85+
- `key` is in tree -> `Proof` is invalid -> exclusion QED
86+
87+
```mermaid
88+
flowchart TD
89+
I["Proof,Key"]
90+
NMD{"proof.NonMembershipLeafData == nil ?"}
91+
KP1["actualPath = sha256(key) \n actualValue = placeholder\ncurrentHash = [32]byte"]
92+
KP2["actualPath = ProvidedKeyHash \n actualValue = ProvidedValueHash\ncurrentHash = sha256([]byte{0}+actualPath+actualValueHash)"]
93+
C["nextHash = sha256(currentHash+sideNodeHash)"]
94+
Compare{"ComputedRootHash == ProvidedRootHash ?"}
95+
EV["Exclusion Prove VALID"]
96+
EI["Exclusion Prove INVALID"]
97+
98+
I --> NMD
99+
NMD -- Yes --> KP1
100+
NMD -- No --> KP2
101+
102+
KP1 -- CurrentHash --> C
103+
KP2 -- CurrentHash --> C
104+
105+
C -- while NextSideNode != nil --> C
106+
107+
C -- ComputedRootHash --> Compare
108+
Compare -- Yes --> EV
109+
Compare -- No --> EI
110+
```
111+
112+
The full implementation of this logic can be found [here](../store/proofs_ics23.go) as well as in the `cosmos/ics23` [library](https://github.com/h5law/ics23/blob/56d948cafb83ded78dc4b9de3c8b04582734851a/go/proof.go#L171).
113+
114+
[ics23]: https://github.com/cosmos/ibc/blob/main/spec/core/ics-023-vector-commitments/README.md
115+
[smt]: https://github.com/pokt-network/smt
116+
[jmt]: https://developers.diem.com/papers/jellyfish-merkle-tree/2021-01-14.pdf

ibc/store/proofs_ics23.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package store
2+
3+
import (
4+
"crypto/sha256"
5+
6+
ics23 "github.com/cosmos/ics23/go"
7+
coreTypes "github.com/pokt-network/pocket/shared/core/types"
8+
"github.com/pokt-network/smt"
9+
)
10+
11+
// position refers to whether the node is either the left or right child of its parent
12+
// for the binary SMT
13+
// Ref: https://github.com/pokt-network/smt/blob/main/types.go
14+
const (
15+
left int = iota // 0
16+
right // 1
17+
hashSize = 32
18+
)
19+
20+
var (
21+
// Custom SMT spec as the store does not hash values
22+
smtSpec *ics23.ProofSpec = &ics23.ProofSpec{
23+
LeafSpec: &ics23.LeafOp{
24+
Hash: ics23.HashOp_SHA256,
25+
PrehashKey: ics23.HashOp_SHA256,
26+
PrehashValue: ics23.HashOp_NO_HASH,
27+
Length: ics23.LengthOp_NO_PREFIX,
28+
Prefix: []byte{0},
29+
},
30+
InnerSpec: &ics23.InnerSpec{
31+
ChildOrder: []int32{0, 1},
32+
ChildSize: hashSize,
33+
MinPrefixLength: 1,
34+
MaxPrefixLength: 1,
35+
EmptyChild: make([]byte, hashSize),
36+
Hash: ics23.HashOp_SHA256,
37+
},
38+
MaxDepth: 256,
39+
PrehashKeyBeforeComparison: true,
40+
}
41+
innerPrefix = []byte{1}
42+
43+
// defaultValue is the default placeholder value in a SparseMerkleTree
44+
defaultValue = make([]byte, hashSize)
45+
)
46+
47+
// VerifyMembership verifies the CommitmentProof provided, checking whether it produces the same
48+
// root as the one given. If it does, the key-value pair is a member of the tree
49+
func VerifyMembership(root ics23.CommitmentRoot, proof *ics23.CommitmentProof, key, value []byte) bool {
50+
// verify the proof
51+
return ics23.VerifyMembership(smtSpec, root, proof, key, value)
52+
}
53+
54+
// VerifyNonMembership verifies the CommitmentProof provided, checking whether it produces the same
55+
// root as the one given. If it does, the key-value pair is not a member of the tree as the proof's
56+
// value is either the default nil value for the SMT or an unrelated value at the path
57+
func VerifyNonMembership(root ics23.CommitmentRoot, proof *ics23.CommitmentProof, key []byte) bool {
58+
// verify the proof
59+
return ics23.VerifyNonMembership(smtSpec, root, proof, key)
60+
}
61+
62+
// createMembershipProof generates a CommitmentProof object verifying the membership of a key-value pair
63+
// in the SMT provided
64+
func createMembershipProof(tree *smt.SMT, key, value []byte) (*ics23.CommitmentProof, error) {
65+
proof, err := tree.Prove(key)
66+
if err != nil {
67+
return nil, coreTypes.ErrCreatingProof(err)
68+
}
69+
return convertSMPToExistenceProof(proof, key, value), nil
70+
}
71+
72+
// createNonMembershipProof generates a CommitmentProof object verifying the membership of an unrealted key at the given key in the SMT provided
73+
func createNonMembershipProof(tree *smt.SMT, key []byte) (*ics23.CommitmentProof, error) {
74+
proof, err := tree.Prove(key)
75+
if err != nil {
76+
return nil, coreTypes.ErrCreatingProof(err)
77+
}
78+
79+
return convertSMPToExclusionProof(proof, key), nil
80+
}
81+
82+
// convertSMPToExistenceProof converts a SparseMerkleProof to an ics23
83+
// ExistenceProof to verify membership of an element
84+
func convertSMPToExistenceProof(proof *smt.SparseMerkleProof, key, value []byte) *ics23.CommitmentProof {
85+
path := sha256.Sum256(key)
86+
steps := convertSideNodesToSteps(proof.SideNodes, path[:])
87+
return &ics23.CommitmentProof{
88+
Proof: &ics23.CommitmentProof_Exist{
89+
Exist: &ics23.ExistenceProof{
90+
Key: key,
91+
Value: value,
92+
Leaf: smtSpec.LeafSpec,
93+
Path: steps,
94+
},
95+
},
96+
}
97+
}
98+
99+
// convertSMPToExclusionProof converts a SparseMerkleProof to an ics23
100+
// ExclusionProof to verify non-membership of an element
101+
func convertSMPToExclusionProof(proof *smt.SparseMerkleProof, key []byte) *ics23.CommitmentProof {
102+
path := sha256.Sum256(key)
103+
steps := convertSideNodesToSteps(proof.SideNodes, path[:])
104+
leaf := &ics23.LeafOp{
105+
Hash: ics23.HashOp_SHA256,
106+
// Do not re-hash already hashed fields from NonMembershipLeafData
107+
PrehashKey: ics23.HashOp_NO_HASH,
108+
PrehashValue: ics23.HashOp_NO_HASH,
109+
Length: ics23.LengthOp_NO_PREFIX,
110+
Prefix: []byte{0},
111+
}
112+
actualPath := path[:]
113+
actualValue := defaultValue
114+
if proof.NonMembershipLeafData != nil {
115+
actualPath = proof.NonMembershipLeafData[1 : 1+hashSize] // len(prefix): len(prefix) + hashSize
116+
actualValue = proof.NonMembershipLeafData[1+hashSize:]
117+
}
118+
return &ics23.CommitmentProof{
119+
Proof: &ics23.CommitmentProof_Exclusion{
120+
Exclusion: &ics23.ExclusionProof{
121+
Key: key,
122+
ActualPath: actualPath,
123+
ActualValueHash: actualValue,
124+
Leaf: leaf,
125+
Path: steps,
126+
},
127+
},
128+
}
129+
}
130+
131+
// convertSideNodesToSteps converts the SideNodes field in the SparseMerkleProof
132+
// into a list of InnerOps for the ics23 CommitmentProof
133+
func convertSideNodesToSteps(sideNodes [][]byte, path []byte) []*ics23.InnerOp {
134+
steps := make([]*ics23.InnerOp, 0, len(sideNodes))
135+
for i := 0; i < len(sideNodes); i++ {
136+
var prefix, suffix []byte
137+
prefix = append(prefix, innerPrefix...)
138+
if isLeft(path, len(sideNodes)-1-i) {
139+
// path is on the left so sidenode must be on the right
140+
suffix = make([]byte, 0, len(sideNodes[i]))
141+
suffix = append(suffix, sideNodes[i]...)
142+
} else {
143+
// path is on the right so sidenode must be on the left
144+
prefix = append(prefix, sideNodes[i]...)
145+
}
146+
op := &ics23.InnerOp{
147+
Hash: ics23.HashOp_SHA256,
148+
Prefix: prefix,
149+
Suffix: suffix,
150+
}
151+
steps = append(steps, op)
152+
}
153+
return steps
154+
}
155+
156+
// isLeft returns true is the i-th bit of path is a left child in the SMT
157+
func isLeft(path []byte, i int) bool {
158+
return smt.GetPathBit(path, i) == left
159+
}

0 commit comments

Comments
 (0)