Proof of Concept: Merkle proof provider service

This commit is contained in:
alrevuelta 2024-01-24 11:31:21 +01:00
parent 190d8e8e08
commit 8d243366c3
No known key found for this signature in database
GPG Key ID: F345C9F3CCDB886E
6 changed files with 162 additions and 35 deletions

View File

@ -1,10 +1,15 @@
package rest
import (
"context"
"encoding/hex"
"fmt"
"math/big"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/waku-org/go-waku/waku/v2/node"
"github.com/waku-org/go-zerokit-rln/rln"
)
type DebugService struct {
@ -20,8 +25,15 @@ type InfoReply struct {
ListenAddresses []string `json:"listenAddresses,omitempty"`
}
// Run as:
// ./build/waku --rest --rest-address=0.0.0.0 --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-client-address=wss://sepolia.infura.io/ws/v3/4576482c0f474483ac709755f2663b20 --rln-relay-eth-contract-address=0xF471d71E9b1455bBF4b85d475afb9BB0954A29c4
// Example usage (replace by your public commitment)
// curl http://localhost:8645/debug/v1/merkleProof/15506699537643273163469326218249028331014943998871371946527772121417127479348
const routeDebugInfoV1 = "/debug/v1/info"
const routeDebugVersionV1 = "/debug/v1/version"
const routeDebugGetMerkleProofV1 = "/debug/v1/merkleProof/{commitment}"
func NewDebugService(node *node.WakuNode, m *chi.Mux) *DebugService {
d := &DebugService{
@ -31,6 +43,7 @@ func NewDebugService(node *node.WakuNode, m *chi.Mux) *DebugService {
m.Get(routeDebugInfoV1, d.getV1Info)
m.Get(routeDebugVersionV1, d.getV1Version)
m.Get(routeDebugGetMerkleProofV1, d.getV1MerkleProof)
return d
}
@ -50,3 +63,102 @@ func (d *DebugService) getV1Version(w http.ResponseWriter, req *http.Request) {
response := VersionResponse(node.GetVersionInfo().String())
writeErrOrResponse(w, nil, response)
}
type MerkleProofResponse struct {
MerkleRoot string `json:"root"`
MerkePathElements []string `json:"pathElements"`
MerkePathIndexes []uint `json:"pathIndexes"`
LeafIndex uint64 `json:"leafIndex"`
CommitmentId string `json:"commitmentId"`
}
func (d *DebugService) getV1MerkleProof(w http.ResponseWriter, req *http.Request) {
commitmentReq := chi.URLParam(req, "commitment")
if commitmentReq == "" {
writeErrResponse(w, nil, fmt.Errorf("commitment is empty"), http.StatusBadRequest)
return
}
commitmentReqBig := new(big.Int)
commitmentReqBig, ok := commitmentReqBig.SetString(commitmentReq, 10)
if !ok {
writeErrResponse(w, nil, fmt.Errorf("commitment is not a number"), http.StatusBadRequest)
return
}
fmt.Println("commitmentReq: ", commitmentReq)
// Some dirty way to access rln and group manager
rlnInstance := d.node.RLNInstance
groupManager := d.node.GroupManager
ready, err := groupManager.IsReady(context.Background())
if err != nil {
writeErrResponse(w, nil, fmt.Errorf("could not check if service was ready"), http.StatusBadRequest)
return
}
if !ready {
writeErrResponse(w, nil, fmt.Errorf("service is not ready"), http.StatusBadRequest)
return
}
found := false
membershipIndex := uint(0)
for leafIdx := uint(0); leafIdx < rlnInstance.LeavesSet(); leafIdx++ {
leaf, err := rlnInstance.GetLeaf(leafIdx)
if err != nil {
writeErrResponse(w, nil, fmt.Errorf("could not get leaf"), http.StatusBadRequest)
return
}
leafBig := rln.Bytes32ToBigInt(leaf)
if leafBig.Cmp(commitmentReqBig) == 0 {
found = true
membershipIndex = leafIdx
break
}
}
if !found {
writeErrResponse(w, nil, fmt.Errorf("commitment not found: %s", commitmentReqBig.String()), http.StatusBadRequest)
return
}
fmt.Println("membershipIndex: ", membershipIndex)
merkleProof, err := rlnInstance.GetMerkleProof(rln.MembershipIndex(membershipIndex))
if err != nil {
writeErrOrResponse(w, err, nil)
return
}
elementsStr := make([]string, 0)
indexesStr := make([]uint, 0)
for _, path := range merkleProof.PathElements {
fmt.Println("path: ", path)
elementsStr = append(elementsStr, "0x"+hex.EncodeToString(path[:]))
}
for _, index := range merkleProof.PathIndexes {
indexesStr = append(indexesStr, uint(index))
}
// TODO: Not nide to get proof and root in different non atomic calls. In an unlikely edge case the tree can change between the two calls
// if a membership is added. Proof of concept by now.
merkleRoot, err := rlnInstance.GetMerkleRoot()
if err != nil {
writeErrOrResponse(w, err, nil)
return
}
fmt.Println("merkleRoot: ", merkleRoot)
writeErrOrResponse(w, nil, MerkleProofResponse{
MerkleRoot: "0x" + hex.EncodeToString(merkleRoot[:]),
MerkePathElements: elementsStr,
MerkePathIndexes: indexesStr,
LeafIndex: uint64(membershipIndex),
CommitmentId: commitmentReqBig.String(),
})
}

8
go.mod
View File

@ -41,7 +41,7 @@ require (
github.com/libp2p/go-libp2p-mplex v0.9.0
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0
github.com/waku-org/go-noise v0.0.4
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240116153345-7e086e8f8930
github.com/wk8/go-ordered-map v1.0.0
)
@ -73,9 +73,9 @@ require (
github.com/rjeczalik/notify v0.9.3 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/status-im/status-go/extkeys v1.1.2 // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20230916171518-2a77c3734dd1 // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240116134931-a8b8c6ab4b80 // indirect
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240116135046-2875fec12afc // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/fx v1.20.1 // indirect
go.uber.org/mock v0.3.0 // indirect

16
go.sum
View File

@ -1540,14 +1540,14 @@ github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0 h1:R
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0/go.mod h1:EhZP9fee0DYjKH/IOQvoNSy1tSHp2iZadsHGphcAJgY=
github.com/waku-org/go-noise v0.0.4 h1:ZfQDcCw8pazm89EBl5SXY7GGAnzDQb9AHFXlw3Ktbvk=
github.com/waku-org/go-noise v0.0.4/go.mod h1:+PWRfs2eSOVwKrPcQlfhwDngSh3faL/1QoxvoqggEKc=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 h1:Sd7QD/1Yo2o2M1MY49F8Zr4KNBPUEK5cz5HoXQVJbrs=
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20230916171518-2a77c3734dd1 h1:4HSdWMFMufpRo3ECTX6BrvA+VzKhXZf7mS0rTa5cCWU=
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20230916171518-2a77c3734dd1/go.mod h1:+LeEYoW5/uBUTVjtBGLEVCUe9mOYAlu5ZPkIxLOSr5Y=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240116153345-7e086e8f8930 h1:R9s+zA28gCX3e6b3iZKwLX7oRh3G15r1eSuOglSwUfk=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240116153345-7e086e8f8930/go.mod h1:IOXLch4yJlN8WMf3S8kbGiZPMV1xYQ+xQ3D1yOGUAxg=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef h1:MAkZryAeRhiH3TKHRK2h+WztZI1VqfQ/oeXMIxKZNy0=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240116134931-a8b8c6ab4b80 h1:3KObRaYJnTI41U0reNBk7DYr5PVCTq8T9gJLXGfPfaY=
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240116134931-a8b8c6ab4b80/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240116135046-2875fec12afc h1:YjIgIrqlNVC+hXNy2ykYy3JvBKima64J9jXbKM/ULpw=
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240116135046-2875fec12afc/go.mod h1:+LeEYoW5/uBUTVjtBGLEVCUe9mOYAlu5ZPkIxLOSr5Y=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=

View File

@ -42,10 +42,12 @@ import (
"github.com/waku-org/go-waku/waku/v2/protocol/pb"
"github.com/waku-org/go-waku/waku/v2/protocol/peer_exchange"
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager/dynamic"
"github.com/waku-org/go-waku/waku/v2/protocol/store"
"github.com/waku-org/go-waku/waku/v2/rendezvous"
"github.com/waku-org/go-waku/waku/v2/service"
"github.com/waku-org/go-waku/waku/v2/timesource"
r "github.com/waku-org/go-zerokit-rln/rln"
"github.com/waku-org/go-waku/waku/v2/utils"
)
@ -84,11 +86,14 @@ type RLNRelay interface {
}
type WakuNode struct {
host host.Host
opts *WakuNodeParameters
log *zap.Logger
timesource timesource.Timesource
metrics Metrics
// TODO: quick and dirty way to expose
RLNInstance *r.RLN
GroupManager *dynamic.DynamicGroupManager
host host.Host
opts *WakuNodeParameters
log *zap.Logger
timesource timesource.Timesource
metrics Metrics
peerstore peerstore.Peerstore
peerConnector *peermanager.PeerConnectionStrategy
@ -286,10 +291,12 @@ func New(opts ...WakuNodeOption) (*WakuNode, error) {
relay.WithMaxMsgSize(w.opts.maxMsgSizeBytes))
if w.opts.enableRelay {
err = w.setupRLNRelay()
err, rlnInstance, groupManager := w.setupRLNRelay()
if err != nil {
return nil, err
}
w.RLNInstance = rlnInstance
w.GroupManager = groupManager
}
w.opts.legacyFilterOpts = append(w.opts.legacyFilterOpts, legacy_filter.WithPeerManager(w.peermanager))

View File

@ -21,22 +21,22 @@ func (w *WakuNode) RLNRelay() RLNRelay {
return w.rlnRelay
}
func (w *WakuNode) setupRLNRelay() error {
func (w *WakuNode) setupRLNRelay() (error, *r.RLN, *dynamic.DynamicGroupManager) {
var err error
if !w.opts.enableRLN {
return nil
return nil, nil, nil
}
if !w.opts.enableRelay {
return errors.New("rln requires relay")
return errors.New("rln requires relay"), nil, nil
}
var groupManager group_manager.GroupManager
rlnInstance, rootTracker, err := rln.GetRLNInstanceAndRootTracker(w.opts.rlnTreePath)
if err != nil {
return err
return err, nil, nil
}
if !w.opts.rlnRelayDynamic {
w.log.Info("setting up waku-rln-relay in off-chain mode")
@ -49,12 +49,12 @@ func (w *WakuNode) setupRLNRelay() error {
// set up rln relay inputs
groupKeys, idCredential, err := static.Setup(index)
if err != nil {
return err
return err, nil, nil
}
groupManager, err = static.NewStaticGroupManager(groupKeys, idCredential, index, rlnInstance, rootTracker, w.log)
if err != nil {
return err
return err, nil, nil
}
} else {
w.log.Info("setting up waku-rln-relay in on-chain mode")
@ -63,7 +63,7 @@ func (w *WakuNode) setupRLNRelay() error {
if w.opts.keystorePath != "" {
appKeystore, err = keystore.New(w.opts.keystorePath, dynamic.RLNAppInfo, w.log)
if err != nil {
return err
return err, nil, nil
}
}
@ -79,7 +79,7 @@ func (w *WakuNode) setupRLNRelay() error {
w.log,
)
if err != nil {
return err
return err, nil, nil
}
}
@ -93,7 +93,7 @@ func (w *WakuNode) setupRLNRelay() error {
w.Relay().RegisterDefaultValidator(w.rlnRelay.Validator(w.opts.rlnSpamHandler))
return nil
return nil, rlnInstance, groupManager.(*dynamic.DynamicGroupManager)
}
func (w *WakuNode) startRlnRelay(ctx context.Context) error {

View File

@ -52,10 +52,10 @@ func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered,
toRemoveTable := om.New()
toInsertTable := om.New()
if gm.lastBlockProcessed == 0 {
gm.lastBlockProcessed = latestProcessBlock
}
lastBlockProcessed := gm.lastBlockProcessed
//if gm.lastBlockProcessed == 0 {
// gm.lastBlockProcessed = latestProcessBlock
//}
//lastBlockProcessed := gm.lastBlockProcessed
for _, event := range events {
if event.Raw.Removed {
var indexes []uint
@ -74,9 +74,9 @@ func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered,
eventsPerBlock = append(eventsPerBlock, event)
toInsertTable.Set(event.Raw.BlockNumber, eventsPerBlock)
if event.Raw.BlockNumber > lastBlockProcessed {
lastBlockProcessed = event.Raw.BlockNumber
}
//if event.Raw.BlockNumber > lastBlockProcessed {
// lastBlockProcessed = event.Raw.BlockNumber
//}
}
}
@ -90,7 +90,9 @@ func (gm *DynamicGroupManager) handler(events []*contracts.RLNMemberRegistered,
return err
}
gm.lastBlockProcessed = lastBlockProcessed
// TODO: Commented code above is a bug I think. lastBlockProcessed was not being
// updated properly.
gm.lastBlockProcessed = latestProcessBlock
err = gm.SetMetadata(RLNMetadata{
LastProcessedBlock: gm.lastBlockProcessed,
ChainID: gm.web3Config.ChainID,
@ -310,6 +312,8 @@ func (gm *DynamicGroupManager) IsReady(ctx context.Context) (bool, error) {
return false, fmt.Errorf("could not retrieve latest block: %w", err)
}
fmt.Println("latestBlockNumber: ", latestBlockNumber, " gm.lastBlockProcessed: ", gm.lastBlockProcessed)
gm.lastBlockProcessedMutex.RLock()
allBlocksProcessed := gm.lastBlockProcessed >= latestBlockNumber
gm.lastBlockProcessedMutex.RUnlock()
@ -325,3 +329,7 @@ func (gm *DynamicGroupManager) IsReady(ctx context.Context) (bool, error) {
return syncProgress == nil, nil // syncProgress only has a value while node is syncing
}
func GetRLN(gm *DynamicGroupManager) *rln.RLN {
return gm.rln
}