2023-08-18 09:59:37 -04:00
|
|
|
package dynamic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
2023-08-23 10:45:30 -04:00
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2023-09-01 11:04:49 -04:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager"
|
2023-08-18 09:59:37 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// RLNMetadata persists attributes in the RLN database
|
|
|
|
type RLNMetadata struct {
|
|
|
|
LastProcessedBlock uint64
|
2023-08-23 10:45:30 -04:00
|
|
|
ChainID *big.Int
|
|
|
|
ContractAddress common.Address
|
2023-09-01 11:04:49 -04:00
|
|
|
ValidRootsPerBlock []group_manager.RootsPerBlock
|
2023-08-18 09:59:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Serialize converts a RLNMetadata into a binary format expected by zerokit's RLN
|
|
|
|
func (r RLNMetadata) Serialize() []byte {
|
2023-08-23 10:45:30 -04:00
|
|
|
chainID := r.ChainID
|
|
|
|
if chainID == nil {
|
|
|
|
chainID = big.NewInt(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
var result []byte
|
|
|
|
result = binary.LittleEndian.AppendUint64(result, r.LastProcessedBlock)
|
|
|
|
result = binary.LittleEndian.AppendUint64(result, chainID.Uint64())
|
|
|
|
result = append(result, r.ContractAddress.Bytes()...)
|
2023-09-01 11:04:49 -04:00
|
|
|
result = binary.LittleEndian.AppendUint64(result, uint64(len(r.ValidRootsPerBlock)))
|
|
|
|
for _, v := range r.ValidRootsPerBlock {
|
|
|
|
result = append(result, v.Root[:]...)
|
|
|
|
result = binary.LittleEndian.AppendUint64(result, v.BlockNumber)
|
|
|
|
}
|
|
|
|
|
2023-08-18 09:59:37 -04:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2023-08-23 10:45:30 -04:00
|
|
|
const lastProcessedBlockOffset = 0
|
|
|
|
const chainIDOffset = lastProcessedBlockOffset + 8
|
|
|
|
const contractAddressOffset = chainIDOffset + 8
|
2023-09-01 11:04:49 -04:00
|
|
|
const validRootsLenOffset = contractAddressOffset + 20
|
|
|
|
const validRootsValOffset = validRootsLenOffset + 8
|
|
|
|
const metadataByteLen = 8 + 8 + 20 + 8 // uint64 + uint64 + ethAddress + uint64
|
2023-08-23 10:45:30 -04:00
|
|
|
|
2023-08-18 09:59:37 -04:00
|
|
|
// DeserializeMetadata converts a byte slice into a RLNMetadata instance
|
|
|
|
func DeserializeMetadata(b []byte) (RLNMetadata, error) {
|
2023-09-01 11:04:49 -04:00
|
|
|
if len(b) < metadataByteLen {
|
2023-08-18 09:59:37 -04:00
|
|
|
return RLNMetadata{}, errors.New("wrong size")
|
|
|
|
}
|
2023-08-23 10:45:30 -04:00
|
|
|
|
2023-09-01 11:04:49 -04:00
|
|
|
validRootLen := binary.LittleEndian.Uint64(b[validRootsLenOffset:validRootsValOffset])
|
|
|
|
if len(b) < int(metadataByteLen+validRootLen*(32+8)) { // len of a merkle node and len of a uint64 for the block number
|
|
|
|
return RLNMetadata{}, errors.New("wrong size")
|
|
|
|
}
|
|
|
|
|
|
|
|
validRoots := make([]group_manager.RootsPerBlock, 0, validRootLen)
|
|
|
|
for i := 0; i < int(validRootLen); i++ {
|
|
|
|
rootOffset := validRootsValOffset + (i * (32 + 8))
|
|
|
|
blockOffset := rootOffset + 32
|
|
|
|
root := group_manager.RootsPerBlock{
|
|
|
|
BlockNumber: binary.LittleEndian.Uint64(b[blockOffset : blockOffset+8]),
|
|
|
|
}
|
|
|
|
copy(root.Root[:], b[rootOffset:blockOffset])
|
|
|
|
validRoots = append(validRoots, root)
|
|
|
|
}
|
|
|
|
|
2023-08-18 09:59:37 -04:00
|
|
|
return RLNMetadata{
|
2023-08-23 10:45:30 -04:00
|
|
|
LastProcessedBlock: binary.LittleEndian.Uint64(b[lastProcessedBlockOffset:chainIDOffset]),
|
|
|
|
ChainID: new(big.Int).SetUint64(binary.LittleEndian.Uint64(b[chainIDOffset:contractAddressOffset])),
|
2023-09-01 11:04:49 -04:00
|
|
|
ContractAddress: common.BytesToAddress(b[contractAddressOffset:validRootsLenOffset]),
|
|
|
|
ValidRootsPerBlock: validRoots,
|
2023-08-18 09:59:37 -04:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetMetadata stores some metadata into the zerokit's RLN database
|
|
|
|
func (gm *DynamicGroupManager) SetMetadata(meta RLNMetadata) error {
|
|
|
|
b := meta.Serialize()
|
|
|
|
return gm.rln.SetMetadata(b)
|
|
|
|
}
|