diff --git a/Dockerfile.release b/Dockerfile.release index dd3a8b6..95fd410 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -62,6 +62,8 @@ LABEL org.opencontainers.image.source=$GIT_REPO LABEL org.opencontainers.image.ref.name=$GIT_BRANCH LABEL org.opencontainers.image.revision=$GIT_COMMIT +RUN apt-get update && apt-get install -y ca-certificates + COPY --from=build /opt/ceremonyclient/node/node /usr/local/bin COPY --from=build /opt/ceremonyclient/node/node.dgst /usr/local/bin COPY --from=build /opt/ceremonyclient/node/node.dgst.sig.* /usr/local/bin diff --git a/Dockerfile.source b/Dockerfile.source index 8b6956f..6f093c8 100644 --- a/Dockerfile.source +++ b/Dockerfile.source @@ -71,6 +71,8 @@ LABEL org.opencontainers.image.source=$GIT_REPO LABEL org.opencontainers.image.ref.name=$GIT_BRANCH LABEL org.opencontainers.image.revision=$GIT_COMMIT +RUN apt-get update && apt-get install -y ca-certificates + COPY --from=build /go/bin/node /usr/local/bin COPY --from=build /go/bin/grpcurl /usr/local/bin COPY --from=build /opt/ceremonyclient/client/qclient /usr/local/bin diff --git a/client/cmd/all.go b/client/cmd/all.go index 3f3cdb0..1a67b57 100644 --- a/client/cmd/all.go +++ b/client/cmd/all.go @@ -1,16 +1,270 @@ package cmd import ( + "bytes" + "context" + "encoding/binary" "fmt" + "os" + "strings" + "time" + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" "github.com/spf13/cobra" + "go.uber.org/zap" + "google.golang.org/grpc" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" ) var allCmd = &cobra.Command{ Use: "all", - Short: "Mints all available token rewards", + Short: "Mints all pre-2.0 rewards", + Run: func(cmd *cobra.Command, args []string) { - fmt.Println("command not yet available") + if len(args) != 0 { + fmt.Println("command has no arguments") + os.Exit(1) + } + + if !LightNode { + fmt.Println( + "mint all cannot be run unless node is not running. ensure your node " + + "is not running and your config.yml has grpc disabled", + ) + os.Exit(1) + } + + db := store.NewPebbleDB(NodeConfig.DB) + logger, _ := zap.NewProduction() + dataProofStore := store.NewPebbleDataProofStore(db, logger) + peerId := GetPeerIDFromConfig(NodeConfig) + privKey, err := GetPrivKeyFromConfig(NodeConfig) + if err != nil { + panic(err) + } + + pub, err := privKey.GetPublic().Raw() + if err != nil { + panic(err) + } + + pubSub := p2p.NewBlossomSub(NodeConfig.P2P, logger) + logger.Info("connecting to network") + time.Sleep(5 * time.Second) + + increment, _, _, err := dataProofStore.GetLatestDataTimeProof( + []byte(peerId), + ) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + logger.Info("could not find pre-2.0 proofs") + return + } + + panic(err) + } + + addrBI, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + panic(err) + } + + addr := addrBI.FillBytes(make([]byte, 32)) + + genesis := config.GetGenesis() + bpub, err := crypto.UnmarshalEd448PublicKey(genesis.Beacon) + if err != nil { + panic(err) + } + + bpeerId, err := peer.IDFromPublicKey(bpub) + if err != nil { + panic(errors.Wrap(err, "error getting peer id")) + } + + resume := make([]byte, 32) + cc, err := pubSub.GetDirectChannel([]byte(bpeerId), "worker") + if err != nil { + logger.Info( + "could not establish direct channel, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + for { + if cc == nil { + cc, err = pubSub.GetDirectChannel([]byte(bpeerId), "worker") + if err != nil { + logger.Info( + "could not establish direct channel, waiting...", + zap.Error(err), + ) + cc = nil + time.Sleep(10 * time.Second) + continue + } + } + + client := protobufs.NewDataServiceClient(cc) + + if bytes.Equal(resume, make([]byte, 32)) { + status, err := client.GetPreMidnightMintStatus( + context.Background(), + &protobufs.PreMidnightMintStatusRequest{ + Owner: addr, + }, + grpc.MaxCallSendMsgSize(1*1024*1024), + grpc.MaxCallRecvMsgSize(1*1024*1024), + ) + if err != nil || status == nil { + logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + cc.Close() + cc = nil + err = pubSub.Reconnect([]byte(peerId)) + if err != nil { + logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + continue + } + + resume = status.Address + + if status.Increment != 0 { + increment = status.Increment - 1 + } else if !bytes.Equal(status.Address, make([]byte, 32)) { + increment = 0 + } + } + + proofs := [][]byte{ + []byte("pre-dusk"), + resume, + } + + batchCount := 0 + // the cast is important, it underflows without: + for i := int(increment); i >= 0; i-- { + _, parallelism, input, output, err := dataProofStore.GetDataTimeProof( + []byte(peerId), + uint32(i), + ) + if err == nil { + p := []byte{} + p = binary.BigEndian.AppendUint32(p, uint32(i)) + p = binary.BigEndian.AppendUint32(p, parallelism) + p = binary.BigEndian.AppendUint64(p, uint64(len(input))) + p = append(p, input...) + p = binary.BigEndian.AppendUint64(p, uint64(len(output))) + p = append(p, output...) + + proofs = append(proofs, p) + } else { + logger.Error( + "could not find data time proof for peer and increment, stopping worker", + zap.String("peer_id", peerId.String()), + zap.Int("increment", i), + ) + cc.Close() + cc = nil + return + } + + batchCount++ + if batchCount == 200 || i == 0 { + logger.Info("publishing proof batch", zap.Int("increment", i)) + + payload := []byte("mint") + for _, i := range proofs { + payload = append(payload, i...) + } + sig, err := pubSub.SignMessage(payload) + if err != nil { + cc.Close() + panic(err) + } + + resp, err := client.HandlePreMidnightMint( + context.Background(), + &protobufs.MintCoinRequest{ + Proofs: proofs, + Signature: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: pub, + }, + Signature: sig, + }, + }, + grpc.MaxCallSendMsgSize(1*1024*1024), + grpc.MaxCallRecvMsgSize(1*1024*1024), + ) + + if err != nil { + if strings.Contains( + err.Error(), + application.ErrInvalidStateTransition.Error(), + ) && i == 0 { + resume = make([]byte, 32) + logger.Info("pre-midnight proofs submitted, returning") + cc.Close() + cc = nil + return + } + + logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + + resume = make([]byte, 32) + cc.Close() + cc = nil + time.Sleep(10 * time.Second) + err = pubSub.Reconnect([]byte(peerId)) + if err != nil { + logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + break + } + + resume = resp.Address + batchCount = 0 + proofs = [][]byte{ + []byte("pre-dusk"), + resume, + } + + if i == 0 { + logger.Info("pre-midnight proofs submitted, returning") + cc.Close() + cc = nil + return + } else { + increment = uint32(i) - 1 + } + + break + } + } + } }, } diff --git a/client/cmd/balance.go b/client/cmd/balance.go index 8ab6b68..ab1fc57 100644 --- a/client/cmd/balance.go +++ b/client/cmd/balance.go @@ -22,6 +22,16 @@ var balanceCmd = &cobra.Command{ client := protobufs.NewNodeServiceClient(conn) peerId := GetPeerIDFromConfig(NodeConfig) + privKey, err := GetPrivKeyFromConfig(NodeConfig) + if err != nil { + panic(err) + } + + pub, err := privKey.GetPublic().Raw() + if err != nil { + panic(err) + } + addr, err := poseidon.HashBytes([]byte(peerId)) if err != nil { panic(err) @@ -38,13 +48,42 @@ var balanceCmd = &cobra.Command{ panic(err) } - if info.OwnedTokens == nil { - panic("invalid response from RPC") - } tokens := new(big.Int).SetBytes(info.OwnedTokens) conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16) r := new(big.Rat).SetFrac(tokens, conversionFactor) - fmt.Println("Total balance:", r.FloatString(12), "QUIL") + + altAddr, err := poseidon.HashBytes([]byte(pub)) + if err != nil { + panic(err) + } + + altAddrBytes := altAddr.FillBytes(make([]byte, 32)) + info, err = client.GetTokenInfo( + context.Background(), + &protobufs.GetTokenInfoRequest{ + Address: altAddrBytes, + }, + ) + if err != nil { + panic(err) + } + + if info.OwnedTokens == nil { + panic("invalid response from RPC") + } + + tokens = new(big.Int).SetBytes(info.OwnedTokens) + r2 := new(big.Rat).SetFrac(tokens, conversionFactor) + fmt.Println("Total balance:", r.FloatString(12), fmt.Sprintf( + "QUIL (Account 0x%x)", + addrBytes, + )) + if r2.Cmp(big.NewRat(0, 1)) != 0 { + fmt.Println("Total balance:", r2.FloatString(12), fmt.Sprintf( + "QUIL (Account 0x%x)", + altAddrBytes, + )) + } }, } diff --git a/client/cmd/coins.go b/client/cmd/coins.go index 1dc60d2..5e85a49 100644 --- a/client/cmd/coins.go +++ b/client/cmd/coins.go @@ -2,13 +2,11 @@ package cmd import ( "context" - "encoding/hex" "fmt" "math/big" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/spf13/cobra" - "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) @@ -24,6 +22,16 @@ var coinsCmd = &cobra.Command{ client := protobufs.NewNodeServiceClient(conn) peerId := GetPeerIDFromConfig(NodeConfig) + privKey, err := GetPrivKeyFromConfig(NodeConfig) + if err != nil { + panic(err) + } + + pub, err := privKey.GetPublic().Raw() + if err != nil { + panic(err) + } + addr, err := poseidon.HashBytes([]byte(peerId)) if err != nil { panic(err) @@ -44,15 +52,43 @@ var coinsCmd = &cobra.Command{ panic("invalid response from RPC") } + altAddr, err := poseidon.HashBytes([]byte(pub)) + if err != nil { + panic(err) + } + + altAddrBytes := altAddr.FillBytes(make([]byte, 32)) + resp2, err := client.GetTokensByAccount( + context.Background(), + &protobufs.GetTokensByAccountRequest{ + Address: altAddrBytes, + }, + ) + if err != nil { + panic(err) + } + + if len(resp.Coins) != len(resp.FrameNumbers) { + panic("invalid response from RPC") + } + for i, coin := range resp.Coins { amount := new(big.Int).SetBytes(coin.Amount) conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16) r := new(big.Rat).SetFrac(amount, conversionFactor) - addr, err := token.GetAddressOfCoin(coin, resp.FrameNumbers[i]) - if err != nil { - panic(err) - } - fmt.Println(r.FloatString(12), "QUIL (Coin 0x", hex.EncodeToString(addr), ")") + fmt.Println( + r.FloatString(12), + fmt.Sprintf("QUIL (Coin 0x%x)", resp.Addresses[i]), + ) + } + for i, coin := range resp2.Coins { + amount := new(big.Int).SetBytes(coin.Amount) + conversionFactor, _ := new(big.Int).SetString("1DCD65000", 16) + r := new(big.Rat).SetFrac(amount, conversionFactor) + fmt.Println( + r.FloatString(12), + fmt.Sprintf("QUIL (Coin 0x%x)", resp.Addresses[i]), + ) } }, } diff --git a/client/cmd/root.go b/client/cmd/root.go index 8cf78ed..5b8b5e5 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -86,7 +86,7 @@ var rootCmd = &cobra.Command{ count++ } - if count < len(config.Signatories)/2+len(config.Signatories)%2 { + if count < ((len(config.Signatories)-4)/2)+((len(config.Signatories)-4)%2) { fmt.Printf("Quorum on signatures not met") os.Exit(1) } diff --git a/client/cmd/split.go b/client/cmd/split.go index 1f26a59..3def31f 100644 --- a/client/cmd/split.go +++ b/client/cmd/split.go @@ -48,7 +48,7 @@ var splitCmd = &cobra.Command{ fmt.Println("invalid amount") os.Exit(1) } - amount.Mul(decimal.NewFromBigInt(conversionFactor, 0)) + amount = amount.Mul(decimal.NewFromBigInt(conversionFactor, 0)) amountBytes := amount.BigInt().FillBytes(make([]byte, 32)) amounts = append(amounts, amountBytes) payload = append(payload, amountBytes...) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 9bd084c..51627c8 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -6,7 +6,7 @@ name: quilibrium services: node: # image: ${QUILIBRIUM_IMAGE_NAME:-quilibrium} - image: eth2dev/quilibrium:v2.0.0-p8-signed + image: eth2dev/quilibrium:v2.0.2-p3-signed container_name: "quil" restart: unless-stopped # command: ["--signature-check=false"] diff --git a/node/app/node.go b/node/app/node.go index ea0f13a..6254cc8 100644 --- a/node/app/node.go +++ b/node/app/node.go @@ -26,6 +26,7 @@ type Node struct { pubSub p2p.PubSub execEngines map[string]execution.ExecutionEngine engine consensus.ConsensusEngine + pebble store.KVDB } type DHTNode struct { @@ -51,6 +52,7 @@ func newNode( pubSub p2p.PubSub, tokenExecutionEngine *token.TokenExecutionEngine, engine consensus.ConsensusEngine, + pebble store.KVDB, ) (*Node, error) { if engine == nil { return nil, errors.New("engine must not be nil") @@ -70,6 +72,7 @@ func newNode( pubSub, execEngines, engine, + pebble, }, nil } @@ -169,6 +172,8 @@ func (n *Node) Stop() { if err != nil { panic(err) } + + n.pebble.Close() } func (n *Node) GetLogger() *zap.Logger { diff --git a/node/app/wire_gen.go b/node/app/wire_gen.go index e64fcce..961193c 100644 --- a/node/app/wire_gen.go +++ b/node/app/wire_gen.go @@ -45,15 +45,15 @@ func NewDebugNode(configConfig *config.Config, selfTestReport *protobufs.SelfTes fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger) p2PConfig := configConfig.P2P blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger) - engineConfig := configConfig.Engine wesolowskiFrameProver := crypto.NewWesolowskiFrameProver(zapLogger) kzgInclusionProver := crypto.NewKZGInclusionProver(zapLogger) + engineConfig := configConfig.Engine masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, wesolowskiFrameProver) inMemoryPeerInfoManager := p2p.NewInMemoryPeerInfoManager(zapLogger) pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger) - tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, engineConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport) + tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport) masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, wesolowskiFrameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport) - node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine) + node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine, pebbleDB) if err != nil { return nil, err } @@ -71,15 +71,15 @@ func NewNode(configConfig *config.Config, selfTestReport *protobufs.SelfTestRepo fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger) p2PConfig := configConfig.P2P blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger) - engineConfig := configConfig.Engine wesolowskiFrameProver := crypto.NewWesolowskiFrameProver(zapLogger) kzgInclusionProver := crypto.NewKZGInclusionProver(zapLogger) + engineConfig := configConfig.Engine masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, wesolowskiFrameProver) inMemoryPeerInfoManager := p2p.NewInMemoryPeerInfoManager(zapLogger) pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger) - tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, engineConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport) + tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport) masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, wesolowskiFrameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport) - node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine) + node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine, pebbleDB) if err != nil { return nil, err } diff --git a/node/config/config.go b/node/config/config.go index 99d8d92..8ad8df6 100644 --- a/node/config/config.go +++ b/node/config/config.go @@ -4,6 +4,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" + "encoding/base64" "encoding/hex" "encoding/json" "fmt" @@ -74,13 +75,14 @@ var BootstrapPeers = []string{ "/ip4/34.143.255.235/udp/8336/quic-v1/p2p/QmeifsP6Kvq8A3yabQs6CBg7prSpDSqdee8P2BDQm9EpP8", "/ip4/34.34.125.238/udp/8336/quic-v1/p2p/QmZdSyBJLm9UiDaPZ4XDkgRGXUwPcHJCmKoH6fS9Qjyko4", "/ip4/34.80.245.52/udp/8336/quic-v1/p2p/QmNmbqobt82Vre5JxUGVNGEWn2HsztQQ1xfeg6mx7X5u3f", - "/dns/bravo-1.qcommander.sh/udp/8336/quic-v1/p2p/QmWFK1gVuhEqZdr8phTo3QbyLwjYmyivx31Zubqt7oR4XB", + "/dns/bravo-1.qcommander.sh/udp/8336/quic-v1/p2p/QmURj4qEB9vNdCCKzSMq4ESEgz13nJrqazgMdGi2DBSeeC", "/ip4/109.199.100.108/udp/8336/quic-v1/p2p/Qma9fgugQc17MDu4YRSvnhfhVre6AYZ3nZdW8dSUYbsWvm", "/ip4/47.251.49.193/udp/8336/quic-v1/p2p/QmP6ADPmMCsB8y82oFbrKTrwYWXt1CTMJ3jGNDXRHyYJgR", "/ip4/138.201.203.208/udp/8336/quic-v1/p2p/QmbNhSTd4Y64ZCbV2gAXYR4ZFDdfRBMfrgWsNg99JHxsJo", "/ip4/148.251.9.90/udp/8336/quic-v1/p2p/QmRpKmQ1W83s6moBFpG6D6nrttkqdQSbdCJpvfxDVGcs38", "/ip4/15.235.211.121/udp/8336/quic-v1/p2p/QmZHNLUSAFCkTwHiEE3vWay3wsus5fWYsNLFTFU6tPCmNR", "/ip4/63.141.228.58/udp/8336/quic-v1/p2p/QmezARggdWKa1sw3LqE3LfZwVvtuCpXpK8WVo8EEdfakJV", + "/ip4/185.209.178.191/udp/8336/quic-v1/p2p/QmcKQjpQmLpbDsiif2MuakhHFyxWvqYauPsJDaXnLav7PJ", // purged peers (keep your node online to return to this list) // "/ip4/204.186.74.47/udp/8317/quic-v1/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", // "/ip4/186.233.184.181/udp/8336/quic-v1/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", @@ -99,8 +101,8 @@ var BootstrapPeers = []string{ } type Signature struct { - PublicKeyHex string `json:"publicKeyHex"` - SignatureHex string `json:"signatureHex"` + PublicKeyHex string `json:PublicKeyHex` + SignatureHex string `json:SignatureHex` } type SignedGenesisUnlock struct { @@ -120,19 +122,79 @@ var Signatories = []string{ "92cd8ee5362f3ae274a75ab9471024dbc144bff441ed8af7d19750ac512ff51e40e7f7b01e4f96b6345dd58878565948c3eb52c53f250b5080", "001a4cbfce5d9aeb7e20665b0d236721b228a32f0baee62ffa77f45b82ecaf577e8a38b7ef91fcf7d2d2d2b504f085461398d30b24abb1d700", "65b835071731c6e785bb2d107c7d85d8a537d79c435c3f42bb2f87027f93f858d7b37c598cef267a5db46e345f7a6f81969b465686657d1e00", - "4507626f7164e7d8c304c07ff8d2e23c113fe108b221d2e60672f4d07750345815e2b4b3cc3df4d3466bf2f669c35c3172e06511270612ab00", - "4fb2537345e46be3d5f96340c1441007501702dd5bfaf6dbf6943bbefceca8fb2b94ec0a8a1a2f49850fbe1d10244889a4f40abfa9e0c9e000", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "57be2861faf0fffcbfd122c85c77010dce8f213030905781b85b6f345d912c7b5ace17797d9810899dfb8d13e7c8369595740725ab3dd5bd00", "61628beef8f6964466fd078d6a2b90a397ab0777a14b9728227fd19f36752f9451b1a8d780740a0b9a8ce3df5f89ca7b9ff17de9274a270980", - "5547afc71b02821e2f5bfdd30fbe1374c3853898deff20a1b5cc729b8e81670fbbb9d1e917f85d153ea4b26bbf6f9c546dc1b64b9916608d80", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "81d63a45f068629f568de812f18be5807bfe828a830097f09cf02330d6acd35e3607401df3fda08b03b68ea6e68afd506b23506b11e87a0f80", "6e2872f73c4868c4286bef7bfe2f5479a41c42f4e07505efa4883c7950c740252e0eea78eef10c584b19b1dcda01f7767d3135d07c33244100", - "a114b061f8d35e3f3497c8c43d83ba6b4af67aa7b39b743b1b0a35f2d66110b5051dd3d86f69b57122a35b64e624b8180bee63b6152fce4280", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", } var unlock *SignedGenesisUnlock func DownloadAndVerifyGenesis(network uint) (*SignedGenesisUnlock, error) { + if network != 0 { + unlock = &SignedGenesisUnlock{ + GenesisSeedHex: "726573697374206d7563682c206f626579206c6974746c657c000000000000000000000005", + Beacon: []byte{ + 0x58, 0xef, 0xd9, 0x7e, 0xdd, 0x0e, 0xb6, 0x2f, + 0x51, 0xc7, 0x5d, 0x00, 0x29, 0x12, 0x45, 0x49, + 0x2e, 0x2f, 0xee, 0x17, 0x24, 0xf4, 0x76, 0x0b, + 0xe6, 0x18, 0x82, 0xab, 0xca, 0x7f, 0xc8, 0x3a, + 0xbd, 0x1a, 0x9e, 0x01, 0x71, 0xb2, 0xe0, 0x8c, + 0x35, 0xa0, 0x42, 0xd0, 0x91, 0x32, 0xb0, 0x42, + 0xda, 0xee, 0x71, 0xf5, 0xe3, 0x73, 0x93, 0x4e, + 0x80, + }, + } + } else { + // From https://releases.quilibrium.com/genesisunlock, skip a download: + beacon, _ := base64.StdEncoding.DecodeString("ImqaBAzHM61pHODoywHu2a6FIOqoXKY/RECZuOXjDfds8DBxtA0g+4hCfOgwiti2TpOF8AH7xH0A") + unlock = &SignedGenesisUnlock{ + GenesisSeedHex: "726573697374206d7563682c206f626579206c6974746c657c083fb0a4274b1f70e9aa2b3f", + Signatures: []Signature{ + { + PublicKeyHex: "b1214da7f355f5a9edb7bcc23d403bdf789f070cca10db2b4cadc22f2d837afb650944853e35d5f42ef3c4105b802b144b4077d5d3253e4100", + SignatureHex: "5176d46e7974cb0d37eb16864fa01ed4d10222ffd38009e451a6339af0ae4938d95dad7af5db7ea9a3bc818cf4dee8e20f9a3be6717d45aa80c0b8bf9783bc5129a7efb0cd900b2a56d84f16d2c531e16a4c4456a37ebed68b95dff3d5b910705aa3963989a92e8908d8eb58622d47bb0c00", + }, + { + PublicKeyHex: "de4cfe7083104bfe32f0d4082fa0200464d8b10804a811653eedda376efcad64dd222f0f0ceb0b8ae58abe830d7a7e3f3b2d79d691318daa00", + SignatureHex: "6f6fb897e54787d716697b54bb18eab857857114d30ca3abe7949d1d1502662a4b181942a207d7ebb144ebd56b0eb83b7860eddf85d51bcd0065d1429006a5840dad464d21d0ac0293bec6ec0ea9f7b38c48e9979febaa36e51101f8a263d1e7666d3cc23746626168d2ad2c817b36f00a00", + }, + { + PublicKeyHex: "540237a35e124882d6b64e7bb5718273fa338e553f772b77fe90570e45303762b34131bdcb6c0b9f2cf9e393d9c7e0f546eeab0bcbbd881680", + SignatureHex: "2ef74fb5222ca8053543b6f62aa89a728fb316c17154c191a27fc50d9923ca55bf469c32134df667a142e28ef563205e72fcfcc0afed3ff50032975bee3f6f2b8f14b90a3693d065075880f0e42755de2828882f5245840edb71083fc8620f041ed44da8515b03360ea6d78715c189f71300", + }, + { + PublicKeyHex: "fbe4166e37f93f90d2ebf06305315ae11b37e501d09596f8bde11ba9d343034fbca80f252205aa2f582a512a72ad293df371baa582da072900", + SignatureHex: "15b25055d570d8a6a1caab8e266995609fc7489045f216871a37201c85515c341c1dbf3f0537ff9436579858ee38c4741dce9e00b4c1ddf180cb592cc73ef6ba6e9374d8a8937fac84ad76a66b528164db9a8de48a11a15557f296f075f729617afe9ca17552f1a8f6dd2c1bb151f2930e00", + }, + { + PublicKeyHex: "45170b626884b85d61ae109f2aa9b0e1ecc18b181508431ea6308f3869f2adae49da9799a0a594eaa4ef3ad492518fb1729decd44169d40d00", + SignatureHex: "4af69e871617eee5ba8b51d73190500bc064ec77e7e396e4d8bca1942dfb538007b1f1ac65787d57f3406e54279d3d360f465723eaf58a8e002cfd54fe78c2c8799cb71a37ea13debd32b868005ff61eea9946b063fa25407929dc445e99b58786e3fe01749208e2a2e367640d9a66130100", + }, + { + PublicKeyHex: "001a4cbfce5d9aeb7e20665b0d236721b228a32f0baee62ffa77f45b82ecaf577e8a38b7ef91fcf7d2d2d2b504f085461398d30b24abb1d700", + SignatureHex: "966f12f5b59f9ac18e15608f638938c137017c9a68f5419de8560f6aedffd454b0dbd6326719a37c84b1e56795933f1584e156145f8814970000554d97e98156c1489b95a1cd196391f71f13d4958eaa66054399c710fe32c4e6cb3214c1f2126f3d44a3402247209cf32bf17b5806d63700", + }, + { + PublicKeyHex: "61628beef8f6964466fd078d6a2b90a397ab0777a14b9728227fd19f36752f9451b1a8d780740a0b9a8ce3df5f89ca7b9ff17de9274a270980", + SignatureHex: "9521933c79b269d33f38ca45f65f02555ae2126e0c378f40ccbf6edc16680035098104caf34a91733043297b44870a739af2ce23a035ffa080b394d438eb781d69167966b7aec1ba2194cda276dfdcf25158d4795f863d779a28c3fd7858ba3b9d3af6c69d91e5609c1b3a28101697500f00", + }, + { + PublicKeyHex: "81d63a45f068629f568de812f18be5807bfe828a830097f09cf02330d6acd35e3607401df3fda08b03b68ea6e68afd506b23506b11e87a0f80", + SignatureHex: "3ebba8c10d2e188ce8e7138d2189dac51a3854c9706849f28c7f60a264951cc5b88534793e5a25b540bb2cb736da5c0b97040ed904d79afe8061e4ad334b16b89a3e29c1c26f6062fc6db146a00f9b7da76ee237004f60bca6e32f452d9074b4c07402092a62cb2596c2eab96d80454c0000", + }, + { + PublicKeyHex: "6e2872f73c4868c4286bef7bfe2f5479a41c42f4e07505efa4883c7950c740252e0eea78eef10c584b19b1dcda01f7767d3135d07c33244100", + SignatureHex: "5701f5cd907a105d0421d2d6d49b147410211e297ef1bc7b8040ec96c742d1b628523cda378ebb57e37bf6a9b6d23bf196a75dc1c461d5b5809be734030c41e577854641b103fe394524439e2c538458bdd4b5490176bf35cac03eb90dfd9b54ff87e46f0da4b7fd2057394922c448eb1c00", + }, + }, + Beacon: beacon, + } + } if unlock != nil { return unlock, nil } @@ -190,12 +252,11 @@ func DownloadAndVerifyGenesis(network uint) (*SignedGenesisUnlock, error) { count++ } - if count < len(Signatories)/2+len(Signatories)%2 { + if count < ((len(Signatories)-4)/2)+((len(Signatories)-4)%2) { fmt.Printf("Quorum on signatures not met") return nil, errors.New("quorum on signatures not met") } - fmt.Println("Stasis lock released. Welcome to 2.0.") unlock = checkUnlock return unlock, err } @@ -457,12 +518,15 @@ func PrintLogo() { fmt.Println("████████████████████████████████████████████████████████████████████████████████") } -func PrintVersion() { +func PrintVersion(network uint8) { patch := GetPatchNumber() patchString := "" if patch != 0x00 { patchString = fmt.Sprintf("-p%d", patch) } + if network != 0 { + patchString = fmt.Sprintf("-b%d", GetRCNumber()) + } fmt.Println(" ") fmt.Println(" Quilibrium Node - v" + GetVersionString() + patchString + " – Dusk") } diff --git a/node/config/p2p.go b/node/config/p2p.go index c38a7b3..95857dd 100644 --- a/node/config/p2p.go +++ b/node/config/p2p.go @@ -39,4 +39,5 @@ type P2PConfig struct { Network uint8 `yaml:"network"` LowWatermarkConnections uint `yaml:"lowWatermarkConnections"` HighWatermarkConnections uint `yaml:"highWatermarkConnections"` + DirectPeers []string `yaml:"directPeers"` } diff --git a/node/config/version.go b/node/config/version.go index 338b501..7b93698 100644 --- a/node/config/version.go +++ b/node/config/version.go @@ -6,15 +6,15 @@ import ( ) func GetMinimumVersionCutoff() time.Time { - return time.Date(2024, time.October, 12, 11, 0, 0, 0, time.UTC) + return time.Date(2024, time.October, 24, 11, 0, 0, 0, time.UTC) } func GetMinimumVersion() []byte { - return []byte{0x02, 0x00, 0x00} + return []byte{0x02, 0x00, 0x02} } func GetVersion() []byte { - return []byte{0x02, 0x00, 0x00} + return []byte{0x02, 0x00, 0x02} } func GetVersionString() string { @@ -36,5 +36,9 @@ func FormatVersion(version []byte) string { } func GetPatchNumber() byte { - return 0x08 + return 0x03 +} + +func GetRCNumber() byte { + return 0x00 } diff --git a/node/consensus/consensus_engine.go b/node/consensus/consensus_engine.go index fab7cf9..65e834c 100644 --- a/node/consensus/consensus_engine.go +++ b/node/consensus/consensus_engine.go @@ -2,6 +2,7 @@ package consensus import ( "crypto" + "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/execution" "source.quilibrium.com/quilibrium/monorepo/node/keys" @@ -40,7 +41,6 @@ type DataConsensusEngine interface { GetFrame() *protobufs.ClockFrame GetDifficulty() uint32 GetState() EngineState - GetFrameChannel() <-chan *protobufs.ClockFrame GetProvingKey( engineConfig *config.EngineConfig, ) (crypto.Signer, keys.KeyType, []byte, []byte) diff --git a/node/consensus/data/broadcast_messaging.go b/node/consensus/data/broadcast_messaging.go index 61e6d00..c424719 100644 --- a/node/consensus/data/broadcast_messaging.go +++ b/node/consensus/data/broadcast_messaging.go @@ -32,56 +32,101 @@ func (e *DataClockConsensusEngine) publishProof( "publishing frame and aggregations", zap.Uint64("frame_number", frame.FrameNumber), ) - head, err := e.dataTimeReel.Head() + + timestamp := time.Now().UnixMilli() + msg := binary.BigEndian.AppendUint64([]byte{}, frame.FrameNumber) + msg = append(msg, config.GetVersion()...) + msg = binary.BigEndian.AppendUint64(msg, uint64(timestamp)) + sig, err := e.pubSub.SignMessage(msg) if err != nil { panic(err) } - peers, max, err := e.GetMostAheadPeer(head.FrameNumber) - if err != nil || len(peers) == 0 || head.FrameNumber > max { - timestamp := time.Now().UnixMilli() - msg := binary.BigEndian.AppendUint64([]byte{}, frame.FrameNumber) - msg = append(msg, config.GetVersion()...) - msg = binary.BigEndian.AppendUint64(msg, uint64(timestamp)) - sig, err := e.pubSub.SignMessage(msg) - if err != nil { - panic(err) - } - - e.peerMapMx.Lock() - e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{ - peerId: e.pubSub.GetPeerID(), - multiaddr: "", - maxFrame: frame.FrameNumber, - version: config.GetVersion(), - signature: sig, - publicKey: e.pubSub.GetPublicKey(), - timestamp: timestamp, - totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( - make([]byte, 256), - ), - } - list := &protobufs.DataPeerListAnnounce{ - PeerList: []*protobufs.DataPeer{}, - } - list.PeerList = append(list.PeerList, &protobufs.DataPeer{ - PeerId: e.pubSub.GetPeerID(), - Multiaddr: "", - MaxFrame: frame.FrameNumber, - Version: config.GetVersion(), - Signature: sig, - PublicKey: e.pubSub.GetPublicKey(), - Timestamp: timestamp, - TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( - make([]byte, 256), - ), - }) - e.peerMapMx.Unlock() - if err := e.publishMessage(e.filter, list); err != nil { - e.logger.Debug("error publishing message", zap.Error(err)) - } + e.peerMapMx.Lock() + e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{ + peerId: e.pubSub.GetPeerID(), + multiaddr: "", + maxFrame: frame.FrameNumber, + version: config.GetVersion(), + signature: sig, + publicKey: e.pubSub.GetPublicKey(), + timestamp: timestamp, + totalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( + make([]byte, 256), + ), + } + list := &protobufs.DataPeerListAnnounce{ + PeerList: []*protobufs.DataPeer{}, + } + list.PeerList = append(list.PeerList, &protobufs.DataPeer{ + PeerId: e.pubSub.GetPeerID(), + Multiaddr: "", + MaxFrame: frame.FrameNumber, + Version: config.GetVersion(), + Signature: sig, + PublicKey: e.pubSub.GetPublicKey(), + Timestamp: timestamp, + TotalDistance: e.dataTimeReel.GetTotalDistance().FillBytes( + make([]byte, 256), + ), + }) + e.peerMapMx.Unlock() + if err := e.publishMessage(e.filter, list); err != nil { + e.logger.Debug("error publishing message", zap.Error(err)) + } + + e.publishMessage(e.filter, frame) + + return nil +} + +func (e *DataClockConsensusEngine) insertMessage( + filter []byte, + message proto.Message, +) error { + any := &anypb.Any{} + if err := any.MarshalFrom(message); err != nil { + return errors.Wrap(err, "publish message") } + any.TypeUrl = strings.Replace( + any.TypeUrl, + "type.googleapis.com", + "types.quilibrium.com", + 1, + ) + + payload, err := proto.Marshal(any) + if err != nil { + return errors.Wrap(err, "publish message") + } + + h, err := poseidon.HashBytes(payload) + if err != nil { + return errors.Wrap(err, "publish message") + } + + msg := &protobufs.Message{ + Hash: h.Bytes(), + Address: e.provingKeyAddress, + Payload: payload, + } + data, err := proto.Marshal(msg) + if err != nil { + return errors.Wrap(err, "publish message") + } + + m := &pb.Message{ + Data: data, + Bitmask: filter, + From: e.pubSub.GetPeerID(), + Seqno: nil, + } + + go func() { + e.messageProcessorCh <- m + }() + return nil } diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 14029bf..1012c10 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -17,19 +17,57 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) +func (e *DataClockConsensusEngine) collect( + enqueuedFrame *protobufs.ClockFrame, +) (*protobufs.ClockFrame, error) { + e.logger.Info("collecting vdf proofs") + + latest := enqueuedFrame + + for { + peerId, maxFrame, err := e.GetMostAheadPeer(latest.FrameNumber) + if maxFrame > latest.FrameNumber { + e.syncingStatus = SyncStatusSynchronizing + if err != nil { + e.logger.Info("no peers available for sync, waiting") + time.Sleep(5 * time.Second) + } else if maxFrame > latest.FrameNumber { + if maxFrame-latest.FrameNumber > 100 { + maxFrame = latest.FrameNumber + 100 + } + latest, err = e.sync(latest, maxFrame, peerId) + if err == nil { + break + } + } + } else { + break + } + } + + e.syncingStatus = SyncStatusNotSyncing + + e.logger.Info( + "returning leader frame", + zap.Uint64("frame_number", latest.FrameNumber), + ) + + return latest, nil +} + func (e *DataClockConsensusEngine) prove( previousFrame *protobufs.ClockFrame, ) (*protobufs.ClockFrame, error) { e.stagedTransactionsMx.Lock() executionOutput := &protobufs.IntrinsicExecutionOutput{} app, err := application.MaterializeApplicationFromFrame( + e.provingKey, previousFrame, e.frameProverTries, e.coinStore, e.logger, ) if err != nil { - e.stagedTransactions = &protobufs.TokenRequests{} e.stagedTransactionsMx.Unlock() return nil, errors.Wrap(err, "prove") } @@ -44,7 +82,8 @@ func (e *DataClockConsensusEngine) prove( ) var validTransactions *protobufs.TokenRequests - app, validTransactions, _, err = app.ApplyTransitions( + var invalidTransactions *protobufs.TokenRequests + app, validTransactions, invalidTransactions, err = app.ApplyTransitions( previousFrame.FrameNumber, e.stagedTransactions, true, @@ -55,7 +94,13 @@ func (e *DataClockConsensusEngine) prove( return nil, errors.Wrap(err, "prove") } - defer e.stagedTransactionsMx.Unlock() + e.logger.Info( + "applied transitions", + zap.Int("successful", len(validTransactions.Requests)), + zap.Int("failed", len(invalidTransactions.Requests)), + ) + e.stagedTransactions = &protobufs.TokenRequests{} + e.stagedTransactionsMx.Unlock() outputState, err := app.MaterializeStateFromApplication() if err != nil { @@ -162,13 +207,17 @@ func (e *DataClockConsensusEngine) GetMostAheadPeer( uint64, error, ) { - e.logger.Info( + e.logger.Debug( "checking peer list", zap.Int("peers", len(e.peerMap)), zap.Int("uncooperative_peers", len(e.uncooperativePeersMap)), zap.Uint64("current_head_frame", frameNumber), ) + if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + return e.pubSub.GetPeerID(), frameNumber, nil + } + max := frameNumber var peer []byte = nil e.peerMapMx.RLock() @@ -204,7 +253,7 @@ func (e *DataClockConsensusEngine) sync( ) (*protobufs.ClockFrame, error) { latest := currentLatest e.logger.Info("polling peer for new frames", zap.Binary("peer_id", peerId)) - cc, err := e.pubSub.GetDirectChannel(peerId, "") + cc, err := e.pubSub.GetDirectChannel(peerId, "sync") if err != nil { e.logger.Debug( "could not establish direct channel", @@ -222,87 +271,85 @@ func (e *DataClockConsensusEngine) sync( client := protobufs.NewDataServiceClient(cc) - response, err := client.GetDataFrame( - context.TODO(), - &protobufs.GetDataFrameRequest{ - FrameNumber: currentLatest.FrameNumber + 1, - }, - grpc.MaxCallRecvMsgSize(600*1024*1024), - ) - if err != nil { - e.logger.Debug( - "could not get frame", - zap.Error(err), + for { + response, err := client.GetDataFrame( + context.TODO(), + &protobufs.GetDataFrameRequest{ + FrameNumber: latest.FrameNumber + 1, + }, + grpc.MaxCallRecvMsgSize(600*1024*1024), ) - e.peerMapMx.Lock() - if _, ok := e.peerMap[string(peerId)]; ok { - e.uncooperativePeersMap[string(peerId)] = e.peerMap[string(peerId)] - e.uncooperativePeersMap[string(peerId)].timestamp = time.Now().UnixMilli() - delete(e.peerMap, string(peerId)) - } - e.peerMapMx.Unlock() - if err := cc.Close(); err != nil { - e.logger.Error("error while closing connection", zap.Error(err)) + if err != nil { + e.logger.Debug( + "could not get frame", + zap.Error(err), + ) + e.peerMapMx.Lock() + if _, ok := e.peerMap[string(peerId)]; ok { + e.uncooperativePeersMap[string(peerId)] = e.peerMap[string(peerId)] + e.uncooperativePeersMap[string(peerId)].timestamp = time.Now().UnixMilli() + delete(e.peerMap, string(peerId)) + } + e.peerMapMx.Unlock() + if err := cc.Close(); err != nil { + e.logger.Error("error while closing connection", zap.Error(err)) + } + return latest, errors.Wrap(err, "sync") } - return latest, errors.Wrap(err, "sync") - } - if response == nil { - e.logger.Debug("received no response from peer") - if err := cc.Close(); err != nil { - e.logger.Error("error while closing connection", zap.Error(err)) + if response == nil { + e.logger.Debug("received no response from peer") + if err := cc.Close(); err != nil { + e.logger.Error("error while closing connection", zap.Error(err)) + } + return latest, nil } - return latest, nil - } - - e.logger.Info( - "received new leading frame", - zap.Uint64("frame_number", response.ClockFrame.FrameNumber), - ) - if err := cc.Close(); err != nil { - e.logger.Error("error while closing connection", zap.Error(err)) - } - e.dataTimeReel.Insert(response.ClockFrame, false) - - return response.ClockFrame, nil -} + if response.ClockFrame == nil || + response.ClockFrame.FrameNumber != latest.FrameNumber+1 || -func (e *DataClockConsensusEngine) collect( - currentFramePublished *protobufs.ClockFrame, -) (*protobufs.ClockFrame, error) { - e.logger.Info("collecting vdf proofs") - - latest := currentFramePublished - - for { - peerId, maxFrame, err := e.GetMostAheadPeer(latest.FrameNumber) - if maxFrame > latest.FrameNumber { - e.syncingStatus = SyncStatusSynchronizing - if err != nil { - e.logger.Info("no peers available for sync, waiting") - time.Sleep(5 * time.Second) - } else if maxFrame > latest.FrameNumber { - latest, err = e.sync(latest, maxFrame, peerId) - if err == nil { - break - } + response.ClockFrame.Timestamp < latest.Timestamp { + e.logger.Debug("received invalid response from peer") + e.peerMapMx.Lock() + if _, ok := e.peerMap[string(peerId)]; ok { + e.uncooperativePeersMap[string(peerId)] = e.peerMap[string(peerId)] + e.uncooperativePeersMap[string(peerId)].timestamp = time.Now().UnixMilli() + delete(e.peerMap, string(peerId)) } - } else { + e.peerMapMx.Unlock() + if err := cc.Close(); err != nil { + e.logger.Error("error while closing connection", zap.Error(err)) + } + return latest, nil + } + e.logger.Info( + "received new leading frame", + zap.Uint64("frame_number", response.ClockFrame.FrameNumber), + ) + if !e.IsInProverTrie( + response.ClockFrame.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) { + e.peerMapMx.Lock() + if _, ok := e.peerMap[string(peerId)]; ok { + e.uncooperativePeersMap[string(peerId)] = e.peerMap[string(peerId)] + e.uncooperativePeersMap[string(peerId)].timestamp = time.Now().UnixMilli() + delete(e.peerMap, string(peerId)) + } + e.peerMapMx.Unlock() + } + if err := e.frameProver.VerifyDataClockFrame( + response.ClockFrame, + ); err != nil { + return nil, errors.Wrap(err, "sync") + } + e.dataTimeReel.Insert(response.ClockFrame, true) + latest = response.ClockFrame + if latest.FrameNumber >= maxFrame { break } } - - e.syncingStatus = SyncStatusNotSyncing - - if latest.FrameNumber < currentFramePublished.FrameNumber { - latest = currentFramePublished + if err := cc.Close(); err != nil { + e.logger.Error("error while closing connection", zap.Error(err)) } - - e.logger.Info( - "returning leader frame", - zap.Uint64("frame_number", latest.FrameNumber), - ) - return latest, nil } diff --git a/node/consensus/data/data_clock_consensus_engine.go b/node/consensus/data/data_clock_consensus_engine.go index 8f1b9d5..4f69024 100644 --- a/node/consensus/data/data_clock_consensus_engine.go +++ b/node/consensus/data/data_clock_consensus_engine.go @@ -1,13 +1,11 @@ package data import ( - "bytes" "context" "crypto" "encoding/binary" "fmt" "math/big" - "slices" "sync" "time" @@ -32,7 +30,7 @@ import ( ) const PEER_INFO_TTL = 60 * 60 * 1000 -const UNCOOPERATIVE_PEER_INFO_TTL = 5 * 60 * 1000 +const UNCOOPERATIVE_PEER_INFO_TTL = 60 * 1000 var ErrNoApplicableChallenge = errors.New("no applicable challenge") @@ -63,11 +61,12 @@ type ChannelServer = protobufs.DataService_GetPublicChannelServer type DataClockConsensusEngine struct { protobufs.UnimplementedDataServiceServer difficulty uint32 - engineConfig *config.EngineConfig + config *config.Config logger *zap.Logger state consensus.EngineState clockStore store.ClockStore coinStore store.CoinStore + dataProofStore store.DataProofStore keyStore store.KeyStore pubSub p2p.PubSub keyManager keys.KeyManager @@ -81,6 +80,8 @@ type DataClockConsensusEngine struct { lastFrameReceivedAt time.Time latestFrameReceived uint64 frameProverTries []*tries.RollingFrecencyCritbitTrie + preMidnightMintMx sync.Mutex + preMidnightMint map[string]struct{} frameProverTriesMx sync.RWMutex dependencyMap map[string]*anypb.Any pendingCommits chan *anypb.Any @@ -92,24 +93,24 @@ type DataClockConsensusEngine struct { currentReceivingSyncPeersMx sync.Mutex currentReceivingSyncPeers int - frameChan chan *protobufs.ClockFrame - executionEngines map[string]execution.ExecutionEngine - filter []byte - input []byte - parentSelector []byte - syncingStatus SyncStatusType - syncingTarget []byte - previousHead *protobufs.ClockFrame - engineMx sync.Mutex - dependencyMapMx sync.Mutex - stagedTransactions *protobufs.TokenRequests - stagedTransactionsMx sync.Mutex - peerMapMx sync.RWMutex - peerAnnounceMapMx sync.Mutex - proverTrieJoinRequests map[string]string - proverTrieLeaveRequests map[string]string - proverTriePauseRequests map[string]string - proverTrieResumeRequests map[string]string + frameChan chan *protobufs.ClockFrame + executionEngines map[string]execution.ExecutionEngine + filter []byte + input []byte + parentSelector []byte + syncingStatus SyncStatusType + syncingTarget []byte + previousHead *protobufs.ClockFrame + engineMx sync.Mutex + dependencyMapMx sync.Mutex + stagedTransactions *protobufs.TokenRequests + stagedTransactionsMx sync.Mutex + peerMapMx sync.RWMutex + peerAnnounceMapMx sync.Mutex + // proverTrieJoinRequests map[string]string + // proverTrieLeaveRequests map[string]string + // proverTriePauseRequests map[string]string + // proverTrieResumeRequests map[string]string proverTrieRequestsMx sync.Mutex lastKeyBundleAnnouncementFrame uint64 peerSeniority *peerSeniority @@ -144,11 +145,12 @@ func (p peerSeniorityItem) Priority() *big.Int { var _ consensus.DataConsensusEngine = (*DataClockConsensusEngine)(nil) func NewDataClockConsensusEngine( - engineConfig *config.EngineConfig, + config *config.Config, logger *zap.Logger, keyManager keys.KeyManager, clockStore store.ClockStore, coinStore store.CoinStore, + dataProofStore store.DataProofStore, keyStore store.KeyStore, pubSub p2p.PubSub, frameProver qcrypto.FrameProver, @@ -165,7 +167,7 @@ func NewDataClockConsensusEngine( panic(errors.New("logger is nil")) } - if engineConfig == nil { + if config == nil { panic(errors.New("engine config is nil")) } @@ -181,6 +183,10 @@ func NewDataClockConsensusEngine( panic(errors.New("coin store is nil")) } + if dataProofStore == nil { + panic(errors.New("data proof store is nil")) + } + if keyStore == nil { panic(errors.New("key store is nil")) } @@ -209,14 +215,14 @@ func NewDataClockConsensusEngine( panic(errors.New("peer info manager is nil")) } - minimumPeersRequired := engineConfig.MinimumPeersRequired + minimumPeersRequired := config.Engine.MinimumPeersRequired if minimumPeersRequired == 0 { minimumPeersRequired = 3 } - difficulty := engineConfig.Difficulty + difficulty := config.Engine.Difficulty if difficulty == 0 { - difficulty = 200000 + difficulty = 160000 } e := &DataClockConsensusEngine{ @@ -225,6 +231,7 @@ func NewDataClockConsensusEngine( state: consensus.EngineStateStopped, clockStore: clockStore, coinStore: coinStore, + dataProofStore: dataProofStore, keyStore: keyStore, keyManager: keyManager, pubSub: pubSub, @@ -252,13 +259,14 @@ func NewDataClockConsensusEngine( peerInfoManager: peerInfoManager, peerSeniority: newFromMap(peerSeniority), messageProcessorCh: make(chan *pb.Message), - engineConfig: engineConfig, + config: config, + preMidnightMint: map[string]struct{}{}, } logger.Info("constructing consensus engine") signer, keyType, bytes, address := e.GetProvingKey( - engineConfig, + config.Engine, ) e.filter = filter @@ -294,23 +302,39 @@ func (e *DataClockConsensusEngine) Start() <-chan error { e.logger.Info("subscribing to pubsub messages") e.pubSub.Subscribe(e.filter, e.handleMessage) - go func() { server := grpc.NewServer( grpc.MaxSendMsgSize(600*1024*1024), grpc.MaxRecvMsgSize(600*1024*1024), ) protobufs.RegisterDataServiceServer(server, e) - if err := e.pubSub.StartDirectChannelListener( e.pubSub.GetPeerID(), - "", + "sync", server, ); err != nil { panic(err) } }() + go func() { + if e.dataTimeReel.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + server := grpc.NewServer( + grpc.MaxSendMsgSize(1*1024*1024), + grpc.MaxRecvMsgSize(1*1024*1024), + ) + protobufs.RegisterDataServiceServer(server, e) + + if err := e.pubSub.StartDirectChannelListener( + e.pubSub.GetPeerID(), + "worker", + server, + ); err != nil { + panic(err) + } + } + }() + e.state = consensus.EngineStateCollecting go func() { @@ -325,8 +349,9 @@ func (e *DataClockConsensusEngine) Start() <-chan error { panic(err) } - if frame.FrameNumber >= nextFrame.FrameNumber { - time.Sleep(30 * time.Second) + if frame.FrameNumber-100 >= nextFrame.FrameNumber || + nextFrame.FrameNumber == 0 { + time.Sleep(60 * time.Second) continue } @@ -409,11 +434,23 @@ func (e *DataClockConsensusEngine) Start() <-chan error { }() go e.runLoop() + go e.rebroadcastLoop() + go func() { + time.Sleep(30 * time.Second) + e.logger.Info("checking for snapshots to play forward") + if err := e.downloadSnapshot(e.config.DB.Path, e.config.P2P.Network); err != nil { + e.logger.Error("error downloading snapshot", zap.Error(err)) + } else if err := e.applySnapshot(e.config.DB.Path); err != nil { + e.logger.Error("error replaying snapshot", zap.Error(err)) + } + }() go func() { errChan <- nil }() + go e.runPreMidnightProofWorker() + go func() { frame, err := e.dataTimeReel.Head() if err != nil { @@ -429,7 +466,7 @@ func (e *DataClockConsensusEngine) Start() <-chan error { } var clients []protobufs.DataIPCServiceClient - if len(e.engineConfig.DataWorkerMultiaddrs) != 0 { + if len(e.config.Engine.DataWorkerMultiaddrs) != 0 { clients, err = e.createParallelDataClientsFromList() if err != nil { panic(err) @@ -454,7 +491,14 @@ func (e *DataClockConsensusEngine) Start() <-chan error { continue } - e.PerformTimeProof(frame, frame.Difficulty, clients) + frame = nextFrame + + for i, trie := range e.GetFrameProverTries()[1:] { + if trie.Contains(e.provingKeyAddress) { + e.logger.Info("creating data shard ring proof", zap.Int("ring", i-1)) + e.PerformTimeProof(frame, frame.Difficulty, clients) + } + } } }() @@ -474,7 +518,7 @@ func (e *DataClockConsensusEngine) PerformTimeProof( for j := 3; j >= 0; j-- { var err error if client == nil { - if len(e.engineConfig.DataWorkerMultiaddrs) != 0 { + if len(e.config.Engine.DataWorkerMultiaddrs) != 0 { e.logger.Error( "client failed, reconnecting after 50ms", zap.Uint32("client", uint32(i)), @@ -484,7 +528,7 @@ func (e *DataClockConsensusEngine) PerformTimeProof( if err != nil { e.logger.Error("failed to reconnect", zap.Error(err)) } - } else if len(e.engineConfig.DataWorkerMultiaddrs) == 0 { + } else if len(e.config.Engine.DataWorkerMultiaddrs) == 0 { e.logger.Error( "client failed, reconnecting after 50ms", ) @@ -513,7 +557,7 @@ func (e *DataClockConsensusEngine) PerformTimeProof( if j == 0 { e.logger.Error("unable to get a response in time from worker", zap.Error(err)) } - if len(e.engineConfig.DataWorkerMultiaddrs) != 0 { + if len(e.config.Engine.DataWorkerMultiaddrs) != 0 { e.logger.Error( "client failed, reconnecting after 50ms", zap.Uint32("client", uint32(i)), @@ -523,7 +567,7 @@ func (e *DataClockConsensusEngine) PerformTimeProof( if err != nil { e.logger.Error("failed to reconnect", zap.Error(err)) } - } else if len(e.engineConfig.DataWorkerMultiaddrs) == 0 { + } else if len(e.config.Engine.DataWorkerMultiaddrs) == 0 { e.logger.Error( "client failed, reconnecting after 50ms", ) @@ -566,307 +610,29 @@ func (e *DataClockConsensusEngine) PerformTimeProof( return []byte{} } -func ( - e *DataClockConsensusEngine, -) GetFrameProverTries() []*tries.RollingFrecencyCritbitTrie { - e.frameProverTriesMx.RLock() - frameProverTries := make( - []*tries.RollingFrecencyCritbitTrie, - len(e.frameProverTries), - ) - - for i, trie := range e.frameProverTries { - newTrie := &tries.RollingFrecencyCritbitTrie{} - b, err := trie.Serialize() - if err != nil { - panic(err) - } - - err = newTrie.Deserialize(b) - if err != nil { - panic(err) - } - frameProverTries[i] = newTrie - } - - e.frameProverTriesMx.RUnlock() - return frameProverTries -} - -func (e *DataClockConsensusEngine) runLoop() { - dataFrameCh := e.dataTimeReel.NewFrameCh() - - for e.state < consensus.EngineStateStopping { - peerCount := e.pubSub.GetNetworkPeersCount() - if peerCount < e.minimumPeersRequired { - e.logger.Info( - "waiting for minimum peers", - zap.Int("peer_count", peerCount), - ) - time.Sleep(1 * time.Second) - } else { - latestFrame, err := e.dataTimeReel.Head() - if err != nil { - panic(err) - } - select { - case dataFrame := <-dataFrameCh: - if latestFrame, err = e.collect(dataFrame); err != nil { - e.logger.Error("could not collect", zap.Error(err)) - } - - dataFrame, err := e.dataTimeReel.Head() - if err != nil { - panic(err) - } - - if latestFrame != nil && - dataFrame.FrameNumber > latestFrame.FrameNumber { - latestFrame = dataFrame - } - - if e.latestFrameReceived < latestFrame.FrameNumber { - e.latestFrameReceived = latestFrame.FrameNumber - go func() { - select { - case e.frameChan <- latestFrame: - default: - } - }() - } - - trie := e.GetFrameProverTries()[0] - if bytes.Equal( - trie.FindNearest(e.provingKeyAddress).External.Key, - e.provingKeyAddress, - ) { - var nextFrame *protobufs.ClockFrame - if nextFrame, err = e.prove(latestFrame); err != nil { - e.logger.Error("could not prove", zap.Error(err)) - e.state = consensus.EngineStateCollecting - continue - } - - e.proverTrieRequestsMx.Lock() - joinAddrs := tries.NewMinHeap[peerSeniorityItem]() - leaveAddrs := tries.NewMinHeap[peerSeniorityItem]() - for _, addr := range e.proverTrieJoinRequests { - if _, ok := (*e.peerSeniority)[addr]; !ok { - joinAddrs.Push(peerSeniorityItem{ - addr: addr, - seniority: 0, - }) - } else { - joinAddrs.Push((*e.peerSeniority)[addr]) - } - } - for _, addr := range e.proverTrieLeaveRequests { - if _, ok := (*e.peerSeniority)[addr]; !ok { - leaveAddrs.Push(peerSeniorityItem{ - addr: addr, - seniority: 0, - }) - } else { - leaveAddrs.Push((*e.peerSeniority)[addr]) - } - } - for _, addr := range e.proverTrieResumeRequests { - if _, ok := e.proverTriePauseRequests[addr]; ok { - delete(e.proverTriePauseRequests, addr) - } - } - - joinReqs := make([]peerSeniorityItem, len(joinAddrs.All())) - copy(joinReqs, joinAddrs.All()) - slices.Reverse(joinReqs) - leaveReqs := make([]peerSeniorityItem, len(leaveAddrs.All())) - copy(leaveReqs, leaveAddrs.All()) - slices.Reverse(leaveReqs) - - e.proverTrieJoinRequests = make(map[string]string) - e.proverTrieLeaveRequests = make(map[string]string) - e.proverTrieRequestsMx.Unlock() - - e.frameProverTriesMx.Lock() - for _, addr := range joinReqs { - rings := len(e.frameProverTries) - last := e.frameProverTries[rings-1] - set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) - if len(set) == 8 { - e.frameProverTries = append( - e.frameProverTries, - &tries.RollingFrecencyCritbitTrie{}, - ) - last = e.frameProverTries[rings] - } - last.Add([]byte(addr.addr), nextFrame.FrameNumber) - } - for _, addr := range leaveReqs { - for _, t := range e.frameProverTries { - if bytes.Equal( - t.FindNearest([]byte(addr.addr)).External.Key, - []byte(addr.addr), - ) { - t.Remove([]byte(addr.addr)) - break - } - } - } - e.frameProverTriesMx.Unlock() - - e.dataTimeReel.Insert(nextFrame, false) - - if err = e.publishProof(nextFrame); err != nil { - e.logger.Error("could not publish", zap.Error(err)) - e.state = consensus.EngineStateCollecting - } - break - } - case <-time.After(20 * time.Second): - dataFrame, err := e.dataTimeReel.Head() - if err != nil { - panic(err) - } - - if latestFrame, err = e.collect(dataFrame); err != nil { - e.logger.Error("could not collect", zap.Error(err)) - continue - } - - if latestFrame == nil || - latestFrame.FrameNumber < dataFrame.FrameNumber { - latestFrame, err = e.dataTimeReel.Head() - if err != nil { - panic(err) - } - } - - if e.latestFrameReceived < latestFrame.FrameNumber { - e.latestFrameReceived = latestFrame.FrameNumber - go func() { - select { - case e.frameChan <- latestFrame: - default: - } - }() - } - - for _, trie := range e.GetFrameProverTries() { - if bytes.Equal( - trie.FindNearest(e.provingKeyAddress).External.Key, - e.provingKeyAddress, - ) { - var nextFrame *protobufs.ClockFrame - if nextFrame, err = e.prove(latestFrame); err != nil { - e.logger.Error("could not prove", zap.Error(err)) - e.state = consensus.EngineStateCollecting - continue - } - - e.proverTrieRequestsMx.Lock() - joinAddrs := tries.NewMinHeap[peerSeniorityItem]() - leaveAddrs := tries.NewMinHeap[peerSeniorityItem]() - for _, addr := range e.proverTrieJoinRequests { - if _, ok := (*e.peerSeniority)[addr]; !ok { - joinAddrs.Push(peerSeniorityItem{ - addr: addr, - seniority: 0, - }) - } else { - joinAddrs.Push((*e.peerSeniority)[addr]) - } - } - for _, addr := range e.proverTrieLeaveRequests { - if _, ok := (*e.peerSeniority)[addr]; !ok { - leaveAddrs.Push(peerSeniorityItem{ - addr: addr, - seniority: 0, - }) - } else { - leaveAddrs.Push((*e.peerSeniority)[addr]) - } - } - for _, addr := range e.proverTrieResumeRequests { - if _, ok := e.proverTriePauseRequests[addr]; ok { - delete(e.proverTriePauseRequests, addr) - } - } - - joinReqs := make([]peerSeniorityItem, len(joinAddrs.All())) - copy(joinReqs, joinAddrs.All()) - slices.Reverse(joinReqs) - leaveReqs := make([]peerSeniorityItem, len(leaveAddrs.All())) - copy(leaveReqs, leaveAddrs.All()) - slices.Reverse(leaveReqs) - - e.proverTrieJoinRequests = make(map[string]string) - e.proverTrieLeaveRequests = make(map[string]string) - e.proverTrieRequestsMx.Unlock() - - e.frameProverTriesMx.Lock() - for _, addr := range joinReqs { - rings := len(e.frameProverTries) - last := e.frameProverTries[rings-1] - set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) - if len(set) == 8 { - e.frameProverTries = append( - e.frameProverTries, - &tries.RollingFrecencyCritbitTrie{}, - ) - last = e.frameProverTries[rings] - } - last.Add([]byte(addr.addr), nextFrame.FrameNumber) - } - for _, addr := range leaveReqs { - for _, t := range e.frameProverTries { - if bytes.Equal( - t.FindNearest([]byte(addr.addr)).External.Key, - []byte(addr.addr), - ) { - t.Remove([]byte(addr.addr)) - break - } - } - } - e.frameProverTriesMx.Unlock() - - e.dataTimeReel.Insert(nextFrame, false) - - if err = e.publishProof(nextFrame); err != nil { - e.logger.Error("could not publish", zap.Error(err)) - e.state = consensus.EngineStateCollecting - } - break - } - } - } - } - } -} - func (e *DataClockConsensusEngine) Stop(force bool) <-chan error { e.logger.Info("stopping ceremony consensus engine") e.state = consensus.EngineStateStopping errChan := make(chan error) - msg := []byte("pause") - msg = binary.BigEndian.AppendUint64(msg, e.GetFrame().FrameNumber) - msg = append(msg, e.filter...) - sig, err := e.pubSub.SignMessage(msg) - if err != nil { - panic(err) - } - - e.publishMessage(e.filter, &protobufs.AnnounceProverPause{ - Filter: e.filter, - FrameNumber: e.GetFrame().FrameNumber, - PublicKeySignatureEd448: &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - Signature: sig, - }, - }) + // msg := []byte("pause") + // msg = binary.BigEndian.AppendUint64(msg, e.GetFrame().FrameNumber) + // msg = append(msg, e.filter...) + // sig, err := e.pubSub.SignMessage(msg) + // if err != nil { + // panic(err) + // } + + // e.publishMessage(e.filter, &protobufs.AnnounceProverPause{ + // Filter: e.filter, + // FrameNumber: e.GetFrame().FrameNumber, + // PublicKeySignatureEd448: &protobufs.Ed448Signature{ + // PublicKey: &protobufs.Ed448PublicKey{ + // KeyValue: e.pubSub.GetPublicKey(), + // }, + // Signature: sig, + // }, + // }) wg := sync.WaitGroup{} wg.Add(len(e.executionEngines)) @@ -908,7 +674,7 @@ func (e *DataClockConsensusEngine) GetDifficulty() uint32 { func (e *DataClockConsensusEngine) GetFrame() *protobufs.ClockFrame { frame, err := e.dataTimeReel.Head() if err != nil { - panic(err) + return nil } return frame @@ -918,12 +684,6 @@ func (e *DataClockConsensusEngine) GetState() consensus.EngineState { return e.state } -func ( - e *DataClockConsensusEngine, -) GetFrameChannel() <-chan *protobufs.ClockFrame { - return e.frameChan -} - func ( e *DataClockConsensusEngine, ) GetPeerInfo() *protobufs.PeerInfoResponse { @@ -1000,7 +760,7 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromListAndIndex( protobufs.DataIPCServiceClient, error, ) { - ma, err := multiaddr.NewMultiaddr(e.engineConfig.DataWorkerMultiaddrs[index]) + ma, err := multiaddr.NewMultiaddr(e.config.Engine.DataWorkerMultiaddrs[index]) if err != nil { return nil, errors.Wrap(err, "create parallel data client") } @@ -1046,18 +806,18 @@ func ( zap.Uint32("client", index), ) - if e.engineConfig.DataWorkerBaseListenMultiaddr == "" { - e.engineConfig.DataWorkerBaseListenMultiaddr = "/ip4/127.0.0.1/tcp/%d" + if e.config.Engine.DataWorkerBaseListenMultiaddr == "" { + e.config.Engine.DataWorkerBaseListenMultiaddr = "/ip4/127.0.0.1/tcp/%d" } - if e.engineConfig.DataWorkerBaseListenPort == 0 { - e.engineConfig.DataWorkerBaseListenPort = 40000 + if e.config.Engine.DataWorkerBaseListenPort == 0 { + e.config.Engine.DataWorkerBaseListenPort = 40000 } ma, err := multiaddr.NewMultiaddr( fmt.Sprintf( - e.engineConfig.DataWorkerBaseListenMultiaddr, - int(e.engineConfig.DataWorkerBaseListenPort)+int(index), + e.config.Engine.DataWorkerBaseListenMultiaddr, + int(e.config.Engine.DataWorkerBaseListenPort)+int(index), ), ) if err != nil { @@ -1096,7 +856,7 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromList() ( []protobufs.DataIPCServiceClient, error, ) { - parallelism := len(e.engineConfig.DataWorkerMultiaddrs) + parallelism := len(e.config.Engine.DataWorkerMultiaddrs) e.logger.Info( "connecting to data worker processes", @@ -1106,7 +866,7 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromList() ( clients := make([]protobufs.DataIPCServiceClient, parallelism) for i := 0; i < parallelism; i++ { - ma, err := multiaddr.NewMultiaddr(e.engineConfig.DataWorkerMultiaddrs[i]) + ma, err := multiaddr.NewMultiaddr(e.config.Engine.DataWorkerMultiaddrs[i]) if err != nil { panic(err) } @@ -1150,12 +910,12 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromBaseMultiaddr( zap.Int("parallelism", parallelism), ) - if e.engineConfig.DataWorkerBaseListenMultiaddr == "" { - e.engineConfig.DataWorkerBaseListenMultiaddr = "/ip4/127.0.0.1/tcp/%d" + if e.config.Engine.DataWorkerBaseListenMultiaddr == "" { + e.config.Engine.DataWorkerBaseListenMultiaddr = "/ip4/127.0.0.1/tcp/%d" } - if e.engineConfig.DataWorkerBaseListenPort == 0 { - e.engineConfig.DataWorkerBaseListenPort = 40000 + if e.config.Engine.DataWorkerBaseListenPort == 0 { + e.config.Engine.DataWorkerBaseListenPort = 40000 } clients := make([]protobufs.DataIPCServiceClient, parallelism) @@ -1163,8 +923,8 @@ func (e *DataClockConsensusEngine) createParallelDataClientsFromBaseMultiaddr( for i := 0; i < parallelism; i++ { ma, err := multiaddr.NewMultiaddr( fmt.Sprintf( - e.engineConfig.DataWorkerBaseListenMultiaddr, - int(e.engineConfig.DataWorkerBaseListenPort)+i, + e.config.Engine.DataWorkerBaseListenMultiaddr, + int(e.config.Engine.DataWorkerBaseListenPort)+i, ), ) if err != nil { diff --git a/node/consensus/data/frame_importer.go b/node/consensus/data/frame_importer.go new file mode 100644 index 0000000..7f7b1bb --- /dev/null +++ b/node/consensus/data/frame_importer.go @@ -0,0 +1,272 @@ +package data + +import ( + "archive/zip" + "bufio" + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "io" + "net/http" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +func (e *DataClockConsensusEngine) downloadSnapshot( + dbPath string, + network uint8, +) error { + frame, _, err := e.clockStore.GetLatestDataClockFrame(e.filter) + if err != nil { + return errors.Wrap(err, "download snapshot") + } + + if frame.Timestamp > time.Now().Add(-6*time.Hour).UnixMilli() { + return errors.Wrap( + errors.New("synced higher than recent snapshot"), + "download snapshot", + ) + } + + resp, err := http.Get( + fmt.Sprintf( + "https://frame-snapshots.quilibrium.com/%d/latest-backup", + network, + ), + ) + if err != nil { + return errors.Wrap(err, "download snapshot") + } + defer resp.Body.Close() + + scanner := bufio.NewScanner(resp.Body) + if !scanner.Scan() { + return errors.Wrap( + errors.New("metadata file is empty"), + "download snapshot", + ) + } + zipURL := strings.TrimSpace(scanner.Text()) + + if !scanner.Scan() { + return errors.Wrap( + errors.New("metadata file missing hash"), + "download snapshot", + ) + } + expectedHash := strings.TrimSpace(scanner.Text()) + + resp, err = http.Get( + fmt.Sprintf( + "https://frame-snapshots.quilibrium.com/%d/%s", + network, + zipURL, + ), + ) + if err != nil { + return errors.Wrap(err, "download snapshot") + } + defer resp.Body.Close() + + err = os.MkdirAll( + path.Join(dbPath, "snapshot"), + 0755, + ) + if err != nil { + return errors.Wrap( + fmt.Errorf("failed to create extraction directory: %w", err), + "download snapshot", + ) + } + + tempFile, err := os.CreateTemp( + path.Join(dbPath, "snapshot"), + "snapshot.zip", + ) + if err != nil { + return errors.Wrap(err, "download snapshot") + } + defer os.Remove(tempFile.Name()) + defer tempFile.Close() + + hasher := sha256.New() + writer := io.MultiWriter(tempFile, hasher) + + _, err = io.Copy(writer, resp.Body) + if err != nil { + return errors.Wrap(err, "download snapshot") + } + + actualHash := hex.EncodeToString(hasher.Sum(nil)) + if actualHash != expectedHash { + return errors.Wrap( + fmt.Errorf( + "hash mismatch: expected %s, got %s", + expectedHash, + actualHash, + ), + "download snapshot", + ) + } + + zipReader, err := zip.OpenReader(tempFile.Name()) + if err != nil { + return fmt.Errorf("failed to open zip file: %w", err) + } + defer zipReader.Close() + + for _, file := range zipReader.File { + destPath := filepath.Join( + path.Join(dbPath, "snapshot"), + file.Name, + ) + if !strings.HasPrefix( + destPath, + filepath.Clean(path.Join(dbPath, "snapshot"))+string(os.PathSeparator), + ) { + return errors.Wrap( + fmt.Errorf("invalid file path in zip: %s", file.Name), + "download snapshot", + ) + } + + if file.FileInfo().IsDir() { + os.MkdirAll(destPath, file.Mode()) + continue + } + err := os.MkdirAll(filepath.Dir(destPath), 0755) + if err != nil { + return errors.Wrap( + fmt.Errorf( + "failed to create directory for file %s: %w", + file.Name, + err, + ), + "download snapshot", + ) + } + + destFile, err := os.OpenFile( + destPath, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode(), + ) + if err != nil { + return errors.Wrap( + fmt.Errorf("failed to create destination file %s: %w", file.Name, err), + "download snapshot", + ) + } + + srcFile, err := file.Open() + if err != nil { + destFile.Close() + return errors.Wrap( + fmt.Errorf("failed to open file in zip %s: %w", file.Name, err), + "download snapshot", + ) + } + + _, err = io.Copy(destFile, srcFile) + srcFile.Close() + destFile.Close() + if err != nil { + return errors.Wrap( + fmt.Errorf("failed to extract file %s: %w", file.Name, err), + "download snapshot", + ) + } + } + + return nil +} + +func (e *DataClockConsensusEngine) applySnapshot( + dbPath string, +) error { + dirEntries, err := os.ReadDir( + path.Join(dbPath, "snapshot"), + ) + if err != nil { + return errors.Wrap( + err, + "apply snapshot", + ) + } + defer os.RemoveAll(path.Join(dbPath, "snapshot")) + + snapshotDBPath := "" + for _, entry := range dirEntries { + if entry.IsDir() && strings.HasPrefix(entry.Name(), "exporter") { + snapshotDBPath = path.Join(path.Join(dbPath, "snapshot"), entry.Name()) + } + } + + if snapshotDBPath == "" { + return nil + } + + temporaryStore := store.NewPebbleDB(&config.DBConfig{ + Path: snapshotDBPath, + }) + temporaryClockStore := store.NewPebbleClockStore(temporaryStore, e.logger) + + max, _, err := e.clockStore.GetLatestDataClockFrame(e.filter) + if err != nil { + temporaryStore.Close() + return errors.Wrap( + err, + "apply snapshot", + ) + } + + key := []byte{store.CLOCK_FRAME, store.CLOCK_DATA_FRAME_DATA} + key = binary.BigEndian.AppendUint64(key, 0) + key = append(key, e.filter...) + + _, _, err = temporaryClockStore.GetDataClockFrame( + e.filter, + max.FrameNumber+1, + false, + ) + if err != nil { + fmt.Println("not found", max.FrameNumber+1) + temporaryStore.Close() + return errors.Wrap( + err, + "apply snapshot", + ) + } + + for i := max.FrameNumber + 1; true; i++ { + frame, _, err := temporaryClockStore.GetDataClockFrame( + e.filter, + i, + false, + ) + if err != nil { + break + } + + if err := e.handleClockFrame([]byte{}, []byte{}, frame); err != nil { + temporaryStore.Close() + return errors.Wrap( + err, + "apply snapshot", + ) + } + } + + temporaryStore.Close() + + e.logger.Info("imported snapshot") + + return nil +} diff --git a/node/consensus/data/main_data_loop.go b/node/consensus/data/main_data_loop.go new file mode 100644 index 0000000..55064b1 --- /dev/null +++ b/node/consensus/data/main_data_loop.go @@ -0,0 +1,361 @@ +package data + +import ( + "bytes" + "crypto/rand" + "time" + + "go.uber.org/zap" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +func ( + e *DataClockConsensusEngine, +) GetFrameProverTries() []*tries.RollingFrecencyCritbitTrie { + e.frameProverTriesMx.RLock() + frameProverTries := make( + []*tries.RollingFrecencyCritbitTrie, + len(e.frameProverTries), + ) + + for i, trie := range e.frameProverTries { + newTrie := &tries.RollingFrecencyCritbitTrie{} + b, err := trie.Serialize() + if err != nil { + panic(err) + } + + err = newTrie.Deserialize(b) + if err != nil { + panic(err) + } + frameProverTries[i] = newTrie + } + + e.frameProverTriesMx.RUnlock() + return frameProverTries +} + +func (e *DataClockConsensusEngine) runLoop() { + dataFrameCh := e.dataTimeReel.NewFrameCh() + + for e.state < consensus.EngineStateStopping { + peerCount := e.pubSub.GetNetworkPeersCount() + if peerCount < e.minimumPeersRequired { + e.logger.Info( + "waiting for minimum peers", + zap.Int("peer_count", peerCount), + ) + time.Sleep(1 * time.Second) + } else { + latestFrame, err := e.dataTimeReel.Head() + if err != nil { + panic(err) + } + + select { + case dataFrame := <-dataFrameCh: + e.logger.Info( + "current frame head", + zap.Uint64("frame_number", dataFrame.FrameNumber), + ) + if !e.IsInProverTrie(e.provingKeyBytes) { + if latestFrame, err = e.collect(dataFrame); err != nil { + e.logger.Error("could not collect", zap.Error(err)) + } + } + + if latestFrame != nil && + dataFrame.FrameNumber > latestFrame.FrameNumber { + latestFrame = dataFrame + } + + if e.latestFrameReceived < latestFrame.FrameNumber { + e.latestFrameReceived = latestFrame.FrameNumber + } + + trie := e.GetFrameProverTries()[0] + selBI, _ := dataFrame.GetSelector() + sel := make([]byte, 32) + sel = selBI.FillBytes(sel) + + if bytes.Equal( + trie.FindNearest(sel).External.Key, + e.provingKeyAddress, + ) { + var nextFrame *protobufs.ClockFrame + if nextFrame, err = e.prove(latestFrame); err != nil { + e.logger.Error("could not prove", zap.Error(err)) + e.state = consensus.EngineStateCollecting + continue + } + + // e.proverTrieRequestsMx.Lock() + // joinAddrs := tries.NewMinHeap[peerSeniorityItem]() + // leaveAddrs := tries.NewMinHeap[peerSeniorityItem]() + // for _, addr := range e.proverTrieJoinRequests { + // if _, ok := (*e.peerSeniority)[addr]; !ok { + // joinAddrs.Push(peerSeniorityItem{ + // addr: addr, + // seniority: 0, + // }) + // } else { + // joinAddrs.Push((*e.peerSeniority)[addr]) + // } + // } + // for _, addr := range e.proverTrieLeaveRequests { + // if _, ok := (*e.peerSeniority)[addr]; !ok { + // leaveAddrs.Push(peerSeniorityItem{ + // addr: addr, + // seniority: 0, + // }) + // } else { + // leaveAddrs.Push((*e.peerSeniority)[addr]) + // } + // } + // for _, addr := range e.proverTrieResumeRequests { + // if _, ok := e.proverTriePauseRequests[addr]; ok { + // delete(e.proverTriePauseRequests, addr) + // } + // } + + // joinReqs := make([]peerSeniorityItem, len(joinAddrs.All())) + // copy(joinReqs, joinAddrs.All()) + // slices.Reverse(joinReqs) + // leaveReqs := make([]peerSeniorityItem, len(leaveAddrs.All())) + // copy(leaveReqs, leaveAddrs.All()) + // slices.Reverse(leaveReqs) + + // e.proverTrieJoinRequests = make(map[string]string) + // e.proverTrieLeaveRequests = make(map[string]string) + // e.proverTrieRequestsMx.Unlock() + + // e.frameProverTriesMx.Lock() + // for _, addr := range joinReqs { + // rings := len(e.frameProverTries) + // last := e.frameProverTries[rings-1] + // set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) + // if len(set) == 1024 { + // e.frameProverTries = append( + // e.frameProverTries, + // &tries.RollingFrecencyCritbitTrie{}, + // ) + // last = e.frameProverTries[rings] + // } + // last.Add([]byte(addr.addr), nextFrame.FrameNumber) + // } + // for _, addr := range leaveReqs { + // for _, t := range e.frameProverTries { + // if bytes.Equal( + // t.FindNearest([]byte(addr.addr)).External.Key, + // []byte(addr.addr), + // ) { + // t.Remove([]byte(addr.addr)) + // break + // } + // } + // } + // e.frameProverTriesMx.Unlock() + + e.dataTimeReel.Insert(nextFrame, true) + + if err = e.publishProof(nextFrame); err != nil { + e.logger.Error("could not publish", zap.Error(err)) + e.state = consensus.EngineStateCollecting + } + break + } + case <-time.After(20 * time.Second): + dataFrame, err := e.dataTimeReel.Head() + if err != nil { + panic(err) + } + + e.logger.Info( + "current frame head", + zap.Uint64("frame_number", dataFrame.FrameNumber), + ) + + if !e.IsInProverTrie(e.provingKeyBytes) { + if latestFrame, err = e.collect(dataFrame); err != nil { + e.logger.Error("could not collect", zap.Error(err)) + } + } + + if latestFrame == nil || + latestFrame.FrameNumber < dataFrame.FrameNumber { + latestFrame, err = e.dataTimeReel.Head() + if err != nil { + panic(err) + } + } + + if e.latestFrameReceived < latestFrame.FrameNumber { + e.latestFrameReceived = latestFrame.FrameNumber + } + + for _, trie := range e.GetFrameProverTries() { + if bytes.Equal( + trie.FindNearest(e.provingKeyAddress).External.Key, + e.provingKeyAddress, + ) { + var nextFrame *protobufs.ClockFrame + if nextFrame, err = e.prove(latestFrame); err != nil { + e.logger.Error("could not prove", zap.Error(err)) + e.state = consensus.EngineStateCollecting + continue + } + + // e.proverTrieRequestsMx.Lock() + // joinAddrs := tries.NewMinHeap[peerSeniorityItem]() + // leaveAddrs := tries.NewMinHeap[peerSeniorityItem]() + // for _, addr := range e.proverTrieJoinRequests { + // if _, ok := (*e.peerSeniority)[addr]; !ok { + // joinAddrs.Push(peerSeniorityItem{ + // addr: addr, + // seniority: 0, + // }) + // } else { + // joinAddrs.Push((*e.peerSeniority)[addr]) + // } + // } + // for _, addr := range e.proverTrieLeaveRequests { + // if _, ok := (*e.peerSeniority)[addr]; !ok { + // leaveAddrs.Push(peerSeniorityItem{ + // addr: addr, + // seniority: 0, + // }) + // } else { + // leaveAddrs.Push((*e.peerSeniority)[addr]) + // } + // } + // for _, addr := range e.proverTrieResumeRequests { + // if _, ok := e.proverTriePauseRequests[addr]; ok { + // delete(e.proverTriePauseRequests, addr) + // } + // } + + // joinReqs := make([]peerSeniorityItem, len(joinAddrs.All())) + // copy(joinReqs, joinAddrs.All()) + // slices.Reverse(joinReqs) + // leaveReqs := make([]peerSeniorityItem, len(leaveAddrs.All())) + // copy(leaveReqs, leaveAddrs.All()) + // slices.Reverse(leaveReqs) + + // e.proverTrieJoinRequests = make(map[string]string) + // e.proverTrieLeaveRequests = make(map[string]string) + // e.proverTrieRequestsMx.Unlock() + + // e.frameProverTriesMx.Lock() + // for _, addr := range joinReqs { + // rings := len(e.frameProverTries) + // last := e.frameProverTries[rings-1] + // set := last.FindNearestAndApproximateNeighbors(make([]byte, 32)) + // if len(set) == 8 { + // e.frameProverTries = append( + // e.frameProverTries, + // &tries.RollingFrecencyCritbitTrie{}, + // ) + // last = e.frameProverTries[rings] + // } + // last.Add([]byte(addr.addr), nextFrame.FrameNumber) + // } + // for _, addr := range leaveReqs { + // for _, t := range e.frameProverTries { + // if bytes.Equal( + // t.FindNearest([]byte(addr.addr)).External.Key, + // []byte(addr.addr), + // ) { + // t.Remove([]byte(addr.addr)) + // break + // } + // } + // } + // e.frameProverTriesMx.Unlock() + + e.dataTimeReel.Insert(nextFrame, true) + + if err = e.publishProof(nextFrame); err != nil { + e.logger.Error("could not publish", zap.Error(err)) + e.state = consensus.EngineStateCollecting + } + break + } + } + } + } + } +} + +func (e *DataClockConsensusEngine) rebroadcastLoop() { + if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + time.Sleep(120 * time.Second) + for { + _, err := e.dataTimeReel.Head() + if err != nil { + e.logger.Info("no frames to rebroadcast yet, waiting...") + time.Sleep(10 * time.Second) + continue + } + + max, _, err := e.clockStore.GetLatestDataClockFrame(e.filter) + frames := []*protobufs.ClockFrame{} + sent := false + for i := uint64(1); i < max.FrameNumber; i++ { + if e.state == consensus.EngineStateStopped || + e.state == consensus.EngineStateStopping { + e.logger.Info("shutting down rebroadcaster") + return + } + frame, _, err := e.clockStore.GetDataClockFrame(e.filter, i, false) + if err != nil { + frames = []*protobufs.ClockFrame{} + e.logger.Error("error while iterating", zap.Error(err)) + break + } + + if frame == nil { + frames = []*protobufs.ClockFrame{} + e.logger.Error("too far ahead", zap.Error(err)) + break + } + + frames = append(frames, frame) + if i%50 == 0 { + e.logger.Info( + "rebroadcasting frames", + zap.Uint64("from", frames[0].FrameNumber), + zap.Uint64("to", frames[len(frames)-1].FrameNumber), + ) + e.publishMessage(e.filter, &protobufs.FrameRebroadcast{ + From: frames[0].FrameNumber, + To: frames[len(frames)-1].FrameNumber, + ClockFrames: frames, + }) + time.Sleep(60 * time.Second) + sent = true + frames = []*protobufs.ClockFrame{} + } + } + + if !sent && len(frames) != 0 { + e.logger.Info( + "rebroadcasting frames", + zap.Uint64("from", frames[0].FrameNumber), + zap.Uint64("to", frames[len(frames)-1].FrameNumber), + ) + b := make([]byte, 24) + rand.Read(b) + e.publishMessage(e.filter, &protobufs.FrameRebroadcast{ + From: frames[0].FrameNumber, + To: frames[len(frames)-1].FrameNumber, + ClockFrames: frames, + Random: b, + }) + time.Sleep(60 * time.Second) + } + } + } +} diff --git a/node/consensus/data/message_handler.go b/node/consensus/data/message_handler.go index 893f481..6fee6c0 100644 --- a/node/consensus/data/message_handler.go +++ b/node/consensus/data/message_handler.go @@ -13,6 +13,7 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) @@ -24,23 +25,17 @@ func (e *DataClockConsensusEngine) runMessageHandler() { msg := &protobufs.Message{} if err := proto.Unmarshal(message.Data, msg); err != nil { + e.logger.Debug("bad message") continue } - e.peerMapMx.RLock() - peer, ok := e.peerMap[string(message.From)] - e.peerMapMx.RUnlock() - - if ok && bytes.Compare(peer.version, config.GetMinimumVersion()) >= 0 && - bytes.Equal( - e.frameProverTries[0].FindNearest(e.provingKeyAddress).External.Key, - e.provingKeyAddress, - ) && e.syncingStatus == SyncStatusNotSyncing { + if e.frameProverTries[0].Contains(e.provingKeyAddress) && + e.syncingStatus == SyncStatusNotSyncing { for name := range e.executionEngines { name := name go func() error { messages, err := e.executionEngines[name].ProcessMessage( - msg.Address, + application.TOKEN_ADDRESS, msg, ) if err != nil { @@ -64,6 +59,8 @@ func (e *DataClockConsensusEngine) runMessageHandler() { continue } + e.logger.Debug(appMsg.TypeUrl) + switch appMsg.TypeUrl { case protobufs.TokenRequestType: t := &protobufs.TokenRequest{} @@ -88,74 +85,206 @@ func (e *DataClockConsensusEngine) runMessageHandler() { e.logger.Error("error while unmarshaling", zap.Error(err)) continue } + e.logger.Debug("message type", zap.String("type", any.TypeUrl)) go func() { switch any.TypeUrl { - case protobufs.ClockFrameType: - if !ok || bytes.Compare( - peer.version, - config.GetMinimumVersion(), - ) < 0 { - e.logger.Debug("received frame from unknown or outdated peer") - return - } - if err := e.handleClockFrameData( + case protobufs.FrameRebroadcastType: + if err := e.handleRebroadcast( message.From, msg.Address, any, - false, ); err != nil { return } - case protobufs.DataPeerListAnnounceType: - if err := e.handleDataPeerListAnnounce( - message.From, - msg.Address, - any, - ); err != nil { - return - } - case protobufs.AnnounceProverJoinType: - if err := e.handleDataAnnounceProverJoin( + case protobufs.ClockFrameType: + if err := e.handleClockFrameData( message.From, msg.Address, any, + false, ); err != nil { return } - case protobufs.AnnounceProverLeaveType: - if !e.IsInProverTrie(peer.peerId) { - return - } - if err := e.handleDataAnnounceProverLeave( + case protobufs.DataPeerListAnnounceType: + if err := e.handleDataPeerListAnnounce( message.From, msg.Address, any, ); err != nil { return } + // case protobufs.AnnounceProverJoinType: + // if err := e.handleDataAnnounceProverJoin( + // message.From, + // msg.Address, + // any, + // ); err != nil { + // return + // } + // case protobufs.AnnounceProverLeaveType: + // if !e.IsInProverTrie(peer.peerId) { + // return + // } + // if err := e.handleDataAnnounceProverLeave( + // message.From, + // msg.Address, + // any, + // ); err != nil { + // return + // } case protobufs.AnnounceProverPauseType: - if err := e.handleDataAnnounceProverPause( - message.From, - msg.Address, - any, - ); err != nil { - return - } + // stop spamming + e.pubSub.AddPeerScore(message.From, -1000) + // if err := e.handleDataAnnounceProverPause( + // message.From, + // msg.Address, + // any, + // ); err != nil { + // return + // } case protobufs.AnnounceProverResumeType: - if err := e.handleDataAnnounceProverResume( - message.From, - msg.Address, - any, - ); err != nil { - return - } + // stop spamming + e.pubSub.AddPeerScore(message.From, -1000) + // if err := e.handleDataAnnounceProverResume( + // message.From, + // msg.Address, + // any, + // ); err != nil { + // return + // } } }() } } } +func (e *DataClockConsensusEngine) handleRebroadcast( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + if bytes.Equal(peerID, e.pubSub.GetPeerID()) { + return nil + } + + frames := &protobufs.FrameRebroadcast{} + if err := any.UnmarshalTo(frames); err != nil { + return errors.Wrap(err, "handle clock frame data") + } + + head, err := e.dataTimeReel.Head() + if err != nil { + return nil + } + + e.logger.Debug( + "received rebroadcast", + zap.Uint64("from", frames.From), + zap.Uint64("to", frames.To), + ) + if head.FrameNumber+1 < frames.From { + return nil + } + + if head.FrameNumber > frames.To { + return nil + } + + for _, frame := range frames.ClockFrames { + if head.FrameNumber >= frame.FrameNumber { + continue + } + + e.logger.Info("receiving synchronization data") + + if err := e.handleClockFrame(peerID, address, frame); err != nil { + // if they're sending invalid clock frames, nuke them. + e.pubSub.AddPeerScore(peerID, -100000) + return errors.Wrap(err, "handle rebroadcast") + } + } + + return nil +} + +func (e *DataClockConsensusEngine) handleClockFrame( + peerID []byte, + address []byte, + frame *protobufs.ClockFrame, +) error { + if frame == nil { + return errors.Wrap(errors.New("frame is nil"), "handle clock frame") + } + + addr, err := poseidon.HashBytes( + frame.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "handle clock frame data") + } + + trie := e.GetFrameProverTries()[0] + if !trie.Contains(addr.Bytes()) { + e.logger.Debug( + "prover not in trie at frame, address may be in fork", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + return nil + } + + e.logger.Debug( + "got clock frame", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + zap.Int("proof_count", len(frame.AggregateProofs)), + ) + + if err := e.frameProver.VerifyDataClockFrame(frame); err != nil { + e.logger.Debug("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + e.logger.Debug( + "clock frame was valid", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + + head, err := e.dataTimeReel.Head() + if err != nil { + panic(err) + } + + if frame.FrameNumber > head.FrameNumber { + e.dataTimeReel.Insert(frame, false) + } + + return nil +} + +func (e *DataClockConsensusEngine) handleClockFrameData( + peerID []byte, + address []byte, + any *anypb.Any, + isSync bool, +) error { + if bytes.Equal(peerID, e.pubSub.GetPeerID()) { + return nil + } + + frame := &protobufs.ClockFrame{} + if err := any.UnmarshalTo(frame); err != nil { + return errors.Wrap(err, "handle clock frame data") + } + + return e.handleClockFrame(peerID, address, frame) +} + func (e *DataClockConsensusEngine) handleDataPeerListAnnounce( peerID []byte, address []byte, @@ -218,7 +347,7 @@ func (e *DataClockConsensusEngine) handleDataPeerListAnnounce( "peer provided outdated version, penalizing app score", zap.Binary("peer_id", p.PeerId), ) - e.pubSub.SetPeerScore(p.PeerId, -10000) + e.pubSub.SetPeerScore(p.PeerId, -1000000) continue } } @@ -288,187 +417,187 @@ func (e *DataClockConsensusEngine) getAddressFromSignature( return addrBI.FillBytes(make([]byte, 32)), nil } -func (e *DataClockConsensusEngine) handleDataAnnounceProverJoin( - peerID []byte, - address []byte, - any *anypb.Any, -) error { - if e.GetFrameProverTries()[0].Contains(e.parentSelector) { - announce := &protobufs.AnnounceProverJoin{} - if err := any.UnmarshalTo(announce); err != nil { - return errors.Wrap(err, "handle data announce prover join") - } - - if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { - return errors.Wrap( - errors.New("invalid data"), - "handle data announce prover join", - ) - } - - address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) - if err != nil { - return errors.Wrap(err, "handle data announce prover join") - } - - msg := []byte("join") - msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) - msg = append(msg, announce.Filter...) - if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { - return errors.Wrap(err, "handle data announce prover join") - } - - e.proverTrieRequestsMx.Lock() - if len(announce.Filter) != len(e.filter) { - return errors.Wrap( - errors.New("filter width mismatch"), - "handle data announce prover join", - ) - } - - e.proverTrieJoinRequests[string(address)] = string(announce.Filter) - e.proverTrieRequestsMx.Unlock() - } - return nil -} - -func (e *DataClockConsensusEngine) handleDataAnnounceProverLeave( - peerID []byte, - address []byte, - any *anypb.Any, -) error { - if e.GetFrameProverTries()[0].Contains(e.parentSelector) { - announce := &protobufs.AnnounceProverLeave{} - if err := any.UnmarshalTo(announce); err != nil { - return errors.Wrap(err, "handle data announce prover leave") - } - - if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { - return errors.Wrap( - errors.New("invalid data"), - "handle data announce prover leave", - ) - } - - e.proverTrieRequestsMx.Lock() - - if len(announce.Filter) != len(e.filter) { - return errors.Wrap( - errors.New("filter width mismatch"), - "handle data announce prover leave", - ) - } - - msg := []byte("leave") - msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) - msg = append(msg, announce.Filter...) - if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { - return errors.Wrap(err, "handle data announce prover leave") - } - - address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) - if err != nil { - return errors.Wrap(err, "handle data announce prover leave") - } - - e.proverTrieLeaveRequests[string(address)] = string(announce.Filter) - e.proverTrieRequestsMx.Unlock() - } - return nil -} - -func (e *DataClockConsensusEngine) handleDataAnnounceProverPause( - peerID []byte, - address []byte, - any *anypb.Any, -) error { - if e.GetFrameProverTries()[0].Contains(e.parentSelector) { - announce := &protobufs.AnnounceProverPause{} - if err := any.UnmarshalTo(announce); err != nil { - return errors.Wrap(err, "handle data announce prover pause") - } - - if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { - return errors.Wrap( - errors.New("invalid data"), - "handle data announce prover leave", - ) - } - - e.proverTrieRequestsMx.Lock() - if len(announce.Filter) != len(e.filter) { - return errors.Wrap( - errors.New("filter width mismatch"), - "handle data announce prover pause", - ) - } - - msg := []byte("pause") - msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) - msg = append(msg, announce.Filter...) - if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { - return errors.Wrap(err, "handle data announce prover pause") - } - - address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) - if err != nil { - return errors.Wrap(err, "handle data announce prover pause") - } - - e.proverTriePauseRequests[string(address)] = string(announce.Filter) - e.proverTrieRequestsMx.Unlock() - } - return nil -} - -func (e *DataClockConsensusEngine) handleDataAnnounceProverResume( - peerID []byte, - address []byte, - any *anypb.Any, -) error { - if e.GetFrameProverTries()[0].Contains(e.parentSelector) { - announce := &protobufs.AnnounceProverResume{} - if err := any.UnmarshalTo(announce); err != nil { - return errors.Wrap(err, "handle data announce prover resume") - } - - if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { - return errors.Wrap( - errors.New("invalid data"), - "handle data announce prover resume", - ) - } - - e.proverTrieRequestsMx.Lock() - if len(announce.Filter) != len(e.filter) { - return errors.Wrap( - errors.New("filter width mismatch"), - "handle data announce prover resume", - ) - } - - address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) - if err != nil { - return errors.Wrap(err, "handle data announce prover resume") - } - - msg := []byte("resume") - msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) - msg = append(msg, announce.Filter...) - if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { - return errors.Wrap(err, "handle data announce prover resume") - } - - e.proverTrieResumeRequests[string(address)] = string(announce.Filter) - e.proverTrieRequestsMx.Unlock() - } - return nil -} +// func (e *DataClockConsensusEngine) handleDataAnnounceProverJoin( +// peerID []byte, +// address []byte, +// any *anypb.Any, +// ) error { +// if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { +// announce := &protobufs.AnnounceProverJoin{} +// if err := any.UnmarshalTo(announce); err != nil { +// return errors.Wrap(err, "handle data announce prover join") +// } + +// if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { +// return errors.Wrap( +// errors.New("invalid data"), +// "handle data announce prover join", +// ) +// } + +// address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) +// if err != nil { +// return errors.Wrap(err, "handle data announce prover join") +// } + +// msg := []byte("join") +// msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) +// msg = append(msg, announce.Filter...) +// if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { +// return errors.Wrap(err, "handle data announce prover join") +// } + +// e.proverTrieRequestsMx.Lock() +// if len(announce.Filter) != len(e.filter) { +// return errors.Wrap( +// errors.New("filter width mismatch"), +// "handle data announce prover join", +// ) +// } + +// e.proverTrieJoinRequests[string(address)] = string(announce.Filter) +// e.proverTrieRequestsMx.Unlock() +// } +// return nil +// } + +// func (e *DataClockConsensusEngine) handleDataAnnounceProverLeave( +// peerID []byte, +// address []byte, +// any *anypb.Any, +// ) error { +// if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { +// announce := &protobufs.AnnounceProverLeave{} +// if err := any.UnmarshalTo(announce); err != nil { +// return errors.Wrap(err, "handle data announce prover leave") +// } + +// if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { +// return errors.Wrap( +// errors.New("invalid data"), +// "handle data announce prover leave", +// ) +// } + +// e.proverTrieRequestsMx.Lock() + +// if len(announce.Filter) != len(e.filter) { +// return errors.Wrap( +// errors.New("filter width mismatch"), +// "handle data announce prover leave", +// ) +// } + +// msg := []byte("leave") +// msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) +// msg = append(msg, announce.Filter...) +// if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { +// return errors.Wrap(err, "handle data announce prover leave") +// } + +// address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) +// if err != nil { +// return errors.Wrap(err, "handle data announce prover leave") +// } + +// e.proverTrieLeaveRequests[string(address)] = string(announce.Filter) +// e.proverTrieRequestsMx.Unlock() +// } +// return nil +// } + +// func (e *DataClockConsensusEngine) handleDataAnnounceProverPause( +// peerID []byte, +// address []byte, +// any *anypb.Any, +// ) error { +// if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { +// announce := &protobufs.AnnounceProverPause{} +// if err := any.UnmarshalTo(announce); err != nil { +// return errors.Wrap(err, "handle data announce prover pause") +// } + +// if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { +// return errors.Wrap( +// errors.New("invalid data"), +// "handle data announce prover leave", +// ) +// } + +// e.proverTrieRequestsMx.Lock() +// if len(announce.Filter) != len(e.filter) { +// return errors.Wrap( +// errors.New("filter width mismatch"), +// "handle data announce prover pause", +// ) +// } + +// msg := []byte("pause") +// msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) +// msg = append(msg, announce.Filter...) +// if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { +// return errors.Wrap(err, "handle data announce prover pause") +// } + +// address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) +// if err != nil { +// return errors.Wrap(err, "handle data announce prover pause") +// } + +// e.proverTriePauseRequests[string(address)] = string(announce.Filter) +// e.proverTrieRequestsMx.Unlock() +// } +// return nil +// } + +// func (e *DataClockConsensusEngine) handleDataAnnounceProverResume( +// peerID []byte, +// address []byte, +// any *anypb.Any, +// ) error { +// if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { +// announce := &protobufs.AnnounceProverResume{} +// if err := any.UnmarshalTo(announce); err != nil { +// return errors.Wrap(err, "handle data announce prover resume") +// } + +// if announce.PublicKeySignatureEd448 == nil || announce.Filter == nil { +// return errors.Wrap( +// errors.New("invalid data"), +// "handle data announce prover resume", +// ) +// } + +// e.proverTrieRequestsMx.Lock() +// if len(announce.Filter) != len(e.filter) { +// return errors.Wrap( +// errors.New("filter width mismatch"), +// "handle data announce prover resume", +// ) +// } + +// address, err := e.getAddressFromSignature(announce.PublicKeySignatureEd448) +// if err != nil { +// return errors.Wrap(err, "handle data announce prover resume") +// } + +// msg := []byte("resume") +// msg = binary.BigEndian.AppendUint64(msg, announce.FrameNumber) +// msg = append(msg, announce.Filter...) +// if err := announce.GetPublicKeySignatureEd448().Verify(msg); err != nil { +// return errors.Wrap(err, "handle data announce prover resume") +// } + +// e.proverTrieResumeRequests[string(address)] = string(announce.Filter) +// e.proverTrieRequestsMx.Unlock() +// } +// return nil +// } func (e *DataClockConsensusEngine) handleTokenRequest( transition *protobufs.TokenRequest, ) error { - if e.GetFrameProverTries()[0].Contains(e.parentSelector) { + if e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { e.stagedTransactionsMx.Lock() if e.stagedTransactions == nil { e.stagedTransactions = &protobufs.TokenRequests{} @@ -509,10 +638,12 @@ func (e *DataClockConsensusEngine) handleTokenRequest( case *protobufs.TokenRequest_Mint: checkmint: for i := range t.Mint.Proofs { - for j := range r.Mint.Proofs { - if bytes.Equal(t.Mint.Proofs[i], r.Mint.Proofs[j]) { - found = true - break checkmint + if len(r.Mint.Proofs) < 2 { + for j := range r.Mint.Proofs { + if bytes.Equal(t.Mint.Proofs[i], r.Mint.Proofs[j]) { + found = true + break checkmint + } } } } @@ -531,82 +662,14 @@ func (e *DataClockConsensusEngine) handleTokenRequest( return nil } -func (e *DataClockConsensusEngine) handleClockFrameData( - peerID []byte, - address []byte, - any *anypb.Any, - isSync bool, -) error { - frame := &protobufs.ClockFrame{} - if err := any.UnmarshalTo(frame); err != nil { - return errors.Wrap(err, "handle clock frame data") - } - - if e.latestFrameReceived > frame.FrameNumber { - return nil - } - - addr, err := poseidon.HashBytes( - frame.GetPublicKeySignatureEd448().PublicKey.KeyValue, - ) - if err != nil { - return errors.Wrap(err, "handle clock frame data") - } - - for _, trie := range e.GetFrameProverTries() { - if trie.Contains(addr.Bytes()) { - e.logger.Info( - "prover not in trie at frame, address may be in fork", - zap.Binary("address", address), - zap.Binary("filter", frame.Filter), - zap.Uint64("frame_number", frame.FrameNumber), - ) - return nil - } +func nearestApplicablePowerOfTwo(number uint64) uint64 { + power := uint64(128) + if number > 2048 { + power = 65536 + } else if number > 1024 { + power = 2048 + } else if number > 128 { + power = 1024 } - - e.logger.Info( - "got clock frame", - zap.Binary("address", address), - zap.Binary("filter", frame.Filter), - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("proof_count", len(frame.AggregateProofs)), - ) - - if err := e.frameProver.VerifyDataClockFrame(frame); err != nil { - e.logger.Error("could not verify clock frame", zap.Error(err)) - return errors.Wrap(err, "handle clock frame data") - } - - if err := e.inclusionProver.VerifyFrame(frame); err != nil { - e.logger.Error("could not verify clock frame", zap.Error(err)) - return errors.Wrap(err, "handle clock frame data") - } - - e.logger.Info( - "clock frame was valid", - zap.Binary("address", address), - zap.Binary("filter", frame.Filter), - zap.Uint64("frame_number", frame.FrameNumber), - ) - - if e.latestFrameReceived < frame.FrameNumber { - e.latestFrameReceived = frame.FrameNumber - go func() { - select { - case e.frameChan <- frame: - default: - } - }() - } - - head, err := e.dataTimeReel.Head() - if err != nil { - panic(err) - } - - if frame.FrameNumber > head.FrameNumber { - e.dataTimeReel.Insert(frame, e.latestFrameReceived < frame.FrameNumber) - } - return nil + return power } diff --git a/node/consensus/data/peer_messaging.go b/node/consensus/data/peer_messaging.go index d3b40f8..d6fc5e0 100644 --- a/node/consensus/data/peer_messaging.go +++ b/node/consensus/data/peer_messaging.go @@ -3,14 +3,19 @@ package data import ( "bytes" "context" + "encoding/binary" + "math/big" "time" + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" "github.com/mr-tron/base58" "github.com/pkg/errors" "go.uber.org/zap" + "golang.org/x/crypto/sha3" "google.golang.org/grpc" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/node/crypto" "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" @@ -53,28 +58,8 @@ func (e *DataClockConsensusEngine) GetDataFrame( return nil, errors.Wrap(err, "get data frame") } - idx, err := e.frameProver.GenerateWeakRecursiveProofIndex(frame) - if err != nil { - return nil, errors.Wrap(err, "get data frame") - } - - indexFrame, _, err := e.clockStore.GetDataClockFrame(e.filter, idx, false) - if err != nil { - return &protobufs.DataFrameResponse{ - ClockFrame: frame, - }, nil - } - - proof := e.frameProver.FetchRecursiveProof(indexFrame) - - e.logger.Debug( - "sending frame response", - zap.Uint64("frame_number", frame.FrameNumber), - ) - return &protobufs.DataFrameResponse{ ClockFrame: frame, - Proof: proof, }, nil } @@ -110,196 +95,464 @@ func (e *DataClockConsensusEngine) GetCompressedSyncFrames( return nil } -func (e *DataClockConsensusEngine) decompressAndStoreCandidates( - peerId []byte, - syncMsg *protobufs.DataCompressedSync, -) (*protobufs.ClockFrame, error) { - if len(syncMsg.TruncatedClockFrames) == 0 { - return nil, ErrNoNewFrames - } - - head, err := e.dataTimeReel.Head() +func (e *DataClockConsensusEngine) HandlePreMidnightMint( + ctx context.Context, + t *protobufs.MintCoinRequest, +) (*protobufs.PreMidnightMintResponse, error) { + addr, err := e.handleMint(t) if err != nil { - panic(err) + e.logger.Error("error while handling pre-midnight mint", zap.Error(err)) + return nil, err } - if len(syncMsg.TruncatedClockFrames) < int( - syncMsg.ToFrameNumber-syncMsg.FromFrameNumber+1, - ) { - e.peerMapMx.Lock() - if _, ok := e.peerMap[string(peerId)]; ok { - e.uncooperativePeersMap[string(peerId)] = e.peerMap[string(peerId)] - e.uncooperativePeersMap[string(peerId)].timestamp = time.Now().UnixMilli() - delete(e.peerMap, string(peerId)) - } - e.peerMapMx.Unlock() - return nil, errors.New("invalid continuity for compressed x response") + return &protobufs.PreMidnightMintResponse{Address: addr}, nil +} + +func (e *DataClockConsensusEngine) GetPreMidnightMintStatus( + ctx context.Context, + t *protobufs.PreMidnightMintStatusRequest, +) (*protobufs.PreMidnightMintResponse, error) { + if !e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + return nil, errors.Wrap( + errors.New("wrong destination"), + "get pre midnight mint status", + ) } - var final *protobufs.ClockFrame - for _, frame := range syncMsg.TruncatedClockFrames { - frame := frame - commits := (len(frame.Input) - 516) / 74 - e.logger.Info( - "processing frame", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("aggregate_commits", commits), + if len(t.Owner) != 32 { + return nil, errors.Wrap( + errors.New("invalid data"), + "get pre midnight mint status", ) - for j := 0; j < commits; j++ { - e.logger.Debug( - "processing commit", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - ) - commit := frame.Input[516+(j*74) : 516+((j+1)*74)] - var aggregateProof *protobufs.InclusionProofsMap - for _, a := range syncMsg.Proofs { - a := a - if bytes.Equal(a.FrameCommit, commit) { - e.logger.Info( - "found matching proof", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), + } + fr, pre, err := e.coinStore.GetPreCoinProofsForOwner(t.Owner) + if err != nil { + return nil, errors.Wrap( + errors.New("invalid data"), + "get pre midnight mint status", + ) + } + + if len(fr) == 0 { + return &protobufs.PreMidnightMintResponse{ + Address: make([]byte, 32), + Increment: 0, + }, nil + } else { + for _, pr := range pre { + addr, err := GetAddressOfPreCoinProof(pr) + if err != nil { + if err != nil { + return nil, errors.Wrap( + errors.New("invalid data"), + "get pre midnight mint status", ) - aggregateProof = a - break } } - if aggregateProof == nil { - e.logger.Error( - "could not find matching proof", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - zap.Binary("proof", aggregateProof.Proof), - ) + + return &protobufs.PreMidnightMintResponse{ + Address: addr, + Increment: pr.Difficulty, + }, nil + } + } + + return &protobufs.PreMidnightMintResponse{ + Address: make([]byte, 32), + Increment: 0, + }, nil +} + +func (e *DataClockConsensusEngine) handleMint( + t *protobufs.MintCoinRequest, +) ([]byte, error) { + if !e.GetFrameProverTries()[0].Contains(e.provingKeyAddress) { + return nil, errors.Wrap(errors.New("wrong destination"), "handle mint") + } + + returnAddr := []byte{} + e.preMidnightMintMx.Lock() + if _, active := e.preMidnightMint[string( + t.Signature.PublicKey.KeyValue, + )]; active { + return nil, errors.Wrap(errors.New("busy"), "handle mint") + } + e.preMidnightMint[string( + t.Signature.PublicKey.KeyValue, + )] = struct{}{} + e.preMidnightMintMx.Unlock() + + defer func() { + e.preMidnightMintMx.Lock() + delete(e.preMidnightMint, string( + t.Signature.PublicKey.KeyValue, + )) + e.preMidnightMintMx.Unlock() + }() + + head, err := e.dataTimeReel.Head() + if err != nil { + return nil, errors.Wrap(errors.New("busy"), "handle mint") + } + + if t == nil || t.Proofs == nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + payload := []byte("mint") + for _, p := range t.Proofs { + payload = append(payload, p...) + } + if err := t.Signature.Verify(payload); err != nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + e.logger.Debug( + "got pre-midnight mint request", + zap.String("peer", peerId.String()), + ) + + if len(t.Proofs) >= 3 && + len(t.Proofs) < 204 && + bytes.Equal( + t.Proofs[0], + []byte("pre-dusk"), + ) && (!bytes.Equal(t.Proofs[1], make([]byte, 32)) || + head.FrameNumber < 67000) && e.GetFrameProverTries()[0].Contains( + e.provingKeyAddress, + ) { + prevInput := []byte{} + prevErrorMetric := uint32(0) + highestIncrement := uint32(0) + deletes := []*protobufs.TokenOutput{} + if !bytes.Equal(t.Proofs[1], make([]byte, 32)) { + pre, err := e.coinStore.GetPreCoinProofByAddress(t.Proofs[1]) + if err != nil { return nil, errors.Wrap( - store.ErrInvalidData, - "decompress and store candidates", + application.ErrInvalidStateTransition, + "handle mint", ) } - inc := &protobufs.InclusionAggregateProof{ - Filter: e.filter, - FrameNumber: frame.FrameNumber, - InclusionCommitments: []*protobufs.InclusionCommitment{}, - Proof: aggregateProof.Proof, + if !bytes.Equal( + pre.Owner.GetImplicitAccount().Address, + altAddr.FillBytes(make([]byte, 32)), + ) { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") } - - for k, c := range aggregateProof.Commitments { - k := k - c := c - e.logger.Debug( - "adding inclusion commitment", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - zap.Int("inclusion_commit_index", k), - zap.String("type_url", c.TypeUrl), + if pre.Difficulty == 0 { + _, pr, err := e.coinStore.GetPreCoinProofsForOwner( + altAddr.FillBytes(make([]byte, 32)), ) - incCommit := &protobufs.InclusionCommitment{ - Filter: e.filter, - FrameNumber: frame.FrameNumber, - Position: uint32(k), - TypeUrl: c.TypeUrl, - Data: []byte{}, - Commitment: c.Commitment, - } - var output *protobufs.IntrinsicExecutionOutput - if c.TypeUrl == protobufs.IntrinsicExecutionOutputType { - output = &protobufs.IntrinsicExecutionOutput{} + if err != nil && !errors.Is(err, store.ErrNotFound) { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") } - for l, h := range c.SegmentHashes { - l := l - h := h - - for _, s := range syncMsg.Segments { - s := s - - if bytes.Equal(s.Hash, h) { - if output != nil { - if l == 0 { - e.logger.Debug( - "found first half of matching segment data", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - zap.Int("inclusion_commit_index", k), - zap.String("type_url", c.TypeUrl), - ) - output.Address = s.Data[:32] - output.Output = s.Data[32:] - } else { - e.logger.Debug( - "found second half of matching segment data", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - zap.Int("inclusion_commit_index", k), - zap.String("type_url", c.TypeUrl), - ) - output.Proof = s.Data - b, err := proto.Marshal(output) - if err != nil { - return nil, errors.Wrap( - err, - "decompress and store candidates", - ) - } - incCommit.Data = b - break - } - } else { - e.logger.Debug( - "found matching segment data", - zap.Uint64("frame_number", frame.FrameNumber), - zap.Int("commit_index", j), - zap.Int("inclusion_commit_index", k), - zap.String("type_url", c.TypeUrl), - ) - incCommit.Data = append(incCommit.Data, s.Data...) - break - } - } + + for _, p := range pr { + if p.IndexProof != nil { + continue + } + if bytes.Equal(p.Amount, pre.Amount) { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") } } - inc.InclusionCommitments = append( - inc.InclusionCommitments, - incCommit, + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } else { + deletes = append(deletes, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_DeletedProof{ + DeletedProof: pre, + }, + }) + } + prevInput = pre.Proof[74:148] + prevErrorMetric = binary.BigEndian.Uint32(pre.Proof[148:152]) + highestIncrement = binary.BigEndian.Uint32(pre.Proof[152:156]) + } + + var previousIncrement = uint32(0xFFFFFFFF) + reward := new(big.Int) + var index uint32 + var indexProof []byte + var parallelism uint32 + var kzgCommitment []byte + var kzgProof []byte + for pi, data := range t.Proofs[2:] { + if len(data) < 28 { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + increment := binary.BigEndian.Uint32(data[:4]) + parallelism = binary.BigEndian.Uint32(data[4:8]) + inputLen := binary.BigEndian.Uint64(data[8:16]) + + if len(deletes) != 0 && pi == 0 { + if deletes[0].GetDeletedProof().Difficulty-1 != increment { + return nil, errors.Wrap( + application.ErrInvalidStateTransition, + "handle mint", + ) + } + } else if pi == 0 && bytes.Equal(t.Proofs[1], make([]byte, 32)) { + frames, _, err := e.coinStore.GetPreCoinProofsForOwner( + altAddr.FillBytes(make([]byte, 32)), ) + if err != nil || len(frames) != 0 { + return nil, errors.Wrap( + application.ErrInvalidStateTransition, + "handle mint", + ) + } + } else if pi != 0 { + if increment != previousIncrement-1 { + return nil, errors.Wrap( + application.ErrInvalidStateTransition, + "handle mint", + ) + } + } + previousIncrement = increment + + if uint64(len(data[16:])) < inputLen+8 { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + input := make([]byte, inputLen) + copy(input[:], data[16:16+inputLen]) + + outputLen := binary.BigEndian.Uint64(data[16+inputLen : 16+inputLen+8]) + + if uint64(len(data[16+inputLen+8:])) < outputLen { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + output := make([]byte, outputLen) + copy(output[:], data[16+inputLen+8:]) + dataProver := crypto.NewKZGInclusionProver(e.logger) + wesoProver := crypto.NewWesolowskiFrameProver(e.logger) + index = binary.BigEndian.Uint32(output[:4]) + indexProof = output[4:520] + kzgCommitment = output[520:594] + kzgProof = output[594:668] + ip := sha3.Sum512(indexProof) + + v, err := dataProver.VerifyRaw( + ip[:], + kzgCommitment, + int(index), + kzgProof, + nearestApplicablePowerOfTwo(uint64(parallelism)), + ) + if err != nil { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + if !v { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") } - frame.AggregateProofs = append( - frame.AggregateProofs, - inc, + if len(prevInput) != 0 && !bytes.Equal(prevInput, kzgCommitment) { + heuristic := uint64(highestIncrement) - + (uint64(highestIncrement) * uint64(999) / uint64(1000)) + if highestIncrement != 0 && uint64(prevErrorMetric) > heuristic { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } else { + prevErrorMetric++ + } + } + + wp := []byte{} + wp = append(wp, peerId...) + wp = append(wp, input...) + v = wesoProver.VerifyPreDuskChallengeProof( + wp, + increment, + index, + indexProof, + ) + if !v { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") + } + + pomwBasis := big.NewInt(1200000) + additional := new(big.Int).Mul(pomwBasis, big.NewInt(int64(parallelism))) + reward.Add( + reward, + additional, ) + prevInput = input } - f, err := proto.Marshal(frame) - if err != nil { - return nil, errors.Wrap(err, "decompress and store candidates") + if len(deletes) != 0 { + reward.Add( + reward, + new(big.Int).SetBytes(deletes[0].GetDeletedProof().Amount), + ) } - any := &anypb.Any{ - TypeUrl: protobufs.ClockFrameType, - Value: f, + if previousIncrement == uint32(0xffffffff) { + return nil, errors.Wrap(application.ErrInvalidStateTransition, "handle mint") } - if err = e.handleClockFrameData( - e.syncingTarget, - p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3), - any, - // We'll tell the time reel to process it (isSync = false) if we're caught - // up beyond the head and frame number is divisible by 100 (limited to - // avoid thrash): - head.FrameNumber > frame.FrameNumber || frame.FrameNumber%100 != 0, - ); err != nil { - return nil, errors.Wrap(err, "decompress and store candidates") + + if previousIncrement > highestIncrement { + highestIncrement = previousIncrement } - final = frame - } + txn, err := e.coinStore.NewTransaction() + if err != nil { + return nil, errors.Wrap(err, "handle mint") + } + if previousIncrement != 0 { + add := &protobufs.PreCoinProof{ + Amount: reward.FillBytes(make([]byte, 32)), + Index: index, + IndexProof: indexProof, + Commitment: kzgCommitment, + Proof: binary.BigEndian.AppendUint32( + binary.BigEndian.AppendUint32( + append( + append([]byte{}, kzgProof...), + prevInput..., + ), + prevErrorMetric, + ), + highestIncrement, + ), + Parallelism: parallelism, + Difficulty: previousIncrement, + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: altAddr.FillBytes(make([]byte, 32)), + }, + }, + }, + } + proofAddr, err := GetAddressOfPreCoinProof(add) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + returnAddr = proofAddr + err = e.coinStore.PutPreCoinProof( + txn, + head.FrameNumber, + proofAddr, + add, + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + } else { + proof := &protobufs.PreCoinProof{ + Amount: reward.FillBytes(make([]byte, 32)), + Index: index, + IndexProof: indexProof, + Commitment: kzgCommitment, + Proof: binary.BigEndian.AppendUint32( + binary.BigEndian.AppendUint32( + append( + append([]byte{}, kzgProof...), + prevInput..., + ), + prevErrorMetric, + ), + highestIncrement, + ), + Parallelism: parallelism, + Difficulty: previousIncrement, + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: altAddr.FillBytes(make([]byte, 32)), + }, + }, + }, + } + proofAddr, err := GetAddressOfPreCoinProof(proof) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + returnAddr = proofAddr + err = e.coinStore.PutPreCoinProof( + txn, + head.FrameNumber, + proofAddr, + proof, + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } - e.logger.Info( - "decompressed and stored sync for range", - zap.Uint64("from", syncMsg.FromFrameNumber), - zap.Uint64("to", syncMsg.ToFrameNumber), - ) - return final, nil + mint := []byte{} + mint = append(mint, reward.FillBytes(make([]byte, 32))...) + mint = append(mint, altAddr.FillBytes(make([]byte, 32))...) + sig := []byte("mint") + sig = append(sig, mint...) + out, err := e.pubSub.SignMessage(sig) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + err = e.insertMessage( + e.filter, + &protobufs.TokenRequest{ + Request: &protobufs.TokenRequest_Mint{ + Mint: &protobufs.MintCoinRequest{ + Proofs: [][]byte{mint}, + Signature: &protobufs.Ed448Signature{ + Signature: out, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.provingKeyBytes, + }, + }, + }, + }, + }, + ) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + } + + if len(deletes) == 1 { + a, err := GetAddressOfPreCoinProof(deletes[0].GetDeletedProof()) + if err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + e.coinStore.DeletePreCoinProof( + txn, + a, + deletes[0].GetDeletedProof(), + ) + } + if err := txn.Commit(); err != nil { + txn.Abort() + return nil, errors.Wrap(err, "handle mint") + } + } + return returnAddr, nil } type svr struct { diff --git a/node/consensus/data/pre_midnight_proof_worker.go b/node/consensus/data/pre_midnight_proof_worker.go new file mode 100644 index 0000000..026b943 --- /dev/null +++ b/node/consensus/data/pre_midnight_proof_worker.go @@ -0,0 +1,300 @@ +package data + +import ( + "bytes" + "context" + "encoding/binary" + "strings" + "time" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" + "go.uber.org/zap" + "google.golang.org/grpc" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +func (e *DataClockConsensusEngine) runPreMidnightProofWorker() { + e.logger.Info("checking for pre-2.0 proofs") + + increment, _, _, err := e.dataProofStore.GetLatestDataTimeProof( + e.pubSub.GetPeerID(), + ) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + e.logger.Info("could not find pre-2.0 proofs") + return + } + + panic(err) + } + + for { + if e.state < consensus.EngineStateCollecting { + e.logger.Info("waiting for node to finish starting") + time.Sleep(10 * time.Second) + continue + } + break + } + + addrBI, err := poseidon.HashBytes(e.pubSub.GetPeerID()) + if err != nil { + panic(err) + } + + addr := addrBI.FillBytes(make([]byte, 32)) + + genesis := config.GetGenesis() + pub, err := crypto.UnmarshalEd448PublicKey(genesis.Beacon) + if err != nil { + panic(err) + } + + peerId, err := peer.IDFromPublicKey(pub) + if err != nil { + panic(errors.Wrap(err, "error getting peer id")) + } + + for { + tries := e.GetFrameProverTries() + + if len(tries) == 0 || e.pubSub.GetNetworkPeersCount() < 3 { + e.logger.Info("waiting for more peer info to appear") + time.Sleep(10 * time.Second) + continue + } + + _, prfs, err := e.coinStore.GetPreCoinProofsForOwner(addr) + if err != nil && !errors.Is(err, store.ErrNotFound) { + e.logger.Error("error while fetching pre-coin proofs", zap.Error(err)) + return + } + + if len(prfs) != 0 { + e.logger.Info("already completed pre-midnight mint") + return + } + + break + } + + resume := make([]byte, 32) + cc, err := e.pubSub.GetDirectChannel([]byte(peerId), "worker") + if err != nil { + e.logger.Info( + "could not establish direct channel, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + for { + if e.state >= consensus.EngineStateStopping || e.state == consensus.EngineStateStopped { + break + } + _, prfs, err := e.coinStore.GetPreCoinProofsForOwner(addr) + if err != nil && !errors.Is(err, store.ErrNotFound) { + e.logger.Error("error while fetching pre-coin proofs", zap.Error(err)) + return + } + + if len(prfs) != 0 { + e.logger.Info("already completed pre-midnight mint") + return + } + + if cc == nil { + cc, err = e.pubSub.GetDirectChannel([]byte(peerId), "worker") + if err != nil { + e.logger.Info( + "could not establish direct channel, waiting...", + zap.Error(err), + ) + cc = nil + time.Sleep(10 * time.Second) + continue + } + } + + client := protobufs.NewDataServiceClient(cc) + + if bytes.Equal(resume, make([]byte, 32)) { + status, err := client.GetPreMidnightMintStatus( + context.Background(), + &protobufs.PreMidnightMintStatusRequest{ + Owner: addr, + }, + grpc.MaxCallSendMsgSize(1*1024*1024), + grpc.MaxCallRecvMsgSize(1*1024*1024), + ) + if err != nil || status == nil { + e.logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + cc.Close() + cc = nil + err = e.pubSub.Reconnect([]byte(peerId)) + if err != nil { + e.logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + continue + } + + resume = status.Address + + if status.Increment != 0 { + increment = status.Increment - 1 + } else if !bytes.Equal(status.Address, make([]byte, 32)) { + increment = 0 + } + } + + proofs := [][]byte{ + []byte("pre-dusk"), + resume, + } + + batchCount := 0 + // the cast is important, it underflows without: + for i := int(increment); i >= 0; i-- { + _, parallelism, input, output, err := e.dataProofStore.GetDataTimeProof( + e.pubSub.GetPeerID(), + uint32(i), + ) + if err == nil { + p := []byte{} + p = binary.BigEndian.AppendUint32(p, uint32(i)) + p = binary.BigEndian.AppendUint32(p, parallelism) + p = binary.BigEndian.AppendUint64(p, uint64(len(input))) + p = append(p, input...) + p = binary.BigEndian.AppendUint64(p, uint64(len(output))) + p = append(p, output...) + + proofs = append(proofs, p) + } else { + e.logger.Error( + "could not find data time proof for peer and increment, stopping worker", + zap.String("peer_id", peer.ID(e.pubSub.GetPeerID()).String()), + zap.Int("increment", i), + ) + cc.Close() + cc = nil + return + } + + batchCount++ + if batchCount == 200 || i == 0 { + e.logger.Info("publishing proof batch", zap.Int("increment", i)) + + payload := []byte("mint") + for _, i := range proofs { + payload = append(payload, i...) + } + sig, err := e.pubSub.SignMessage(payload) + if err != nil { + cc.Close() + panic(err) + } + + resp, err := client.HandlePreMidnightMint( + context.Background(), + &protobufs.MintCoinRequest{ + Proofs: proofs, + Signature: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.pubSub.GetPublicKey(), + }, + Signature: sig, + }, + }, + grpc.MaxCallSendMsgSize(1*1024*1024), + grpc.MaxCallRecvMsgSize(1*1024*1024), + ) + + if err != nil { + if strings.Contains( + err.Error(), + application.ErrInvalidStateTransition.Error(), + ) && i == 0 { + resume = make([]byte, 32) + e.logger.Info("pre-midnight proofs submitted, returning") + cc.Close() + cc = nil + return + } + + e.logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + + resume = make([]byte, 32) + cc.Close() + cc = nil + time.Sleep(10 * time.Second) + err = e.pubSub.Reconnect([]byte(peerId)) + if err != nil { + e.logger.Error( + "got error response, waiting...", + zap.Error(err), + ) + time.Sleep(10 * time.Second) + } + break + } + + resume = resp.Address + batchCount = 0 + proofs = [][]byte{ + []byte("pre-dusk"), + resume, + } + + if i == 0 { + e.logger.Info("pre-midnight proofs submitted, returning") + cc.Close() + cc = nil + return + } else { + increment = uint32(i) - 1 + } + + break + } + } + } +} + +func GetAddressOfPreCoinProof( + proof *protobufs.PreCoinProof, +) ([]byte, error) { + eval := []byte{} + eval = append(eval, application.TOKEN_ADDRESS...) + eval = append(eval, proof.Amount...) + eval = binary.BigEndian.AppendUint32(eval, proof.Index) + eval = append(eval, proof.IndexProof...) + eval = append(eval, proof.Commitment...) + eval = append(eval, proof.Proof...) + eval = binary.BigEndian.AppendUint32(eval, proof.Parallelism) + eval = binary.BigEndian.AppendUint32(eval, proof.Difficulty) + eval = binary.BigEndian.AppendUint32(eval, 0) + eval = append(eval, proof.Owner.GetImplicitAccount().Address...) + addressBI, err := poseidon.HashBytes(eval) + if err != nil { + return nil, err + } + + return addressBI.FillBytes(make([]byte, 32)), nil +} diff --git a/node/consensus/data/token_handle_mint_test.go b/node/consensus/data/token_handle_mint_test.go new file mode 100644 index 0000000..3302ad4 --- /dev/null +++ b/node/consensus/data/token_handle_mint_test.go @@ -0,0 +1,715 @@ +package data + +import ( + "context" + gocrypto "crypto" + "crypto/rand" + "encoding/binary" + "encoding/hex" + "fmt" + "slices" + "testing" + "time" + + "github.com/cloudflare/circl/sign/ed448" + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + qtime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +type pubsub struct { + privkey ed448.PrivateKey + pubkey []byte +} + +func (pubsub) GetBitmaskPeers() map[string][]string { return nil } +func (pubsub) Publish(address []byte, data []byte) error { return nil } +func (pubsub) PublishToBitmask(bitmask []byte, data []byte) error { return nil } +func (pubsub) Subscribe(bitmask []byte, handler func(message *pb.Message) error) error { return nil } +func (pubsub) Unsubscribe(bitmask []byte, raw bool) {} +func (pubsub) GetPeerID() []byte { return nil } +func (pubsub) GetPeerstoreCount() int { return 0 } +func (pubsub) GetNetworkPeersCount() int { return 0 } +func (pubsub) GetRandomPeer(bitmask []byte) ([]byte, error) { return nil, nil } +func (pubsub) GetMultiaddrOfPeerStream(ctx context.Context, peerId []byte) <-chan multiaddr.Multiaddr { + return nil +} +func (pubsub) GetMultiaddrOfPeer(peerId []byte) string { return "" } +func (pubsub) StartDirectChannelListener( + key []byte, + purpose string, + server *grpc.Server, +) error { + return nil +} +func (pubsub) GetDirectChannel(peerId []byte, purpose string) (*grpc.ClientConn, error) { + return nil, nil +} +func (pubsub) GetNetworkInfo() *protobufs.NetworkInfoResponse { + return nil +} +func (p pubsub) SignMessage(msg []byte) ([]byte, error) { + return p.privkey.Sign(rand.Reader, msg, gocrypto.Hash(0)) +} +func (p pubsub) GetPublicKey() []byte { return p.pubkey } +func (pubsub) GetPeerScore(peerId []byte) int64 { return 0 } +func (pubsub) SetPeerScore(peerId []byte, score int64) {} +func (pubsub) AddPeerScore(peerId []byte, scoreDelta int64) {} +func (pubsub) Reconnect(peerId []byte) error { return nil } + +type outputs struct { + difficulty uint32 + parallelism uint32 + input string + output string +} + +func TestHandlePreMidnightMint(t *testing.T) { + log, _ := zap.NewDevelopment() + bpub, bprivKey, _ := ed448.GenerateKey(rand.Reader) + app := &application.TokenApplication{ + Beacon: bpub, + CoinStore: store.NewPebbleCoinStore(store.NewInMemKVDB(), log), + Logger: log, + Difficulty: 200000, + Tries: []*tries.RollingFrecencyCritbitTrie{ + &tries.RollingFrecencyCritbitTrie{}, + }, + } + + clockstore := store.NewPebbleClockStore(store.NewInMemKVDB(), log) + dataproofstore := store.NewPebbleDataProofStore(store.NewInMemKVDB(), log) + keystore := store.NewPebbleKeyStore(store.NewInMemKVDB(), log) + d := &DataClockConsensusEngine{ + difficulty: 200000, + logger: log, + state: consensus.EngineStateStopped, + clockStore: clockstore, + coinStore: app.CoinStore, + dataProofStore: dataproofstore, + keyStore: keystore, + keyManager: keys.NewInMemoryKeyManager(), + pubSub: nil, + frameChan: make(chan *protobufs.ClockFrame), + executionEngines: map[string]execution.ExecutionEngine{}, + dependencyMap: make(map[string]*anypb.Any), + parentSelector: []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + currentReceivingSyncPeers: 0, + lastFrameReceivedAt: time.Time{}, + frameProverTries: []*tries.RollingFrecencyCritbitTrie{}, + inclusionProver: qcrypto.NewKZGInclusionProver(log), + syncingStatus: SyncStatusNotSyncing, + peerMap: map[string]*peerInfo{}, + uncooperativePeersMap: map[string]*peerInfo{}, + minimumPeersRequired: 0, + report: nil, + frameProver: qcrypto.NewWesolowskiFrameProver(log), + masterTimeReel: nil, + dataTimeReel: &qtime.DataTimeReel{}, + peerInfoManager: nil, + peerSeniority: newFromMap(map[string]uint64{}), + messageProcessorCh: make(chan *pb.Message), + config: nil, + preMidnightMint: map[string]struct{}{}, + } + + d.dataTimeReel.SetHead(&protobufs.ClockFrame{ + FrameNumber: 0, + }) + + d.pubSub = pubsub{ + privkey: bprivKey, + pubkey: bpub, + } + d.filter = p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3) + d.input = nil + d.provingKey = bprivKey + d.provingKeyType = keys.KeyTypeEd448 + d.provingKeyBytes = bpub + d.frameProverTries = app.Tries + baddr, _ := poseidon.HashBytes(bpub) + d.provingKeyAddress = baddr.FillBytes(make([]byte, 32)) + + app.Tries[0].Add(baddr.FillBytes(make([]byte, 32)), 0) + resume := make([]byte, 32) + proofs := [][]byte{ + []byte("pre-dusk"), + resume, + } + + outputs := []outputs{ + outputs{ + difficulty: 199985, + parallelism: 9, + input: "020ca8a22b2ccfd1bfbce0e527e65f062ed50f8ba1959fc5de138a56d192077c5dfbb84069e37880259707e1a72d61efb719b17409f342fd82181c35f264883cf2388819a12fa3a2213a", + output: "00000008003ccdc80651325d75deb1820430865dbaa457d7cd9dbaf97b88742df443afbc689980134e6118c74690b85208a543dc3e93afe429216d2552a4e77d270f15f8c4951db32063d227a07c4e56ec7c6fd2a7117dd0119b8bdd0945ff42151b8a4681c809a303051e477a4fd36d27e47ee4a5de14010aa61a528004ee3ca29877eade0002d6198e46a66b69afcfeac360e0e10b770cabebc48f6d5e0081ed72213968e0d289fdbcc634164adc1fdf141dbb0d5f903e32fc7b3c1e2e5eb85537f9b5fcf35d745c3ec18d9a0bf1f4ee1b414a63709285ae252decf8a52088111074d977115ac66117a4a54ce935ab085ae6eb82715f28c81f76d44160667d8f69892c21fb0063955d8a562c45df08015422da58a839446259828198764c58a49cfb8f24d916d92537cd4be6c5f12649970d3d4639d0eed35faf27e8ba1ae215cd137a55886e14b5cb413387131da699aa2b242bf32afa7fbde5a5fa9271d50217fac7d6a4e451d471c6cb1dd67f530a3c10e31f5aa360da18646f41b57d5d160bd55c2a66b9005084835a75cc37c52dd0116166d2d0e6e5b61b5e0e69529152363759a89f10d5d97921316df24721477b2e356792bd8c7d7b9431cd721ae0041e8473ccfe37d0b3f494bc3b1be14c188abac295bf27171800e70cf9727eb8eba4da2bcbae283db5c84a26ff6eead7017b214834d623de3971906150fdaa60b755390a8cb3c6ad0203d3afba942d36342dd528c5212f3eca9a08c4a160258762a046c30d031ac4d98ab0af9043fe2e2ffc773241aaac3a8b0ad1e326fba52927d331ab126cb792604c69f5dd13d578093f0310636030c2c67886b429b4a42e42292c2ab0b4baa02079aa9fd89ce6e547b8fe1d9ea3087b46dd72e35478bfdceabe8b84f6b2270d1af747ab4594a00f7397b0d0c0a86623f76d8f89", + }, + outputs{ + difficulty: 199985, + parallelism: 9, + input: "030535b5462e29eb74934667c9b99115f50a907ba3ca0edaf9f9d7527fa7e76a543f5695b30d53831327e049981b6312ae5ab450f7724917521b7ad8e7d96ef9709907e0ee25c7323ec2", + output: "00000001005ed09f37da868db9801ff0dd20af030156e6c4435b49c91911e51ccbc6144df990fc26ca20662a001ba7ab33cce22d77f94ccb472559a2626b2c43c648a6f4a5d91c1d268b77f7e607b62d5cbfa829332a10be360940aa7a3111cea596482878fd94005244a821adf4cc08b08188db3163a4d7344107aa2f4ef0052d1369d3e8004cf81d30e51f7cd1603f9c7880f4da56143dffcdd145b560d94db0b5b43e40a504b77f011832cbaec3b977da68dd11f451f38ce1e1e0488577a06bcec295037f5c1a1d0c6233065ddb0e8d2943ffab1e69be6e66550dc126a42bfae7fdadfdd45760e53358051cb06139a0d02af5714f8a192d9191e3d606783c9b5b6d13570f002ab3ac5eb15c3c95723a7cdb00e979832d689bdad8e8dab1de10e289fd635d9a85fd5598aa1a734af292966ff5b9b8a0bb7aee3ccc831e7e87f687667a599c42c2e269bee29266aa844b4e62bb59d6bfeb3c7a51c48935ab78e22a8e0d7482073b1123d55619e622ce9e64435c8de45cc2366c0df4635efa2880d7e047312542fff92e0e32397b0aed406d5d05ab2bdd7654d7c69e1b1470acbda3039204dbc9c088fba72099ccdd7e25e259ff35daaea596148b2a9e6c5f6a1a2384188ffdd9d0f4e28c89f1255a41e2c59babea8eacdfc43bb971fa3572929ee09735f191fe68f7e40450aeed05167a054bf74bc9ecd6b50e7e13afb84c7f3d81ae9c2dbc5c2f020ca8a22b2ccfd1bfbce0e527e65f062ed50f8ba1959fc5de138a56d192077c5dfbb84069e37880259707e1a72d61efb719b17409f342fd82181c35f264883cf2388819a12fa3a2213a0303ec63aa517961c1c2042ad8edc92be6232383c4ff24e393193eda1426675345816356f29ef9966f043e8617a1b45e01bb16c9c64f8b8171d011721671223c64eeb525f63c8b33d234", + }, + outputs{ + difficulty: 199986, + parallelism: 9, + input: "0303fddb50e39b787ca44c4fd43d16f1a4ff86de9d9bd11000b9cb52b013af1ceb1965cb7d2b62c7a478801a315e863c002dd258c7493a1614b47319818b306c1ce170fe5faf211a0e4b", + output: "00000008003835496aefd907540d74b95de3c367ea6ca1cda247185e4da348825cafd30e1c7ae846790d5e599030ddb9453af8970a0173ebc12a900f2c235e03d155126f57ea172b62a767ebb2190b023960a916367d47564a45e5ab6667e3c58708d600e14de3fec4341b2a2bcbe4ce5e2b279ecc34f09b597bacb60915dd8843664f0a1c00261d7e456e521691ad11fcdd9459536c839a0ec07a8e2d7f8244e6ed5d3126c9474c7f5ff766556ad26d6fe09e478ada7a524a6714677a538ea273b3ccee2de035b375fbd3c6c67c42af80d4608b3ad4047e5f5ded60920c1a45cde9d151e0edd334369f77392e303eba915d307b35edd48f12fed39da771c78876017506d087005a5a2fe2d85fbd96efd30d8755646c4d7af07973bc4ece8f1925e84802a79e3a46dd392fde340dc694695c73eda39a2d9ef2b6ce7905519e2e9db73afce6575817895d0334956c634b9069840347f560029ba8c923e7d0df9761997edbc4793bc7a9a1984f455e955cdae8822c8e64afcfc8e26b49567399868b8887827c2f090036d73613cc2dd733ef2e730e607f117e06ba388349514aba478b66d806434c989f3d994c1fe0c5f79d75935d119feb61e710642f6a7aa6e0183a8a8ddbf0de6df78242fb14ff8f157940a5ae75679ae3b7ea9476b450c38bab5b617c3fa9706647feafd934e67906bd624bb90458ce24168a95c35a56611e14693f748e29fd01030535b5462e29eb74934667c9b99115f50a907ba3ca0edaf9f9d7527fa7e76a543f5695b30d53831327e049981b6312ae5ab450f7724917521b7ad8e7d96ef9709907e0ee25c7323ec2030dc8dd08e194e669eb1208b25abcc7e6b7150090e709e251279f02ada213da73ffc2906bc1e5163a8cb3a30934f741d15781ea6d1997f510712d8479fa5b05c86d138d75e5c5ec4b0e", + }, + outputs{ + difficulty: 199986, + parallelism: 9, + input: "020b613c330838bdfa628eb45bb9d698a116c9e960f4b7efbcc2ab7f1108ae8ac92b48a2c8b0e67370fb4e4759090c233a214f5657464d2b76a0a16f7e4ce18e96be0f800ae0fa179f7e", + output: "0000000000612d89f071b00344f96fb259f5ff79d03030ecd7d41458ed335e01c98f874594831c8c919b961a1c9f23469ea8bd296bb37d7a237696e842637a3ad5d356e326a4060c3da7553fe9abf7819ced0e5a4d3d6df825fa80e8dec10d771137127732d95d61ed1dc36a9813794446a91c83e4f00a8b9377eea6fb6adf62723e76931a000444e072c93c8a8e6606f8bb311b1c59e3e511a657feda6eaed80a65a1206e94ee670dc77d3d90db01c75ba4b19f19835f827617f6e395ebb965251526828e1f871bb5571326038506333decff82c89ad83b0b3b13f021aeadb44e3092bb5549897a872ef17031656df65fa6a7cfe23ca6e15dd2745fadee4781432232d98bb700132ee8e33d54431c8a243c769138f57d710cb169134b92f5fb5d63daca43ec6a19281ba907b03909d44152e60d70d0868ed6093546b651f5e1001419f40f1b4a34a5e527390fbe0678e68984bdecdca2f1a941a85802dcb19ce58a502e14dbb54b7d0b69f625f46a74eb13d30905e2fa16254a9f80a7a908c365f30e0f6a256b0000caabb5bda2e6dc1ab229d8b8ec8e3b1dd38d79afbf7bfa6ebc7a27c0c5eefba598f908fdee3f5447b8374824910791106ce1665786df194c561c99c95cd2a35a1fc39f9c11c8d7b3c709bfd572e6afc8621042a00a578c7c0e22c26a762c052531fc70155a69328c047ee6203415d8a1879b10664116db1b72352cb23315ab0303fddb50e39b787ca44c4fd43d16f1a4ff86de9d9bd11000b9cb52b013af1ceb1965cb7d2b62c7a478801a315e863c002dd258c7493a1614b47319818b306c1ce170fe5faf211a0e4b02007990f2586bf165c35bf4b2b0c8f884a8989911eb2955c233fb2522a5c7ee8b89c81488909468094df2b3f94a3f0258545fa0eb46f583e0b924e03541a9fcbc4198e69522571a169b", + }, + outputs{ + difficulty: 199986, + parallelism: 9, + input: "030948cab5c948307a46b11b23869ee1727357b16748d74bfe571784de9938933ec5b8a4031a4c820a661b800d697a341f2c479cb5e942fb42ddfd4ea3da48fa124fddf6e0bc64b2ae52", + output: "00000001004f93e754fee65e15b50b15b3f95cdf376bb0526630119b817d59587d1fa36295f24a06449b44181250a01d297fe107f2b838b8a6e9bfe3fe4ad92240c3b2e057dc3f9d89684d97ab7df8c6aa24e3d6c53ef2e868ea427461fbe70308c66bfe4f73070b804e58966df929ce2759384ed9a2818a8dfddfceb1d0a9854d3dd300f9001588aec86a68ebce8cf24b6dbe3c947f3aff404d31772e6a27fb6a2c37f3d2b310a0cdafab8443e38f1f453cb775fd593c5072df82b7ed3dacd43cb625ea6f005b10d11ae18f399313b18569372a6f7a3cc58e5abd0c6a34a4085f91285430c64acfac7f91220cde3eb6918064ce9317fbb28a877dda861f3c6f573d77a7df870043e8862973adcebbe6f1fcf032d118cd5cdef6a2d661b18bdef3e6bd51e5afab2f573199dcc3f302f5e6b0026e56f704c474a2a608d0412c6d90bc4337fac5f17c99153c4992fb8ac1f160647da16d03977d2c7f3c58ee3a02d5255b4ed7e49b7d27434c157a64da8b364e55fe0f5d77bd2e023bb48e6096a2cf1798bde69ef5ffd2452d73570a2329be3aae533d232a0a55bffc00b11887c021f3e223ac17b4669451f4428982dd6f576fc867518a0e16c1e558279858b80ce28342cf51a690941e68a335871caf06c9db8dcb5cc9b72e16a9f26ec4af7ed68e51c93f9d3472c9e35b5fad76dc32733758d9a69040ca4a62ef6c0b4c5382b87e22d581af350a23020b613c330838bdfa628eb45bb9d698a116c9e960f4b7efbcc2ab7f1108ae8ac92b48a2c8b0e67370fb4e4759090c233a214f5657464d2b76a0a16f7e4ce18e96be0f800ae0fa179f7e0303b544801a56f99dabd895678cc5a89aca0823790c5f7e0e170f6ba51f407cf7fc743f226dca2b04c6f253d6a34383bd608a7f9fd69bf2697049c1e4ea287b7203f7054eed24021972", + }, + outputs{ + difficulty: 199986, + parallelism: 9, + input: "020a0ffe99899d5fa940d8bf655defe33fed2354bd8ad7eae774171e44aa0412164aad4534fbfeb5499650f1d95bbd76b0e7a0f1535b88034f299508f5a01f68454d9198b4d10e05ad7b", + output: "00000004004a1f9b7f776573361c59ae4d3f6886bab41ab8b7aec0e63538ecb9a693022ae4178c22c11a963f98fae518eb98edad2ccf06a56675283aad1faff13a5061214a6044c6ea9d9f078bff6c3447d0abd6a4123dfc8a5f594c109538c5d4161b749910cee36ca55d477fb9524172c95e2f2c118c6069a23cecf8b2694cd29c08f3ca00049b0585e7fd12c4e37cc9c5b712aa3e4712a73f62770c14f0f1b2527ec26577006f5aafd4b1db8d6ab3a20a45cc89a6ca465f58aa45c3469e6aca884d4d24489a47a5992e9c65b502d42837faab48608583c34a47f0548cf32aec0bd48afb1693e06cd736bfb38042ffff3bacb657ab52de01a2ef3fa1058b50f3d7861f5675005ef18a5679b49c5b39b1d5669bd019b0f05088a63c71f5c39b39f1429dc7a28398a4eeea5a07e2483b82fbc2628ba261c57b7c094adda4cc8a3ad06384135930fb6a6dca7877ca9a8714397de9317592378182345811ec799cbfb81daee1084f55a5204e8ce66a7ff1f6645dde31a9a0ee1f743b9e5bc89b70e8380e684fd6eefffc1170328b615d6b04850a2b30ef9af7f31e0102423893115885b2304d12bd289b282bdd9398c922d26f34de105a33c537d7fbff6db06be790f76a681dde88718efd4400e813d811777fdd76bc149fde725d9ff8f977f4ce5ddff21beaa4d20382fae4a782471bac3796d1c5030d7c64cbaae07e1fbdbaeeaa725447562949c3030948cab5c948307a46b11b23869ee1727357b16748d74bfe571784de9938933ec5b8a4031a4c820a661b800d697a341f2c479cb5e942fb42ddfd4ea3da48fa124fddf6e0bc64b2ae520307613864a8009720be6918228def179c95af4c4965220e52eb5213f8c2da7a2963b47e6e3f087f1fae44e0633a47523fed34d5d50d9e98a4bac0ca49984dcea6354273a4550d20c29c", + }, + outputs{ + difficulty: 199987, + parallelism: 9, + input: "03090b56483e7dbd669997f62c6880630b01db997ab566d1d5773f0c51a8a5085e2fdf8adada9f1ec88a6dbbfe6bdfa7cc37ffce64a94c3c2cd4b5d7d475966eb364137c1e5e7c80d586", + output: "00000002002e4933215598534809ebb87f112446d585ebc174a2c15b12cac3a8c489b35661b127a89dacdd88f9066c1832c414b0c7e76b9cba20afcd66c749038856021b0e1782e776b8c547340f0c4b6089a91e223428fed8e704cd7f7213224e81cfdc04b04868dc4f279e5b3bd8109c4538e63d752381c6ef182ebce5813515751210eb000d46fb7e5570f043d5591387f0458be88fe9b2667ee61c91e3af0431e9894eae4b589856dc82d1eb4a894c0b87f13fe09209fb45acb59c5f3e93353b26d7d51211bd30fc2d8a63caf3981ad089ed146822cf696fbe8fa956ae838944dc680a55156a161d5340b45db5522c46a2a9a0fc61f199f42495b03d879bbc203e9f6a81003384acd8654126b00ce2b5d05ca75a6a460201c9c59c6514b6209e0e1e3e2c456261c96a2a8838e2445ea204c6456fef6ff54da2a1e3a20797a0cdc6f5ea5dd6cf3d44f52cdc098b0388a7daf467e2c408a11114aee2a1f85d64d0ac5d3b75b415f08fedaec1ef0e00772a10f1ef16c5d97586977d58b1a3d6443d681279553affe629eab02fff39ace1c184b24963db6fb417b2697520efbf73975060bdb275bbf8d5128c05028b1a8a8272cddc13e8bd01cb457b458932863bca83b53d63cdf0678bfe927002453b61365551bf2ed44449517cbde28960c6c324f1be6acc3608d910448869fef2c73ae08d404d6418ffa1bbb0fd78133d487762908d676032f7020a0ffe99899d5fa940d8bf655defe33fed2354bd8ad7eae774171e44aa0412164aad4534fbfeb5499650f1d95bbd76b0e7a0f1535b88034f299508f5a01f68454d9198b4d10e05ad7b03102e1e9e4e70a9d644a4795b6fa0f87f2852a6a361eaa2a7d64048a2af413f3db6bc65b3b3c173039f58d28a9c3f3b653c0af005b9664f4da582294ef4f47ae0886abc5fccd63364d2", + }, + outputs{ + difficulty: 199987, + parallelism: 9, + input: "030b253f3e885ceb9df5aea090ca729076818abe8f8411e37aa2c57a07e88ca80507950a5e551ae157985ca305574fd2a34ac2d05f13cc0907b1f11d47381cc66d92630f0fd036b4963f", + output: "00000008004692cf9e4099f0a012504bb437f627dd81cd60715a74b316c1423c014e7b5adabb5d6539da503559916d5c545b9858f5227c1852e5b9336f70363045fa41f87082ae2f48840443e003d4b7928fe396918afa06ed17086c384a23681d022441145a13aa48548af6003444db5b4ad7f3046beb443f4b50bad72f229c54b948087c003d2d34c384ff05c0f55890b9eebec631c17c1dff2a702e8909ddd90d058048bc6473274f1aecff066c63fceac310214d4a8256cad6def202c7e1732a2078c75263cf76c66700a2670820c623e79cd2cd032fb88aaacbe06fd2b2ea33bf59612dd3d6ca45c756170d0c1d003c7be443b449d821e7d6e932e95a638a9a376bd74f00452978001e0bcfcd004e9ff2648687cacdd3d6ce3d6411b4c25b055397bec0940cac8868c97ae19ee0f01d351c23d6090eeb56a1b5b1fc7c04e775a08c2ddc13639b66355d74013c304f9799ae12da12bf5cd6b484585ed994ba84ea14ad819085791d936cdec5564baef7525d397577109021d19d698d65499e1f77d987906cffbda08f84f6591f2c5336232c8c7629bdd9538f0462970771729f7e7740d8f5cfb09672972ede2771aa8d2ca093df53f3a9e7dc7b2d73f361d3b2906442ae4669ed08e34da74f552855eede6d91f4c1ec7be2d725ad198b2ea7869a200fea0ea33736f02cdf4b59ff0d74e3aea26cebe53aa339429d4f483cbf7e50c31d07bbd703090b56483e7dbd669997f62c6880630b01db997ab566d1d5773f0c51a8a5085e2fdf8adada9f1ec88a6dbbfe6bdfa7cc37ffce64a94c3c2cd4b5d7d475966eb364137c1e5e7c80d5860200afb5e8b4b1602eed1c336f385ba4becfc2a3752448437caa798ad86e5e691274c268d5568377fe9cf5fd287ad625ace50e52fe770d59f42532e93acda10e7525e7f455f13f2dfb95", + }, + outputs{ + difficulty: 199987, + parallelism: 9, + input: "03089a75b017471f7ed96d604473f03529a9d502b53000e065ed0291f4ee8b990e8460e60deb0c4379b84dbbdde4214a5ccad0140debf01aaa99d83ad8db531ba756f8cfb8f0bb01f90f", + output: "000000000042f4b4093250580124be16c326bbb55035c2534587aec9c500899870f1b77c5eebfbe2e7d34f1d0739a6b9c8236a604e4745deefa96b1b96fe8039b82b8fbfdc649086e2b1f88233edcf126b2fbbc03cd4d50e710be64e50928c4a4a6cad9acba62c49940652ff43227edfc957d02b40105b1df909830fb9721a593f1da35d90ffc0b2629b871d0c5f6a97c180b21d3a8170be22f64d87e848c2503aab32d3666d2f9f64daf19c33ee276e78a553665fe5242a41754fe083ae8082ed7a2da68eeecf6f24a457832a4958712741505436788e70449a62196ee7678e54780cceb7cc30e8adaa15205886e4de6ddcd4ca0d42ab853f507e106164fa28ef6eb5ccd81f0041e166a7d9af87c2e30e56057933e326a79151093ee7c5e423bfbf13c8095e01e0f437d6cddc547cbf0d2edfc0cb4b4f5bd476a53d2a55b66bff5ce7e57378d16975c597c3a28351b1366b8a851dbbccb49df78b1a85e71e341b2b43177dc4e945ad5b4513e86b87fb5d31622d3f6978d037ea2427bbbe80abc5fe6f5fdb911f0022a02776eb0c5d7184492faa4d23117fbfbca16d39283a145701d4aef5caf1780c285757eaa061422cda5c51dfaf4e71b2cc80d897562564061ead6fcf3537920c157e8449ff5388239f2d0546b96dfcbaf40b2c127a32a0a9a310076aa9febfb063552b02c9362e6a3763e53ef162f1ebbcef3328f73811fa2f8c3e12651507030b253f3e885ceb9df5aea090ca729076818abe8f8411e37aa2c57a07e88ca80507950a5e551ae157985ca305574fd2a34ac2d05f13cc0907b1f11d47381cc66d92630f0fd036b4963f0301383671e1e4e077c55e744bcb05f1a52359da4f3c39698da48746e06affcf38aa29a4ad77ad83c0ded5a96f375f6a86bf00716e3e074506be2854b758e775797b811beac4541ca121", + }, + outputs{ + difficulty: 199987, + parallelism: 9, + input: "0305142d62ad58078b29659b3ea8c6ba25c00b5cbd4fd78727c0d022acd02ef594a48bdc2e2a8a170a8d6657acaaf0b1df0ff0c2adf3f80a3ae95363432f0fdd2fe04d48dbf6413a47dd", + output: "00000002005b1561bb6b638c0c839fe4c191dafae888b49bc89fcbc3a39636066cc67e6c81756c82e76513b8bee2639b7f5a8c3ccf7369fe34b0cd776a5f569e32858838b5d016ba4ef16b89a7cc214172a92a0f89fa199adc95d523a16ed86a7209c21f5569a1a2ae2282a862eaec90a70f2fdfe098311f1f896afe851457cfcaed1319d6ffda37e7a1c0e94eae2e4b9bfc25e84021ff59ee478c8c1338a4bdf70dceca3632d3ee9ae97abed5557e73c54f81346112888181ba74d8497badd9b700ebeaecab31816194384d96b3c68a8e2afdc6cbf333170dccc827832a5959ccaf780a27b5b17b84923172a239a86b76f48ecbd24ba0f479baa30e586ea6c4325a35f4e40d003634d3b5b1108bf931ca2d16bc88c273e22ad9e5b925f6eadd4912aec5bc230d7f95413b5d2915724fc47c6f3267939b14dda2e38d7d7fdf64ba46dc6f4ca501a41cc6185599222c6a9e98a2d67e55adc7a60986805cc2a2638dcab57dfc2f80d1f8521a23d6899fef66d342b86d05411b66a2809f53e9e0f63c07451dbfb16affecaaa6015d937dcf63618cde31e1e16f05b1e8cc7fb942fa2f856efa5904e05a05a9f82ccefb709c8a9ed3cd105b7c45861073eccc91f022d44d2f43c24838a89226cdc725115ce38bdfec7a5361f0528620da8c9c4a730a86e1065bbdae4c2e374aa9986f75d7019996e4f24be31f19ef44e3e2cad760be91324dbd9759840903089a75b017471f7ed96d604473f03529a9d502b53000e065ed0291f4ee8b990e8460e60deb0c4379b84dbbdde4214a5ccad0140debf01aaa99d83ad8db531ba756f8cfb8f0bb01f90f020fbdeb1aaf203066aea66a49b363564c2e9fcfc0e810183677c8f1377268019f8ab1e7ad9e307c62d99dc6011774a6d9a9426a6c68d9802587f4d4e51fcfc79dce446572afb587a2fc", + }, + outputs{ + difficulty: 199988, + parallelism: 9, + input: "020f0e09e1f21f6c33f5f84b8bb11bc15822ab741a546eee1a852b2055634513d6ebcb80d81b604d4ab047c57c6cfb6dfdda6fee6ab94ef08d1f35081e19d39dfa9c488c3c7a9c0b95a8", + output: "00000003003cc0bab2bbbe048deb0e57d2d989c9fd8b05dfa429a40061658beb20f46d514e78c0f77db9ce5f7c1549156bec242a7fffdc32f1fc3f43d2bea22e9d2fe2091c4330c9536c304be683bb4e1f243ce9b0c431434c7919ba4b0bd841dd587f3fdaaf3078ace9a41999b8bf24cdb219ba2aae2b771ffce6cd6bd782e6fc5d69b91e0025d4e88eb0851c6472d04096af4be258aee8eb38a3d54f36aa5dcae01bda3b1794e5688d3c946666c3f1d54bd1416b2b976246987abe1a599c71b01e3787981cdf7f2444d5e7e4a4e758beebf651ddfee7a956c5faf80a90c7e0f0a1c8b590b10a39c865c31a8db1c30f60da51116ad3e885180777dd3b4018ba909c517cfc79000295d34a680aca8f3d081f1db1cbb8bcb5d23fcd56bd98bd59cb23f8f1327cfbfcec984b451a21a6d49fb9d16b0f427374aaa032a342a3b15fbf34d5ab9462986c6216925b493b564fe63143593d91a8a49f5ae471c32c2766a45b0d34958cad3f986fa0ce79687d388fadafc233208136152c725db3f9e160c818c3fd9503190001e48de84608a7744c548b1b0ae19be28e0090f4bf8fc926d37319c1d2a8b3341fb91e80dc6dbff954b2227321a1f0f3fbc3d916b7171ff7392a53034b527387d33187dd16e776f541e076c43c338abbc8c67a0331f13643e1381ef45980c6225692bf48b9387ff8f1fee579e5c7f5fb9213036e1da10d888151692aaae4e8af0305142d62ad58078b29659b3ea8c6ba25c00b5cbd4fd78727c0d022acd02ef594a48bdc2e2a8a170a8d6657acaaf0b1df0ff0c2adf3f80a3ae95363432f0fdd2fe04d48dbf6413a47dd020b976405942c5383f32e2a9a5d980353d03e635f2c87895b3ef81bbdf65b43c161b606659fed934b969bab356137fcc20d09df0a8a41113a8f88dc02f2d5b4ad7c0503a2fd9e1d19fb", + }, + outputs{ + difficulty: 199988, + parallelism: 9, + input: "030bb056f34bce8c23191e2c3dccfae518d72d896510294b585d355d4b83efe69b38b1e78a22b8c59b47d8534c174ca77835f6076b3ebffcab3a3ece013f3b0eeac33597c7a21f153afb", + output: "000000000013ee9fdade8f37213f716830ed94f79ade2a9ddda921c112c0f88bb471b323fdc1e87359e04ee027c56d1af287783a9f2bada94e62cef19fe047b415d25c35340a48e81f93bfcca7845880ad9d120a046791debc07ced37e967d250303295e87d9a052dc8fc880713ea46b5510b79d988e456c91813ed8fc3ac24b6a5efa2b7b0003663eda0e637d6ca8920b74fa039e1a67d5e466dfbb9c39826d8a4f948cb6b67d011fae44d60cef7afd976027b671cf98f265c3707a2c6fee2810a0363d3b8dd855a9ef52e735e3d2ab50b642c9312c8e2ec9330e6892b8c9f6c6cf93b0d22ece826b68fb1b0c1b138207ddd7050160d5ddcf3993712731ef13037e57b0b231003833918a21f8a16d7c2b30a6c39fcd7c0af082c1c684b9b5737e181316c8e8645596e3d1c3146aa49e32741c88d62cadcb2fa2b20259e9baa1fc84e9b55bda1efef747947a32314e5e5bb6970da1356158545ba52840aa8d206e6f675adb4160edc0e76c92389143cb2a1d08fef29cb8410d4b5f637664830d2cc4f9fe861490ffcaf11e6409189cc7c9526bf7f3ff00534776c21c111dfa572d8945902fb612e9b3828ee18e8b00360ad0132e5e059aa3040dce9322c18a289e5b05d347be1ddb1996e42e0f69ced64c2acb23ce88ea8b48d82df889a432fb5961434f55938761ae4cac5fb6f204192f7178f50d4a769f51559b67035c6b89211f233cdc31b07d020f0e09e1f21f6c33f5f84b8bb11bc15822ab741a546eee1a852b2055634513d6ebcb80d81b604d4ab047c57c6cfb6dfdda6fee6ab94ef08d1f35081e19d39dfa9c488c3c7a9c0b95a80209238b117c104188edfb7858c114d99438ede729c78016ca6b3c7e3f5ca8d0ec871ec88a1977c42efbf0616a40fb66626b62a36d66bc93a43bf92325c7e12669806e6f4f929eea671f", + }, + outputs{ + difficulty: 199988, + parallelism: 9, + input: "0311b99c2902209fd75a16e3f107fd2274560c0ad5a247a58d7cbe34cbbd6a5cf6b74f29d3db2fefd93ef477921210888e33124ce1cc98e4087d80f46be6080c522f85f46fce4f1cd594", + output: "00000002005672a12277ef8833337f03c70fd9be7d281ce1c7b371a7e9d16becf413903375cae374879a63ccfb6d0fb784a15071f5d06390c746624e64ae41e31dcfc5c05040110187cef7b2d40627748da272843a49ef0e7cc0d081d68574b2c57da75a3d75abe196bc897381987e3d3ff7b154b66ce380055f5f511ab61b3f4b55c9e431ffb0bd1de9adaa83af42f4d547b41b95f763622cfe9e0a9386adc7c33dc99dd9e3ae044d256a3748e27d9efac31902bf0cdb112f09e81b2ae17ee84176a97a86f8894e1017eddd4d1d156b07ce00651c20f314e30f5821f2b316fc1c20ca567356b21b24a6d448988b6c02c042e7ff235d0e8e8ae111ac505b83ae4699addf550f004eedbd9f48ccdfa57e7363028e767e8c007434dc8b6d8cfdbcd66d02d0a2afb15b1eab9c30af75bffba1654c78f5fac08187438eb373ae641bb531bf94d93f1b2d1bb4b674c1244487093ba231cacf42922523292519674d91eb8867d63487554341900f06cb39ac9a13b7ff735d74b159e4f9b0555deff896e63569b1f10b0b0017ac22b0a3245a58017b8b8287523689e240c6258955051f1d6e94afed98b635a0d9051a4fe08434822362fe86206183d55a6dd0502092d6374f458641053e8363af0ae66b21c84e9a2a53eee4521095cbcf91f9f109e3a709e5f8cbe659752b7d19ae1e2d2c13756e68ab9b8b363d973ccacdc49895cb22d7e38f2b2b096bed030bb056f34bce8c23191e2c3dccfae518d72d896510294b585d355d4b83efe69b38b1e78a22b8c59b47d8534c174ca77835f6076b3ebffcab3a3ece013f3b0eeac33597c7a21f153afb02051fccec09d5abdb71df6d73f4bd869af9af51afcb565c3a08d03949dffa30cb750a37b44a9754bbdc09bb70ff23d2815a7139447c481c760f4ab79439c0b1109a38e1e97152184729", + }, + outputs{ + difficulty: 199988, + parallelism: 9, + input: "020c694f4b39875a02b1e3382dae4d4a3350d23d80e3e6bba4dd7ed7e2607d0bbc56cf0dbeb74dfffeb1b476c23d53434f6deb7dc9fafa61aaa878a3f32647f1651d77bbf348bb353066", + output: "000000030013e9c6a9fa87c726d3b3c72b104ea8d741015831553971686e4dd9866ed3146dbf1cd4c1144185f68abcd39ea45f6c12f72e2755e6f0319adcb77dcf91af5f3f4e05246cde98042bb3b67390e89c568ea53289e6ec53adb1782099c7cbde845c5a348d9b51ffaefab93fdc1e0ab7390698383211e77b8fe1b513e48f3ff8769e0006ef38f9f7a8a6e3855c74428e91771126e876bb3a3b1efdff1032d009795e564c8e8711f9084bfcdb1029d0d5864f9513418a9cd683014395a6229603a1e4ab3bf532b4a642443a40fb30a95b212c5c9ade9fd14dacee7f7611e740dae1566be26265a15776d9f40cdf4bf3f8010d1667a996b4a093ba767625397cafa834b3002be11b9ca022f8b266bcd198f7add17bc97f1a958abb61fb287cdc31f0eec655c6cba30d43fdc34aeb630abdc4a10db804f22d1d4748a01b3f206f2a3451b4c107f66cad65d0e261ff351d70a183ca90ef1d80b82a92f805bfb2ccf2f78e3251a451a5a47798d2db36cce06a27d9be4fe94fbf0ae2d819183ca6aa7cc72ca1c4002597868a96f95afb6410ac436726e86cbb29ed88256f4ec5875a0596cbcb5fd22eb487286248c7ba73cbef82ad8090b7983b20f08f17384118caf4b5103a2182470c9f0f9c61170f178afa8c09a3fbecc45d7b8349f577a6c531f16ece768e6fe70c858c467792994a2639d039669fcc7584ea8075236fb38674d8d6342bfa390311b99c2902209fd75a16e3f107fd2274560c0ad5a247a58d7cbe34cbbd6a5cf6b74f29d3db2fefd93ef477921210888e33124ce1cc98e4087d80f46be6080c522f85f46fce4f1cd5940204779e4d7db73a51cfc07ea6b132a32e14a8ccb331630c09ce4c5e6888c772020b7afb8a6d15a47e462cd66fec063c17c55117ff0a2a3bf979048906fde02293f263adc9855d937e7a", + }, + outputs{ + difficulty: 199989, + parallelism: 9, + input: "030c0b7aaeae6e729746258b684c056320bffdf190a2aeff18ef499239caed72a04077f526229730423c8109d0f61148ef0225b6c39b6bb0cbd03a06cd01e70a070c301b8c3ec18aa4ee", + output: "00000007002b6b3974bd1ab4118c6c53862abb7a720407099f05e196be9adcecd98afe943c96ba6b690b4d7153069f1942099d2ee1cac90268fed6e6a91516188628e55353676e09f0b815d9107a1ed8a0031e31c4fba8747293c09a1e2bc7c90edca0d2fa0c3000f45fa02b11cc26dd5f80c4e0f2f508a257e0ada0265ba7a68b0f4c9720ffeb330cf93d28a31a2663456162e03cd405e8c9069705b085e68205887e150cc7281629b97b5c508cee6e0fd8f6eb5a93a27582a0fc5d5adbb2eb42a31f5fbd7a08463a015a24adce29641f17b03d5ebf567c111eb948bc1b96709b356beffe70af2eb9ff000a60c3e3e377021567264afc5ee5076fe615aa78e68ae1a2133c5b002f28f7b5bd0b4e78a0da5d8f820a3c03856e22d9aa2a742ef29f0b21baa39ee75d9062529e6e310392203cf5b3c705254a225cfebe7be5409161a5ca70802f79e9b097c799e65b59e8f02ec5827ba39b121fae8e57d84f69a89bf3c20991328bde36b18fce0d20841579feb5f3b8e85bb070fc65ad2321cdeee22f11361a9104ffddd7402e062c0779a703f1aee516ace1b0437686c3a24aa143e3095102669ed0a8a2def55b3688704124c025f94b6ed0eb5cac4cbd2348aafd2451531d0d2728f8b5371426867ed67b9329cbf4ca73d7aef1ffa928a77e2a55c676104078291274ba3c0c8953a933fb4e8662aef69bcc485f2646bae0483e810a4f2a5ca64e75020c694f4b39875a02b1e3382dae4d4a3350d23d80e3e6bba4dd7ed7e2607d0bbc56cf0dbeb74dfffeb1b476c23d53434f6deb7dc9fafa61aaa878a3f32647f1651d77bbf348bb35306602098383d714e8b5e24a5fc94696c47a8f8837aa3027c26c3f5a78f9891e025e0b8939485344faa59074aae1490fb0dc3f206b047c525b671b0e760af34693e1c9e05586758c4a11a217", + }, + outputs{ + difficulty: 199989, + parallelism: 9, + input: "0203f98a028b18353a9135a5792fa86076065aad30842dcf409fe980a90baab6b2274232c30521815de3f192f98a57a6b36bc944a06ad4819acb42b9ea7a39afcc588cb709fd7864ef28", + output: "00000008003d046c1cbbd66387e045d827ef2141f88959419a7d8616f1ef2bf00d5d0646da8b522e0ace96cca39847dc449b6ce2da5aa1e6dd623ea90c72f82a301af8dfc9a31f9ea14b2045d887d27bed80f85a58f555a6690d2f09b26376b169b3e341ba013c9788993bfa15b7a1cd1166c73cc7363f9cc413d7ced05eb48caf3ba856f9fffafbd349f93b730df9ef208bfaf30532a10ca45922a8d4d5ba4db3236082040d7a6388b5c26aa120cb4ed4f8d4b3140b3465089deb2d3f2b1f6e77c05c4502ea79cfe85bef18e8487ff6d56e070cb37095f46725f4d1f93b410e0a6336320b9ce66e4d55c831e1a47a3bc5b73f115818a99557dd0c26fc43aed4df9d044edb0d0010a3af9f356dcddf834bf4978893b6549b60c4dcf4e0ebcbea35d548eb1d2be4672a9e024ab400f4a69a931572dc6e9fe67897b6f19073b839d689f9179398d9ad9bad5438a6c152648708f4d0277b3ff65e63bd5140f25953040849657fdd8cb24eddcc3a5d51e21f53fa1762f183143a90daa900905339d6fd01d3c40daaae000f03267aa7fe181aa6d2746c71c1865d2f49758dcf70fa2af619ea008db8b9f1432c022aef6605a6751065d3c46cf4f481be1201f666d9545104d7ac3599d43caaeef8cabd94013dc41b1df7ff57150840f2a2b661da2eda5831aaa7a1af352af2ea7d49f164a604afeda37e2a4868bde60dd033d6a24c5188611e2a8841b03b030c0b7aaeae6e729746258b684c056320bffdf190a2aeff18ef499239caed72a04077f526229730423c8109d0f61148ef0225b6c39b6bb0cbd03a06cd01e70a070c301b8c3ec18aa4ee030af91b85079ddee21485a59208f25f479e2b380e6fe10575bb0df3de697b1f6efdc3ad9b814e773a886482533dc94a54371e2bbb96a58e1df3ede159e19f6af64ccb39e5c79e2a7f04", + }, + outputs{ + difficulty: 199989, + parallelism: 9, + input: "020d5b76aef88a805781988a43d9e5d8942b1e5726f0e377f8ebf05b0823206f632e16f7b02e7ed9741a6348dcc01d5a5087d558ffd7626cc0a33cbec154b90250ed43c901f9dbd1b819", + output: "00000005002df4934f323deb758de0935012ea0f6738b706c6201e49eb999a8c9a00d272a002cf0b2c0e621e7fb15a4965494998058b7e08b0ac6c799654751bb0721ba4071d25ad20317e8fb95fab87bdcfa5d1679349d0ec7eb20cf1d37582455d7616e5b9b2adbced107163e2a6c9d2b5015ebba704a3d1c6032c7dacb49c558d5bd6fb0001248bc277909f8e63c353cb51da51b6c2cb7271d314d018ac6a237525706ea4e74aec2ad3f401ee7bdba0d245d9de82175559fea0be998c2d6124e321a63cd91cd74bd64f048c3770315aba363f31ccbfa7cd62b20959b51144e6e9416cbb644d6ce02961ed8c32a78c49e98b1c27007bd76b68cab3e57d0b784e259de61d45003b857ee8ff52ab0a7def843a74cdbe63d9a143b7f8a0597286057fe8ff3b29bebb1a2170798f3d90a7ac3bc6a412e172f0ea9ae0208c53e1b5d1b6aa0c8e80118a0e1275a2dd1f9955ca95b15e42ef475718c0b4898551d867fa077ec94be32290adbfc85766152123334f13b8f87c5bf7a458cda28038d7f36e96bfeb6b91df00343cefb8c26fc8683161e45acc9bc9d4ac05754f806485a5172d2c01712ae12d6772b323d8ab8ae539c9b63e7b5d24bc26be8b0c209e2673719b248018dd177d155f771a72cbef40d46d8532881034c9ddc0466e81b2c2a757ed59ae78f00c1a0107272e1a6ad9f92d451e8623c395b5c0d3a8415b400c12d18ab8ad29fa74b90203f98a028b18353a9135a5792fa86076065aad30842dcf409fe980a90baab6b2274232c30521815de3f192f98a57a6b36bc944a06ad4819acb42b9ea7a39afcc588cb709fd7864ef280310d1e20cfc13071ab36e493b044868172404f6097d1e9030d542d3405469813dd47b0efdbbc241d825bd711d6a280688c74a942ced8ede88d27caeedf6b5d633316027f04edcfe6cce", + }, + outputs{ + difficulty: 199989, + parallelism: 9, + input: "030fcaa2e7d40ed42e6eb57aa4660c4d372ae66b0b492e7525b42814b7b20b8a9c08ff1007373dd8ce227f94ec68dc828bca34ccb7b47d581ab9636590c4aa950457b1d862b4ff119441", + output: "000000080011df7a870bc84463fcc4037cf0bd450ad7b421e2e5bacb9de28b8b0acfbfd328f21a40adddc47cb2f95d22800a8b09c8b2ecf70457346f137eda5253a8a3bf95c2a89b308c2d55e781bb4669a4496cb888f5a30ff28f7ee59f7d947d72e2ddd5cb00f6bbb64ffbbe28596bb13fb98a8b2be8e4b09dd2ab5f0025546204fb68c7fff2a37845346ffb9d8426e74e2113a44c5ba5e9bb6e5cc8fd096094f7a270efd0c3cbaddc7f97bfcf4b092534638532a96c24bef3031c11778288c09e37bb2e6c7039195aaa9b08192b40406c2d34d980643db0681ab2744946064ae7957a4e6fba4c29e8637cecf3cc7968a5d5af4f0591aa1f9a3f117cfee60969fb4cef0069000ccaf6db8bb32c30685d65854d9182dfa1f9ca03635915891759212315b9491efc45ea9002109a590f2ab1f9eac831621a6c1558f3be3ea57bc6b452be642f1ecefa77aedc7cb44b199e86cd86f2666585f093a82e8f3449dcf5fb2a203af51cd339d5e31d87cb43202d5bb0e86fca10260437e0e1fb9aff5812455723b49a90fffac9cd9f60cd2819143f60a421efd6e5edb34b9bff0d1ca176b94c928d35035dbdab5a934138fc9be934e2b99dde7cbf7a7898427a5b969a7d3a322577fd97e6cd0c37bb0f911b08ac1f6e90640252927e1e094d3ffca1966469623c7578b5bd8729b358a771d49bcb1521253e8e2150acc09ea9831bec30e857557cc898b033020d5b76aef88a805781988a43d9e5d8942b1e5726f0e377f8ebf05b0823206f632e16f7b02e7ed9741a6348dcc01d5a5087d558ffd7626cc0a33cbec154b90250ed43c901f9dbd1b819020587b398d34fd83b2be0e33bf8fbba02e1a6797222a2cb82e7b950cee79f9622daf23afc78be64cab389dad2d71d8d145126b209e3540aa3df3c4b8357ecbf0d87671476b5fe56d6b9", + }, + outputs{ + difficulty: 199990, + parallelism: 9, + input: "020197feead2d1a5f4c6d8cfe82e834d977bfa6e17bf506e601a267c0bb3b6f4bff8e24ceec1fad038c2e5e4c5771e8ab1cc326f7a4d98407bc11f43f0dac5dad910f48c64421997b992", + output: "000000040047c6f02c20b872265d3e3ccf2b13bf76245e7c4d591c1322c555a2e88f884c7b1fe9b0bbac87cd7c4335fa7f26f200b167c43311d22544f1034053292c0924c4c76e012904cefac6181ec9b10d607da7a2ccc3ee9877e50ee516bd67754fd4d985f3d26e031ff4fc4847eaa1ae97f8ff75dce6b3d67d8bbd6a2b1af40ef4df29ffd6cedc7d9cf0f5cb436c745bbb322403638e11968ff35fbfcc382e7777cc1c475f05c9ede9c3a7561fabab4f34519c02db60b74ee6a0428d5a412a04b299282066c0d35b15886db378054ce2bcdb25cde3726efe2e9af93c2a37011fad4f9554ee4f4dbfb1c22010c85015aadc6c6c0287d1fbe48f3a3e168ede8b7df29d108700748e9b74719adc12c4e53cbb6b2a44691b765e980d30d725774fd5bc1b51b69b96235bf102212a82df15014268cb8d99c432394dbaaca839ae3656676cfc2dbb85676066f7ca7770e8a162ba2b93927051e672793019015544187ea3ce4df7cca4d864846e236e52402141b6d3a00848ee5a12d3f78965753ccb379fecfbadceffec18df46da469db714a03872f6520e155253d65ebcd78b24fe87f819fd6c1655fb06ab7372f2ab031dabe4f4b21bcf565496a0a5eed3dcb7d68cb8a0be65bb69689233ec79091c5b33c6296cb361021b187d6fd1009eaaf2b99712ec937ab6ccf616e4c20034e008e3138cab79fab169f12831694f5a802c7bd0f44f609a0761030fcaa2e7d40ed42e6eb57aa4660c4d372ae66b0b492e7525b42814b7b20b8a9c08ff1007373dd8ce227f94ec68dc828bca34ccb7b47d581ab9636590c4aa950457b1d862b4ff119441020c5dba82d3b97df366e4dec1f9d7a236e5581f2332fe9a9dbc36e7b566d9e795694e38c6cefa8d68e3532e78068f8c704658aa134c28e792cc2ed449548a2135ae825eb20c1e8b0e75", + }, + outputs{ + difficulty: 199990, + parallelism: 9, + input: "020a52759cf2b260f4c7dcdf70de6623bd7f98849e57fe38d356f8da7703e23de1af04e71b619c6a16f53dbec872ba295b441353decf90471526fdf236a07a179c04a19976bb3b78fdcf", + output: "00000000001360d62092fbc4bd2b8b22b1077b2234c7d131717dc2cd1bab085f235600976bb6c5f56b9314c0a0f264f4f35c82a03a6dc212c0ee440ed5cafb780bcc1ba377fb42beb140c80343c02dff9526620ac87b4baab647f745449c3a33352edf4df3ed64972e27e5a6185103c3aa80b9a9cea054c1d7d1d3bdcdb742a192e62e9c2d00004a2772daaaf04718b83e58809fae9659e6c2d85f975af0a2a28888f79a35d4dda12934fa7fba011f992a4eb7a33ca4ad6e4b59a5aed40b83fb3120e9962331d9933d3e4d677697a93e8c1a29238d1df96d6116011c4c952a48d7606289fc4e3cbad283e3af63f64ec308aa1f1b98d23f446526a06d32e249ea63e3d0faab8d000da17218c7ff4dcb29b354758fd94bc715d15cc39a0208f58993654132178ef3860eb74377cd627dde4432b7cca3971471be691db263b74bf0a9734175b54622471f3fbcc38db3afe752c5d558c023401956d6ac31499a2aed8ca8f323f5d7d634202ce885b5e6f645e6c44f62eba1749e5e6ad04b6b235875b4102fc783ae18fffcfc2a171bdf281ec2d64212d02b97c66f09312369cfeb103710843928004cb4e82be7d3783b8e566eae6eb46ea1f1e1ee3a29e8edfab322a6bf6554c8c6e439aedea77c61ce375c48695e91aac4861563f8a5de77dae439a67b7082d19a9e4fb549c283d5e344f8cb45e1a7513dab69fd82c2b11ee0c754343fa8d28ffe8639020197feead2d1a5f4c6d8cfe82e834d977bfa6e17bf506e601a267c0bb3b6f4bff8e24ceec1fad038c2e5e4c5771e8ab1cc326f7a4d98407bc11f43f0dac5dad910f48c64421997b9920300f6e632a2485b6d0a731926f415bba9b88fbfa1468546033e3911012a16a209b4562907a6df9df62df5f4e86844b12fb0f4ac0761bd4d853009e22a2746acc4c9e5bb628b73e53d46", + }, + outputs{ + difficulty: 199990, + parallelism: 9, + input: "020f047f50c3ba45713de2241c443f51acbbde9702129d50d72b71f0998d93b0df785c071baaf6ee0856127f5fa2c47ae42766d7e3b09fddfe3f8236e8a57b02dc0e615cd79572807bf5", + output: "00000007001922e4b2bfab43f74b2c1a2cc13143cff01b26c548c3b14cd057ea13011e3728c7f45ce666dae0bd090762a9c861ffe23fd16f5e30b2a5d32f53bd6504936db1ef14b86de1bc6ea90588a843271d2564d28d6bb0c11be3f3a8300156618950154f08fcccb4ea90a5808eefa5cad2be061a567d5faacc1b1d82d7cd504cb28960ffee76925220a0f84e6c91d890f2ad9b398c82ed431f3770b3dd9e0af6e44ed25eba25f22085258b9555628670d7f59f5af2583990e38e9e2c7563fcf958a166a2318fa3da82b85d754b903064f7a7a6b1a3a075460c22543ef87b8bd3dac89ee4805e7cf2ecd1aaa2ba91a769a04361db8ea795442a792bd1282175139a6001cb0065d6ccc82ff4000043dfd6863cac1933eacb29c386ed3d384c2c97bf3a09567b60187d9ad9fb1fbe948b476e1b8611123022edf0a6880b55c2fd70476632837bf99e08e8743d20172f84e23345f4781134a1058b6d998d72e8c97f51660da1c8e170cb5518749ff502c31885e88eb65b86acfc8fd2775a55e79607ec4b444a74ffb33b8df9425dc0c1eac439d368878e6d32e60816d97ac598dd908c7dd7a9679b4cece7e95066ebf58791c5b81f326959233aeba9f840b87bac3a084c927b6679a904c7e918ef1b04c05026d19a2d4422f66311f58152b32169b17311fa536d5262145068989c09b75b3cf7802429300efb79ce981c619ab221d43b76309ebea5020a52759cf2b260f4c7dcdf70de6623bd7f98849e57fe38d356f8da7703e23de1af04e71b619c6a16f53dbec872ba295b441353decf90471526fdf236a07a179c04a19976bb3b78fdcf0300e5558872e28a9187cdca0bbf607497d0c68974a1daea2286bbf2dece55a22d796561b99724b87aaab0edcca402e1facd24f551a7853d9ee35e31c19796a48b29859b794f11a3b36c", + }, + outputs{ + difficulty: 199990, + parallelism: 9, + input: "020a1704d0aad00d7b7606210c77cf456661e6381c597c86ac46bd566f3248ee38eaa99375cf589658ff4df7394b02296416ab9656d69c16c170034ccb21c9c4909f24cedf4ccbfecab5", + output: "0000000100009eefcc3f353b3bcd91cc53a305e67ad0344d932fe44a73534b61c4108a2d4e2c0d451a4f923dc07217cf09be6c8c922dea4d27e8363fd08eeb89c22942a215df53d46988ed54e300202919b684a9ea32872e062160c90d50a8437e41742083090cb49ab2ad4ad83eadf66f7d1c28cc78d835fe50efd4acd8dbe53e41d9daf7fffff6f76fde6337c6ed95a546ee4f956c11b5139c491ad7b51d2cb0060f03bf45ec54270936f14f5da33780abcc7348916f4a8fd58e5ead53a18cfbb6cd35db15341759a193823a5065d8e30aa62c6e9f48e3b074eb4bd3ec1f32b6952f1fc58d39feeaa16e1108b75b39ab9df9368182ac1c4a9edebb7787d338ffa132981caf004fa8e867b6feacdbe4d864e241e83e3d5e54927ef509abdece154a430bd11b1c2fbeaa02c576ea41d6f019716f02b10a8a179e02abf13044188c7536a2e7e1abfd880066592222fde1011ab68ad8ba0958432a2fe5513e11d1fb6bc7a01e242d44c0ce4a302cafd96f7eee1221178496a3365f1160e5d1301634bbb625a4783e0017afbab27f0700b68858471bd5fc0656059a89a64ffe1d96927138bd1e66fd2c6e521b292f07845755915747d4f6e61b625ed684ee7bdbd2e38ef7a8accb7275b7c0bb57bc98f18c6d46cd34dc155d12a00c056a1c1ce562d8da3966325ddc1ffb7a87c0c66ce4a3a8b43a1e405ba09334b861f21bce7730df40d512ba579ec1020f047f50c3ba45713de2241c443f51acbbde9702129d50d72b71f0998d93b0df785c071baaf6ee0856127f5fa2c47ae42766d7e3b09fddfe3f8236e8a57b02dc0e615cd79572807bf5020a44d2cd993244a986abdb7b243bb80fd79d9785dda5703d36215ef0b7ff8df29c8950a190d69e7614562ec61a64a24ddf6305c2f90dca050043edeecc02467ce93d01700185294d84", + }, + outputs{ + difficulty: 199991, + parallelism: 9, + input: "030db08c85a47781b273b3fabe27aadf73dce8be7c503f74fa8ca9a80ed18094865ae0d09ea3eee77fc01ab6c2594c2c45a55dc2cca094f9c0ba07dc5bb31de2983503b5acfcb6175a73", + output: "00000006006bc5db90bacf6caa51ee05b401fef0ea0649ad1c680344ed3e40c78b3b3aa2223b4d742c0aa9aa51c1be7c4af3639229ebe8dd1a466eb3fbcc6d0e3e88fd050e8a638608c2e48b8380dafe217546f7888c0f5e0b3c2fcd9154f8ae7093122c0504a0ef9c55e1ea89702676a54037c2a84a0c9454b10c659cdceb42b5136f10c4002e4dcf1e04ebf360ebe6305cc0ba9cfea002e03f1ee2456878a210b9b4ca486ea3b143d8063dd3262817a6bbe0b0276f3fa94a6a8ae5dd3a66af630348f42b3225b48b312d119ea621b4c2c2c4745ddc57c4573c84ff8c540b85afdb0f9a01db7d9fcf97dc7b0432f605e1505978bfc98fc421704bf5d783cf59ed1439add59300135400b83c8f3bc9a5b4f3cfb2bd6057cc4e8a5e0a910634312243b766d448fe971e893a888ba1a708c7d87c1bca50d33656e78a8f11ab48cc5620d655e70066819af1b6f1349a03ee5f6a0f7989b8a59eca2f458a64099381ecd65ac4398c2de89e890e60978dfc5d1404933ce2573946444c7fd2152c284183955bafd56a51000a62d4fee56b6d005dc12c5acb1db5ae8a38d113604847dd1f29631f2dc205cd043712a7e9ebe9cfebe5fc42880ea434b165bf58eeeef06c9e16d995a088f93ef6ea05a2d3095cc27c7860e1ed7b60d9abe88591b76eb4aa9ef8c31a960c0bec3c3748b6493cb2b286246ba741efab4dfb8a716e7ac6fe8cc3badf85993ae52b020a1704d0aad00d7b7606210c77cf456661e6381c597c86ac46bd566f3248ee38eaa99375cf589658ff4df7394b02296416ab9656d69c16c170034ccb21c9c4909f24cedf4ccbfecab5020c76d32979d5722522fa55a11f853dc2b4affca26260d59d26518ba36a31524c3c6f39a67f04290fbcda786f3aa81480f3125f79c7ff75d29f1bfcb5eeb8e3014a32b24fa22ca4166d", + }, + outputs{ + difficulty: 199991, + parallelism: 9, + input: "02039555818b69143cd94b38d9ff787b1d7f79ca4613d2175a2cfb69d9679962af9e68bd6667b8f244017f45abe2020b1851a2264e39677350172559aadbf699e9dedafa9320f8b6c25f", + output: "00000005005117f68dbbfc899b3e70d0b9f818b5ee17e6c7bdccb891b736925d0cc201b385c727ea253c30056f28e9264fd4d4c86a894de6cc0525da4b67da62e6b9a68691b4c5b6824c7ccb59c460136c56f413aba6d8e26cec258f858d674862791f9cdd62d0edd32997e023fde611a3d2cdd6070b09b96b77046297954b4b16a049c4a6003b2477c9f02885dc85710adb498e21f475d31cf9e185fdd86982a74c57e4e35c84d511d050594bfe6e5951e8f293062921049b732afb6d7e9ae3196a3bace98e5787a9a004405e723769b0390ea7cacbbfd60a0c8a926496719bd798e9a2fbe302563dac2166d5684c6554cae4750cb3bf0fd0f2ffdd654549d57ed4b791f27b0037d8979d52062dd2755d54ab6318b41af13cc6603d7eb3ab7913743164e22d8e245d1170b9bacd7615bde537642847beeaef3eacbdcae0fc250123f85755c4a94bc4e1acaf7454497483edd1a59d28078d1638cec78cdecf93e8312de295b36761a92e71b55cd5ec14a679a03029e9e0b0f90820dee05db2ce0cca496f911120ffe79bb17d4b47af1d104952af0303bbb3831bf56a7d405001e4bbb7c3a6f53fe60b12bcc9de441251dc27e055aad94928a615e7f60c6208fe815af5f93a00281c0a9ecb62ff66b1171a88c448c072f99a56d345c53e6392b7b2cc7875022c8e570e9782ed1629bffe8fae085ac9f72a3af0fc093dfea55c2ffc3f974fce4a3ec7030db08c85a47781b273b3fabe27aadf73dce8be7c503f74fa8ca9a80ed18094865ae0d09ea3eee77fc01ab6c2594c2c45a55dc2cca094f9c0ba07dc5bb31de2983503b5acfcb6175a73030291fef8f2033ce7db7f5d977268c9b05d99605a3d244ac0397bd987b2bb991bf710d9e68801dc91a050dee740eba6fc834099951d14358d51b16e47728452c9f344dbf6b7ece5bf0a", + }, + outputs{ + difficulty: 199991, + parallelism: 9, + input: "030a9ce961dd698605d2bb923fe0bf5a3b8573a6d7c6e4171f66c72ac28e1fff6404be0656ad46c130132840170bc429517cb07fdc9e29dd075280a25d123585e84111cc26eb45b02a65", + output: "00000008005221993ba5738c62afe121dc054107e2b39a45312309f15db9caa6b014f925f397074365373788a06cfec10813dca19d230736b0d0c516e8c761ccc9effddcdc450d2f3f1022fecda6ea757a6b073fa6f70389598f021ee9d5ea7ec14cafc90d525723092502c6567e73354f31ca408175e7a276fd8c0bd53ae5898b0eeb5038000a4e99b7b4c221b3dbaed90c832069356edea42abf7450b3f77766eaf967edffa9fc35b713752073295fefa3fb4730c52dab0955cf815e13983a89ad77ccf0da8cb0e08240ebdac6197eddc38a1f910f82a52206126a6d6d187a696c1521b6e68a2d379e89a4fa553fc340fe4da3d63eccd782060484e97a0c12c5e0110c2ea900123fa35bbc4650980b60b14f0257f454f70eec99e6112086531ff8a387815db75443d8eef94854725b40305633d3ac3fc8a04ab4ac64bdd30a46d74a65965be2a6e9731c33252f374ef01866802ac02bbd4fada635067bd385a1d6bd5a27dde0c9ee550d1c36bf0d7f2836669d85b7d531ce00f1090191865826e178dc1ad12bfffecd712449255516dead83cf1f4b5a73fc950d53694067fa0b4ba042340e92418b1e2b6d66810fd63b7f986f35197916615be104f4b210a83570113bc9627c93fcfc97a207978e74980d1aacef9529efc28cca9e8c14f325efd51be2515f38dfac6643816151b92be0a0ffe427ebc1aad69a91a4f3f6640bf75b98b7c4881aab02039555818b69143cd94b38d9ff787b1d7f79ca4613d2175a2cfb69d9679962af9e68bd6667b8f244017f45abe2020b1851a2264e39677350172559aadbf699e9dedafa9320f8b6c25f0203ad5ee85a50e607b63deb0892fb029645771e4f2083fa6ed5b83ae18b7593315f8971b1a5c8c9178c36bf87813e27a716a8e6be02a1695e10fb876f7d7d2883d1ea51a1687f739dd1", + }, + outputs{ + difficulty: 199991, + parallelism: 9, + input: "0307cb2700551bef7b4ac62df60406436f4123a34ff86b53e20f9b154358744099e706c25021ae7a3e208e8c3cd844ce5eeb2802364c64222456018e97b0d4b46148ab8d3311a9ef3c43", + output: "000000030052ddda85d6d9f1c57bb5bbbcb87097bb6c0198a20b504de478a0c6819829a21d36204db0015c8a6ed5b6ca2f865538a1c93d26f81884731553a63dbbed6f209767c3f59ff954ddb72f554d7b561fe686bfa446b544404d8c79c0c3f6eb69c07c72bb9b3ecd1c1c623c65fb4554d24225346f27061cff63aef20c963caa71eb430041407b803cf21342aa740be5b8b39ab76fcf6dc8d3cbb28abb5c46fbeedf38b8e84b7d548f913c793f01cd1b0ea631c57f86062a22c3a2aadc7b243c8b5a99a62d55751a652c8e3d0f87c16e912f503fc57e43727e28c568f8393eb13111ff7c57a89916a75059ce17595b34e269527ff679793be300485aa07a7ce47838d2f300022901c0af0477a5f24b53c3851c0abd983a26ceae948a0c6a5cd42be93825ed02978b734df86f54c51ddc674877d727abdb2b94b447ed3be1572739d500affc46d6496f345d99cbb4164a40a53f44f25d2020f8d1eebd5fa0cbb1a9bbcbcfea632d3e9794b9a5800a4993d9b07b2e9912dff426283b31bb7031aebabd8a5afc00009772c91cf0a8c4d3e141b9646d4e6f409d48e0bc669432ba93353756e696d5436f21f1767f1440dcc2ef49eb03afb0a894d935cb31ed90dee0b8a0106d214f4d664dd443c0b32b8a7bd3d5a5c89e701cb185b22685ef6b42b8e2ea3ab3ba3524b22a000b0d7abba3edc37b16ad96935ac6b6a7b31e635183869e0b21052c8d030a9ce961dd698605d2bb923fe0bf5a3b8573a6d7c6e4171f66c72ac28e1fff6404be0656ad46c130132840170bc429517cb07fdc9e29dd075280a25d123585e84111cc26eb45b02a6502035f40636663190167f6e0b8aced0e3c4ae6ef8b4f62386aaacd63dd990b0e8021d8f53ee48caa9987b251bc157e062612eb6c734a25008b31ac17ef0a21eb932bbfaf3610a4e9af1d", + }, + outputs{ + difficulty: 199992, + parallelism: 9, + input: "03016ac72c882dab106a45f2462776cbc35df79319e550f85cf92be2221af8b0528fe3c020316a541ae88cb1441c38c02d8be7893302de36ee05883d9bbe29b4fe9a9f1d49ba0d3630c2", + output: "00000008001d594d189aa1a45b5e1cb09a024b6f4b69b4352b9ca4b953128cdc5f2623a1ed5bf79243b9e68885a204953cd2dbf3b03a1959f6fb4e4f61d5565eaa18f166d59a8abd267d329545d13d6cbc34468ad797cd1ebdb818c379c1213444f62799e76841a7dae35cfd8f97fb8aa6c2c8e56754c1baf6033b4714e3e36af532187b7a0002b0f903e0ddf8018fc6246f8741e0d9f0b895a9f8573f7048f4867d230f3b11ff07ccb0d0ac27a2196a902d20c93057ace039ed210fbed37fbd3a15897f86551cd9cad7c242ff9b3a260582085244633bcd4472bace17dd833fb1965a74965e49ab96c743204898a2cb6ca034849f62fc87159da7b891821a1fcda0707056b10050d259b1d439b72e016d3ab831a111a8014df3f35787a989be5ac1592d58b8df61fad9943bf0ec849c3b5c1a81c8b8618c7f20743854798fdeba15b40046341bbef33f6d5e393a806aa9e9d5747cc7dadc9077d2a9e0bdfae2b932a6402dcaa3384898ef013f2dfb5138b9b6fac77b57feb0178e4f937fbbc20e8880763439ae004e17533803eac203c4e1d61e308644bc754d7f1a9a5f8fab4b0a2af8f1b61b19ef66089d646bb1220ed99ea878ff8785bb28863ec835cc8f58e6bfc44465289b086e4e91c3a7a9302b2622cc1b7f91d37434191dc484042a5a974145e3af11add8451b0fdf94127d12d14da604d384165921180da1ca756440a3c691f38554530307cb2700551bef7b4ac62df60406436f4123a34ff86b53e20f9b154358744099e706c25021ae7a3e208e8c3cd844ce5eeb2802364c64222456018e97b0d4b46148ab8d3311a9ef3c43020fd1031c76aa5d23764f6d3cc6b7e02e3fd3ba23a4d102401717c32217254d3c76701b0c293e62f9e09cb59b1d4793ba9b739b3ecb7d7410c7c1c263b1f4b9ded265e2075476bef09b", + }, + outputs{ + difficulty: 199992, + parallelism: 9, + input: "020ab488f00fcbbc7a0c176533ada28ecb5d9678694efdec360a61d8837a2b87a9a987acf1cfe2a71c555ae31e8edea623063fd63b149998e5c5246d30939de8951774af083e7d09ce36", + output: "000000070031681cdb8db4133216b0e86d58db4c55c8e1d5f31241d307ef4bbb0eefe57cccb7a9404760ae76b3c3a84b374f5d36fb6222f80353055ec1c5d43440720ed5a7d1f54bb91bf80b92a2659002651054bf2b937017faac62c0cd507b510fa597dab49ec139faab1a0ebc63c26c45427d71664e25305ed4f981c7d2725e756f45d700148ddeaa8a1e9084926fa41ce6e9056a99088ae80589cc7c7b18a241ccfc981259db9bd43ca0d8f6da3ac2015812a4300f4d6ccd8e3b63718c28fcd37ec4012da55642e36131b4956d5d9624d2726933fd34ffc2a73bfd9698d0cc3cd23437dccac1dbe159f08b8807ca5e9192486924f5a94b8bb3f30147e8ad17562063768b0032cd109873c27aa76e1aa46985074f3e56bd91842996e4e35a20f7fda2eb3a938b100089140d70bfdb2f9ad9a9156c9af2a6822339b68cded95da88a87c7215818bc375ad6241034670564f245e4b87c429b855cecaac875e8ced1fc4e4bf68cc6144ef940e46cd3cf2afba3afdf264ff818f766db59008b8ffc3727b56d0bb6000b10ec24dade0d71ce30d5ddaec45de109337c4d224f82f34f2456242acf4a458a3df40b7f00ee0ee0f30e41ee7b7143a755d5f079647da7604bebcaba686949a32f365807df5ee276cc6c2238628ed66213b8af4295a7de8ce52d38d9f78102615dd17fec469d495971a8f5195374b8c182cc01372aaef5cc3d303dbfc065dd03016ac72c882dab106a45f2462776cbc35df79319e550f85cf92be2221af8b0528fe3c020316a541ae88cb1441c38c02d8be7893302de36ee05883d9bbe29b4fe9a9f1d49ba0d3630c20307328d24183a70cfbd8b7f7065c7f12be65ae2c96a165db7c4565fa531780d4e59617e3dd54c285b300c382b48c089b41d0c48a234042fb2356b3bdd71f60c2c9fdf46d9d36e19e907", + }, + outputs{ + difficulty: 199992, + parallelism: 9, + input: "03052a304ed22887fd57423d8ff9613c7051af69813bbf40ec7e55b2a88c659cd91ab938b9a482112ba5f2531d9e5b96b1aa57823f8563abfc3517d18ba7b8d5cd3d0a0890c9aba9f34f", + output: "000000030049657d6a27236bf155cf497ebb304a8accf99596428d5f4d536dda28a36e70ad59aec38accccb28ed3e5a3d020ef94beed75b48b4ab760de64930d12b9b0d61b7ac62e6d28f01a39e99e2854a2c6cda8f5054ca871cb83b4a9ae0334c43bd8d26e8d33c3866a280e4ca9583faaa8b3db794633d77f934f987cde3736c8f64eb6000f6a28016a6e96f2a936c78e2bce4953ce54b1beea5cc1635baf469a7ae2a92d20cde7667fc044d979778ac4ecc3ffccb8477b63262228dc87b3917efa4d95724c7447fbe214f3bf7f5882739fd88f66a37b02130b176bfac17dd2ee8350198c4b204932562222a66121b17cec857c951741e55562026395f889239bbdd523cf0076ba4612369775b9f49c536b506b92bd867adc59ac7b09702bb70392f26f45edb21cb2c597fd4b5d805d04084d45852b1a94cb53ad8b1f0e7a55f6102d1aca2fa6fb9f9469b44d79777bdc5b5b7114d38e784b77d26cd32e7654254127ee36ba95da93483ccfae57df6980975b8c8fce0e6c8db5190bd325b243245750026d51ffc3739f5a8fee0b3dba929df255d480daf8b0a83ee1bf2f9fe7c5d21747560fad6739f506314afe2b7b7021b5b4ec0eafe40afacb28d572a19a6ab71e285a77feca2542ae4cb7b0d7569e4b8f9e69041b03b4bddf8605c08dd91c772f62ece27ccf0041d74e327e900b8b7a2657b4a78d132e577b752b4b8c464bd723cde8b23d020ab488f00fcbbc7a0c176533ada28ecb5d9678694efdec360a61d8837a2b87a9a987acf1cfe2a71c555ae31e8edea623063fd63b149998e5c5246d30939de8951774af083e7d09ce3603120ff5ae2bc6338efb6ad448dc054470ffafeadd5df58f22a3421225628af6255dd7c816d2a50e66314184bc9dbb2be373fe1d3a64fedabf3c3074b8e1b25823d600c55c5929a49975", + }, + outputs{ + difficulty: 199992, + parallelism: 9, + input: "0302961f11aaaf63b0046faf807ed03e28aaf4a95b0426eea067b213e81aadced90453c57b084cdec3db3faa6cea02b40d296a17060985ebb16261ef434d82e3cbb5fac075dd59f92b56", + output: "0000000600048b9cae9959c311afcbbbd03ca3d7a82e2fad49af9f17513ef90f6034b21e37e0df026707cd497b7fb95fbbdfd26420d08988149844bb067906b697826257865404bc9b59a178d709a2b3b0a03b3f080f80b5986468a202125f71b1d907f8e4bc5367bba8421c733e1d07e57f34691df246aad584f0cb7d24d334f9ff9f57800002c4b516f7d923c64d9bbdd58762ac784cb320a5cd499d76653bfdb1d73e3ae91309df52644a7f34c148f8334464093afcfbe44d38747c9656a71dca78c6cf4b87188b64575ae3f56ae1c8a61b6714c6f3107e5a48890206a46afc09b2a48d8c59119b93d78334abb318462cabc12a8844f2a38b4665f65795dee7cdc1ed75cd003aa8782db183e5d6c5c36ba67319b7e0f7d6b788a41e1b14794bf643b1ff814f323ee8d35a899b02b5a9c63f40efa29d6f03281d3bff1041fbecbc47073e1592388c957100f84604d6ad845202d8d0eea4266b02ec0682c44bd858f354deffedf37fad2a50018fca039375ff5083ff9ab25cbc45c8ea61a462001e8a92056190ffe3904dacac9333109784183ef1e684a6873517a25c62af2e56e96fd76dbfc1b4835b997892d9f86057098c2a6c50dad1ad8d06a97f9b687d3de497d19d3a971731a2e605711bf67d758c22f632cb3d52c45c9415d637b403cef6c1de771f569c0c375c8eb994558576b4a10b791ab403d1d2ffb5152aaa5d325c157b0cc9bdad03052a304ed22887fd57423d8ff9613c7051af69813bbf40ec7e55b2a88c659cd91ab938b9a482112ba5f2531d9e5b96b1aa57823f8563abfc3517d18ba7b8d5cd3d0a0890c9aba9f34f0304cfd293b9df150e0894c160e460d6f5283ce7800f484ef67e284ac9c154bd967ab42f6f2762ca4d16375412fe9cab4c5ea274745805d34ba2f052481b8de6b6fa60873de8a044ac4d", + }, + outputs{ + difficulty: 199993, + parallelism: 9, + input: "02003a889900f60c169c1e50119e1605796afdcc9e134a62344eb1993f8c89591fcc7575be8762821f1fa2736db073e7e0efee17a6bdb7fcedd1f3cf24e73a00b05f5621fb1deb3f594c", + output: "000000020047a22cef1ff3f7b22d4b850ccae827583b2829fac79fcd4ff01e47be897ec82779202c953841568749f1f3fa3a84f84eef9bef2a4cc5321e2995426397079e6879446d7dc4bf0e611d90e78b25621dac5006665993d576485be79739cb9be0faa7f23d8a0a76a8cf768bdaf528daa695044b804f09c62bf67849143d245ffde80037934ef103124ddc24ac3fdbe2eb157799fac07f6bb9d91a5d0f16d166239934d7f013dde3873238ddf7e9a06fe93992da1648a9b3a996d42f413a794c914d1ad5b5edcdd19cf63fac3236e8588f482463616cacd9f0cfdcc6f33edac3e201d26331da6a83a46391693267cab92761549c60afd80987e61dd76a81b46ec36735005332c062556984e726153f51723731fd9222c51c4f4092e21c71e9ae7f35db4b776b8ba26cd259391cd576d6935d002dcf179ea196dde153410444ba1f3ce030e777611f6a41fcacb8fd00a9166ff93d474c977898c9d42f519f332cfee128fa3f8065a2fb516b8f07dd66af7bc431523e5950e6457a93ffa72c9e706a6e9e7effbc019579d95013a738b259376db1cfab9e66051ee64490001fadbbdfa56275af4ac962cb4ccdb111fb0d1928a80511ea5dadf2937b7e4df6909d83f3f11ab0a7ec893bd79477e01f221c7da93f5fb09ee6984a6c482b1aee159321391f381b536f90382e9f6c506b7d676a4bea981f7be9b9d71ab7c5585d7313b943a959aae10302961f11aaaf63b0046faf807ed03e28aaf4a95b0426eea067b213e81aadced90453c57b084cdec3db3faa6cea02b40d296a17060985ebb16261ef434d82e3cbb5fac075dd59f92b56030c0c7789a9f8ecf9b23a7d306aa8f1a42dbdb91bb824dcf2c64019128d2a221de0d1bdd9842e9621b2978c6eec3f0e3018171b69a8e600c083a47c972cef39b403ab617006995cd7d4", + }, + outputs{ + difficulty: 199993, + parallelism: 9, + input: "030b2b9fe6b82876ad6f10521e64bb204cdd87f615d6b1feef80f812c7319cb518550ef230b18a30e8bb835388620d9b56a27b4f561a26ccfede8f85402f660a36917bc57192dfb2107d", + output: "00000006002f8c60bb0ece07403ea71a0fae22027a0922a7704988088ae9b048d668da1f890dc4dcd5bf265401b8e8d970537f4d64b54a612d86f411b556df8cac3f64d52d666bbecac08a48f8cb3746c0c4dc04a07281e276517aebc797c81aeb574768efa2a9a8c89baaec6f88f95b5c90f375106750af7cb2706410a1754873aac7755900053578cb4908521f5b362a15d68e0d98ab2707c5c5adea48589fe17e848bbabf05ab67180c2fcd088597aac9ecea3bc0bd9805214a762b5fc149b23545c95b616a87a34b284736be1adceb7845a899e579ae1d15c96eb4926936fa3b820ad7de1dd685a4e2e170887f2511b274b3c5cad0fae2db7da7b3e2398163296f967c770016a80095ff396d0f1daeaf2c2e36cbf31402e4e12c7e47b4f017c866b3444a1f1a7375998b3b2be689a7e3c1c876e4b88ecec137b8fbd4f2aca2ad55cef634364362a5c358aca08cfb6752e2e05070a887d383e78a96f9e158915b38f791a0e2de9d85ba3bed25cd2b706354b4b88d6ac5f920e7293d9c6d43e13ace0395ead700119008aebdbffd098503095954f3d6829b9ce574a73f3b6cd164e4ebc5676be33f34221b57861d42110267d589aec1279cf9bd44565ae6a9a9274239bf47c973f737cafff1e93213f08b61628dafbc925cc7a00ccee5d391e4af33a07a74a65d2696f3ff72e3e40393ebd4842a2e9129e86a1ac02b4bf4b2766407d0f1c27be502003a889900f60c169c1e50119e1605796afdcc9e134a62344eb1993f8c89591fcc7575be8762821f1fa2736db073e7e0efee17a6bdb7fcedd1f3cf24e73a00b05f5621fb1deb3f594c02042e490087d663167280b9349594393b414bc8884a74cde7f7e7321afc0725be92b0610f29d55822c185b89bd6d9cb7cf1286e4a85f8e2bff9d826552c5c2eb917cd3bd482759a94db", + }, + outputs{ + difficulty: 199993, + parallelism: 9, + input: "02038084585131d7f54fbceb4e09d18145bbf20d5670e4cc43c24360d55461adf57f9b151c722dd3a77d886f7d7322e1274d25b2ea4de73963ff3044d0e622d9ee94685338724c3e90f7", + output: "0000000000348bc464bebc1e7e2625832d03f69996ce92d5904d62e6b87a53b9ba0cb5b209f4960c0097d62047ba2d463edae3bed38acbcae76432a0e0b89118275ea3171edcfbfb85600a89ff4022083f9b471d23e1b120e8099974e6429e6870ccc6d4de122266c9beb380b282c7062ae6ccd9fe62e7d1dd7af6d4dafd80fd5b5aae47e1ffe9296ff4cc2fe87aafd7f1fcd9d394b4508836cb33fe67863c5876ea6162a1d0e209504e517cee5c68593fdda945f377c214d38631d2bc0fde09bfe3f51c21dc70f1187112247eebf5b18b1ff82e0cff0c243301d5aac2fb24b4e12155c338a240c8f635e0c42581c697ddf19dd09e4a071ec94b3e149b31c9f55a93d01ab621002baa43419e6b32346a3e8676cfc0676fbc4f2710aada0e21fdff32c174d859d5aaa1dc20d60a9643aed5b0a1a85f1034a98fb742670b5081cf462e7286e1be44bd5f2e0558f1ec8339f166955fd37b5c3ee7b686bcb485a2c7fde1c110ca2269149b79e5871a6a29eff5f3cca3e81051102f8a112064eea3f11673d68ac9231000065a1ba5d00049cfe31aaa651bcbe35ef57d0cb8fabe1244d93dbbbe6c7cc198545267ed3e0808d9abf5cb42b1fa0b6056c8fdf008b9354a4efc44ec15672e047dab92a2317f9f313d14f3e44f54e5b2f61df4110218087ea886b09fca682f7774e76a8899a0e9442933ebaa0e351d6d36a6120f965ce701c52f7d07378acf27030b2b9fe6b82876ad6f10521e64bb204cdd87f615d6b1feef80f812c7319cb518550ef230b18a30e8bb835388620d9b56a27b4f561a26ccfede8f85402f660a36917bc57192dfb2107d020b84fa1f29c43109901d256aad8e1981c346528ce014b569434cd30685dc6a5a34ad73da3cc3b78487cb4ff4c81b7ae70e092d82aa046312dc0d3e5aa03d690177175624e083da09c3", + }, + outputs{ + difficulty: 199993, + parallelism: 9, + input: "03095c1b7fb646d6a1e768cd7d68c0ccdedc67f8b18ad233f9983fe4a3a3e96517215b73a2798aaa5a4908cb88349879ec6ed0cb1264f64891444bc7ea2bbdde0d4cb3341248018814f6", + output: "00000006007007adcc23ccf1aac803023dc980bacb11ac20c7604e4a9394ccd4a4a93949bdd640b472034bb037045c5f592bb1d563980645db840a3b52ca1cf5279b383ff31c05cec9aca93b427fc0bdfb1652f929e6f20d324e72a0e9c3b4f4c408504815ac1744ba23ad24bc3a634d6b25008a0b7ab4dfd1186614ed16911947f2b426c0ffb76e52b2f81dbfad4b6726f5bda1ec40f04a88a09a62c6898cb3b78be881f9e5d4adf4c822279d493f3fabc5c9cc3106c3df164729f1a5f7ccccdf4047b3feab8d9acf4544c48cb09a07e3506c76bf77a271517a986bf348326a0496b071b7e15c4ae5964e4732ad18dec058c71ddf05b0045db7a3418630bd6e639914c408df0050c27d5329b21e30f61602511838df6e4ca35789d37ad4b2c4ce370cf2b6793107b808f6f78f827afe935d5bda318245548e10d20d0196481575056b0e04bda504f20a1dfc60dff98f6e3419c748db9a922e2e1b99c221fbb33665d8b30c992dab14555016cf37d0ebac1fb69a7536b32144458c6a6267891d44164164463a0e0031a9a2a7dd7194c765f5d192824a0584208b2db2bb52dd146d8aea6801c1e2cc32531fc74339e7d47806cf1ddcae1acbe60ca2d290c66b9a35dad40af6db6e65d6f4ee3f459e7fed6869a3136ed5bc4132433d5f073dcdfd698732dd0bf732e2d92fb8a1887c1b33c6d194fb9ffdd22a7944c4acd4bb55acbae22fcd8fe06e2302038084585131d7f54fbceb4e09d18145bbf20d5670e4cc43c24360d55461adf57f9b151c722dd3a77d886f7d7322e1274d25b2ea4de73963ff3044d0e622d9ee94685338724c3e90f7030d09b0bb759eb0eb9031bc4d7097e2133ada85950c79089dc032b9ee503a1d23875f51e38a9be5dba3a287594112d6801e32832e9d477f296303776d46c6373f532cda1985515094ab", + }, + outputs{ + difficulty: 199994, + parallelism: 9, + input: "030afb22ebeaaaae74d42382a87cb390ea944a2d8dfedb9b578794974cf0bcd9bf4250f2c0ad024f2e5e508e358a5d61cc54809563ecdbe0924ae304ca5fd4714b2a5328eed2dcc1c1e4", + output: "00000005003e81a1783c9dab66e4e6a8e5d83f665099ab8400ae3d2cd67f419d166a90cf4a760d4af138e84866b6f81a56982c1cc9651e06fd19484b5111f52e6dbcfeded8ed2bf5f3dd087ff73bd8450683a71d011c56c3c44bd9b9252a10b9e3c71a372d23d496aab034ffd08e41de2bc972737cc31c062a17ca17bf857e6f54bd59c02fffcb59295d1d857e291b4eccfececfa77065362ab4af3d78e6caa42d26a720aeacdd31eab799aafcced9d771133bad4a9aab55d5e01fe2dde1148dcfa096c24b207af449863382791c421c3955eb77b2c1d1a4af8854a418d777c997b2399c8635a6b7fe39632de1354d11d5d3a139168c14c2f21bd05ca509ce8a518b7d40375b000748f1e314b701135b0fbc99d22c38d8df8aa72857f78367a653941ca39d8849b813d6d7e9e8f10e902daf827b3f6132618efc670f0cb61d199ebbc4aa0ec8cd20d696562f0ffc983fca9f4b55125e26658d2d52c2805164c6fa84f3b158bbb37b0119f74d15bff208aa7f0bc17b1a3fb8044c3bb8e0462e38257458cfe676a00000be71b8c31475100a67fdfd880367117dd193abd15fc7c1ddf857652f27a7536dee85dfa57572683ec1be650563cdc7747dcd8bbae9d27683932683080002edc2ea28781851e97a69c9ec149a9574d0d772a30174664cfd180d4ee484c75b2dee3fbbcb4a9d071e44df2ebe4609b3af79801c30271e38486977b254b0baf0d503095c1b7fb646d6a1e768cd7d68c0ccdedc67f8b18ad233f9983fe4a3a3e96517215b73a2798aaa5a4908cb88349879ec6ed0cb1264f64891444bc7ea2bbdde0d4cb3341248018814f6030cdda313e0f6ada1822a2335ea1c7a010594460a6e4d3602f245922ae9523ea2f641380577220ad3579573639b1439d58af334823d41c8fcf4bb1d53e8e4e24d741a3f930a30c1eb0b", + }, + outputs{ + difficulty: 199994, + parallelism: 9, + input: "0302ef7131bc4ffcfa4c7b999a088eee25fa4aded960882f772474035e3eb987a9844ade14026a5014c2fc38d0a312b86b854b8f7d7ab6dcb02536f7bf1bb25d8d8fd765f3cd460350b0", + output: "000000030007bbdfc3089b86e78b47604a616f9ded88d70ee7d86db1dce9b0d8dc6d1f36a98877938abc5ae76d4cb951e34074ab72cd64e18551864cb605a0893131caef2d3c2826d632785924d6c5bd07e81b9e277be1925dce0570f47f3a5ac12e400bf1bcc20160e8d01efe179e08109eff5e27e8e37ba2a3d6b6fc344026f962b52dac000618040cfad6f554652350acdc733254c9792110d8a00b18251f7db8caa19b76ce7e7a7fbda26f962094e70bc1a53d66effb0455cbfb55cedb5738eb887adead5f6617da66257417865b4ef70b166951b1c227dbb42fca3acd9ac8f188f9393bd2cf89f6101af6f6c4ccaf71cb0b2d1cd496e0fb3b2aa07d444326bef6ca5d5d0027be59d3fb74e51dedbd517ce226f593eddb2308e1241c1b299529edc43b161b87ee53f0d4e5dc41183d56170e2e8c78cfbd091fb1c369ee7de153ffb88bedffeceb34a36df959ffb9be95dbc734624ba806d33fec112a1782dd1946943f51055cc6b3f2a81e772eca5b5f3ceb5adcc0e42754accc71447a0adac92218d7b3b4000a0e110abae4fea1524d08cb09dc413dd12ca7a9fee1a598cb3d0839464b7f1cfccb2e2c9b5650126c2daee69bab0995f243a2b624be990ea4b25814e5578d3039c1abc6b85920e7ba4966b0b124d497f297ffd9f8e11354bfb0da7740b010025d396f65d660f7b39c9be35e5fb7bd651b347c4e1ab58c414d2db7f070074005030afb22ebeaaaae74d42382a87cb390ea944a2d8dfedb9b578794974cf0bcd9bf4250f2c0ad024f2e5e508e358a5d61cc54809563ecdbe0924ae304ca5fd4714b2a5328eed2dcc1c1e4030392fb95de40e81cdbf06e42ecbda97468e3bdd55878c76d731aeb9208f3bbe0e6c32b1883c5e405a734b4e3880349f9bbd4350950f0a659e9391e746cf838322c49f7549d451557db", + }, + outputs{ + difficulty: 199994, + parallelism: 9, + input: "02106e7ca2963c6c3be469ea304b51f7e515cef780140f84d172d4334fa799c0387f15299250034a05051728a823582cd7bd199b74ec46ddc80c6de7bc41cdc83adca94504cbd03b662d", + output: "000000080021ce8a3f9c2375f56443c8f60bf02b708d2ce90d7906001d297a912acb46d2c34fe8da4959debe757c4d13086bdcef1addcda6066a7d57f31598375d96106a23281f792ac3a602c1930415f185ac32192593978a5ab02bae78819c969d6f55f8b6bd29c7d050a7a85630e27329b7049afa2bffb719b5d8c6e7881bbc9ec2575600106dd4734d54d2be00e4cf57f2d1f41e080839a47d54ce64e35b3ab525d781740b3a09a0159f4dea10a0dfe7e9a4229d307eb28771d6e7fb83f1d32227ca50e7cf0d8efb3b9a754e0c03b8b739f73f14fa8d299c52f770ce1ae2db04997ea6069075f29a300b3cb4641d1376165ee3c3be090765be4ba708c57e564d5e2dfe6d001828759ce5e07eb834e15953220ef632fd2e793845932bc49271a8f6c76ce0c29da280a4bac7c359f069dc2d953b06ea893001d5f0cf520562674b9fac4b943a3347625612f42edeff34eea4d72eec2ac8ad7096f4da4c076e2277d517ea41a1786f4e6856661f2e3962f9781b874158982b1bdfaa4764623f6e7bd39d5c0deffff6d949f6ac28acab87fe800f7a663a5b7b357b221a910fb86c7c0a41bd6c04e38fc7b87f92d6be2bfcf04495a908206ca33cd2658a8a1b250fbaff522facd13b969df3dfc16fa6a7c421f87df6408889c0f06b49bb19af339a36f8bffc73f04d52ddc0dea7f7e1160a1b3ee21d4a1bce7d383d12519f6118a30ae53715855e0d0302ef7131bc4ffcfa4c7b999a088eee25fa4aded960882f772474035e3eb987a9844ade14026a5014c2fc38d0a312b86b854b8f7d7ab6dcb02536f7bf1bb25d8d8fd765f3cd460350b00304a362e7ecd8827fa8655c2021b12362406ceddfa1dcfbe45f10dbba5dff1e9f997dc45864105e512e50ba7ee5bd70c6137cace4314c6a6ea1b970f8f9412098796d5ddd09967a5e18", + }, + outputs{ + difficulty: 199994, + parallelism: 9, + input: "020b9ceb757ea54b16f7a8fe53c4ae5155be92777c5e258b8e0bae5095286b3bc786ccbcbc0e8d85bc17dc48c8f916ebfb1b8a22f729c6b2196a63fed4a3325e598247bffd654c2d059f", + output: "00000007002ec0c99e8df8bf7724930d8b108d3ae853cbe2418587431b3905da63d2c1f2415037a6d8dbd6c838ae1b6648f509438f9edeb08f9efcb83c3b8e7f9d77f7d440413f54087931104e9114151193e4a0eee506a41467f8a1b22cf5148d10d56fc9ec45684cbdddef338b628ecd83f262cb52810bc2cee86748ffc28799b3fc53250014983f11d8d01131ca82384b2781d3043ea2b678d5f731010e285c8fc41525d1f58a7bd644a8f7c6c50bec4a689d68db5de9c853a4fd9198dadb4dafad834336599d136161435482b1b9a054e4689fee41beb2cb066ad94b8695a86b592a76ee975634e03002efd81ccbedba1f2855c7ed63cd514ea3c7267697f50f0c9265ab004e75321af55945491332c87b33a104d754316a56cc6be15a2c8241089537063f1b63931f70365dd134899d3156549a0affe380db2368ba507e9c6a974b5c73d89fe5349664d31214178e6cd8247d28fb8c2d09c9332426dfa52dd2cca35fc29041495e7845a11ff025661541a171a86631e6cc303d12f66c87f15d2121567b9e00249a8d1a73d57c84c63694769d2e9020f74f6969219071edaf5acf43fec4287a8d8cc25d25d95dbbe5a50ccde9211f04d1242fac1399f1a3057c3f091e989460a95342af4acc99fe99aa944f64c5bf9f201bb23cd6070b45a909fb1c5deaae493e7916e3d669ae29e2a21471a4cfb76833d626d3cbce0f17d96af49d3acc974302106e7ca2963c6c3be469ea304b51f7e515cef780140f84d172d4334fa799c0387f15299250034a05051728a823582cd7bd199b74ec46ddc80c6de7bc41cdc83adca94504cbd03b662d030a0d51324698232d44c085f4887f30e12221a8baf2b70f295be65df34dc11d47e7bd2ca8b3705cbc474592d800c1a0e3b33b75312ad6ff24bc71875b9d48fd1fb7c7e70655840a6082", + }, + outputs{ + difficulty: 199995, + parallelism: 9, + input: "030e123b6d06ee73561617299c82890607d706873ecdcb4541bf4aa4c0677c4e00a31a72176b30dee4025613f5be0204105b817c9e47c7710703533dcc094ee3e8305bdfb63cca5b6336", + output: "000000050014287b8e6f2895bd7530b350c578c6a0a5bf243a764f5e95eed5db2085a59efc86330a55d07a9b711f59ef0e126e460c38b7c18730ebda6763496350df121b05608e861bd2c3ff0d8815f55b3ae8b2b82de1b50291938220f64af48ea2633b566753c26077f4a9fbf94f307a06f034c2805f9f70accd6d429283921eb4b7cf7d0010fb6b71a087f35b0992ad1e968db4bdf93f0cd46bae98b3a52c30d003c49c69a16d902bffc8796b4671cda8073bd53c3b0e028746b2fe9afba162e1db8467c2cbeb042d5ad3df25b54249ff35c1657a2f82b37a688220502fccb75e83ca76246c7ebe9b97282c2b8efb97fe8b63eee6f4e5c26f31a04572bb2017da43843633005fa6f9187322b64e4e2392bfc8529af59872d651b87d5ffb34032e45a9463e935e1617ec0bec510ed36b21375766d25e68027df24159a476fadf6ef3ac4b226a00f3785e2d7f1a803f664cdc6b406a00c05734719d5264344bc1416e16e9ced3d2fe48a669c32ecdd705bb716e67953129124398c6af3e8a5f2b11cfc7da399500082e05ce5d1c576d573fa03a1d3d991bd084d5236a045a739956a3cb0c61e92c14daf1b0afadab09566f53ba7639662300d6e424ac77cff353a57ecb3da5fc446d06dc050a876ce44e75446d946af71475d8f2be2aa3daa9ece467769e6ddccaba3c8cea086b9ad6816539ec9faa553dbba1340f72e18b471ca5e5361701f303020b9ceb757ea54b16f7a8fe53c4ae5155be92777c5e258b8e0bae5095286b3bc786ccbcbc0e8d85bc17dc48c8f916ebfb1b8a22f729c6b2196a63fed4a3325e598247bffd654c2d059f0308a9af1c6d75b7de5c52b02b7fcb36cddb732b898ea89669dce9ae3811eceebe385c3d092f468cedf3c1d58d35fa9f6bc3144ee1b163428e34be3a258a6e60dd75d8537151897bcd0e", + }, + outputs{ + difficulty: 199995, + parallelism: 9, + input: "030dce9c27343637e4618e5c76ac345499fd130a1c33fd56479912629f67662505d885750890deb134ce2b9019df786bd55edabae3341717e0114dc2421674c6ad9acef3362bafa8c7b0", + output: "000000050057c458db9c179b28edd754bf3ffd9f9843a864ac58728961d7e1b20ac696b42959854e8b78e4035ac83d2243e4cb4780df71595b09b1c56e36772c0ee12dfe76edffa566ef25faf28e13037c7090d0ad884460a61aac0ace99de1ed9c421be68ed99c14d6ebd2dae31fb9ec1a8457bbfff8246fcde2628c788ffc417407bdcf0ffb320bf8071ca2f6b0b9eb94543675bd7ded1108b660a23e1ddadfac2811d3a4a468c9f20f7904d053a61721155da775634d54491f9cf2f1919b6d5f71cad4c232b47d7645b9ccf7300c2d6cc98ad7b2662a63c6b9cb3a33fa4515de12c48616e6d21781188de5dfbfd9b3e5a0e06826d07d0fe7c2cb6aedf4337ecebed270d45000129b9eb8332fcc770d2921b4907ded5a0bafd04c009c58a75b9e3c73e45b8640885df96575a8114f17dd3d52ecb286806be98defdabbb5793f2978841e679d9998733862a614f4f7f8fa4ee1b861c08cbcb9e7505b88e8ced9f1bd08c2aced8d0be1be7ae65049dd649f7d0587829f110d8f92b2342ff0ec21b336722e60c020000aaef37334b80943102de83b064cc571254cf68dfd0b6ae08fa9c5d8daf9e80ad6dd16c28c703fd2c42dd89ecf4fe98896734496041e4b1db894c722248ea2280fe552356a6eddf4e50927fa09cec12cf4f5d7be6c9aec290c87dbbe3b5db2d844e50e3775b171a2b35c0fdf67379538151d53da3f33b15ef5e7df050383e01030e123b6d06ee73561617299c82890607d706873ecdcb4541bf4aa4c0677c4e00a31a72176b30dee4025613f5be0204105b817c9e47c7710703533dcc094ee3e8305bdfb63cca5b633602046024f3b8b264b23ef858c85c5f3ce24a4076e397c945adaa33b24b36813bd539a8cfa24f9c15f4597e7e4ee77f3432ccc14dfd469a974d59e24d6d04692e07e14a6a820330d0d95c", + }, + outputs{ + difficulty: 199995, + parallelism: 9, + input: "0300b54da98bc383c4c09e3a85cd30e51ac0e8911a7e90dcc8288e4185b411997af49deac5816d6b7d830740cca96753fbee126639ced6853b8b0ad9bb89b4e2b1b4a8bbd83d8c36eac5", + output: "000000020018c66061ccaf2316676e31471252952fae7bb631c03b6bcd5740c26c4f0ededbc7c9ccf2e143f2b3cb132817c60ca402a880c7ef88ce1e29da74a3e70f898d334ab7389cbdf484c0e83c26828c219a244278894fb34a555074204d2874d0415ad04603a688902f14b413f8332fad67a52c5106ce9431a36a5faa85afd30836f4fffd2381216844bee4d45173d9f03b92c8b0af8dc6d339faff65e765f6daca5199a65d81b5610e95a66ca116e9dd2f02c793fbc2c2d586c5cd71585218224bf32472fe7c6d1fb75b4e63bfa2666eb1076e5fea949a6f1b4579b6829dfaa3d7cd94d1b24a7c8ce33aa13c4795dbe2747993b3a39c99521d20f5476428716bed15d3001437715eb17d668a70a84aedc4f1636ecf5c9b5507ccd9ae8b9ef38d1dc8a8e296b7cc004b9bd30c44469f78b64c527d6e28e0f4c474d29906dae132348d62aba99f84fd12072f4538e51e61de3c0f48eccbe8fa982d9e7e6799c6dc1bfcb435f4d20db80655f67aa8bd3e836724f25b584cb0c4b2ad051ca0f7a656e5818e620000cb996446f4f3f90889c61ad81498d1fb8f5d036f0f8439756df2bf8a8e16a8a5a4d872a844d82051395ceafbb144e21c70af52addaa2c713d4a0b9226ce5888c562cfe9b02f7e3b50cb52381e4f39c7da471eb2a282ac0f7295ed4ac2f6b0cffabc081549bfff2d1dff5e82689c622e28e2f77cf4231b77771f7bebead3401030dce9c27343637e4618e5c76ac345499fd130a1c33fd56479912629f67662505d885750890deb134ce2b9019df786bd55edabae3341717e0114dc2421674c6ad9acef3362bafa8c7b0020a58004189e8cb49c847dad00dd9e8929475bebdf305dd80a03d85d70d9ff15b1753c8a0bbdf4b90c0d944a431afcffd02dc12cacd77f311d22a69b1bcbd39af18e5541ddbf1bff38b", + }, + outputs{ + difficulty: 199995, + parallelism: 9, + input: "030315da4aa4c0444ce45fc68781f9b75cbd726122d4c86fbf07d735c3bb559d96823059cb3b3f1b7772ede2d627dc818e8b75a5fbe155524392635592c9dd0c514bd46d4d6345defc7e", + output: "00000007000fa816e5333a50f8409b463d537bfa2f0830ee231ac292ee38007f6efcd09bf2bec8aa9cef462c91f2860b7f4a5bed5f09611527a877ea8f075e65139887b7eec8cdcc0a91f0d2b30c700838dbb55240a35d00c2d5711fc03d6c27209826fcf2235542fc4ed0c9680ee935ab827f40a1e054b5471e30f1a477d2224d3a198eda000b5ac3842645e931a24d8b60bd8a7e8fb331772aca051ac1c6750be5a3d758e8b2f18688a5d0ebacffb3aea7bb8b67da438112c0ca88d10680876d5e23d2e83998e8746d588da4cdd53bc1eca16560874efc1535f71a158c9a861460c5a70dd4df2e9c160f5b91037ca5066545d8ef23859662dd40a948c1e19e42d559c5ce2100404e8de4ecf4660cffc2fba8ffb6099f709a8dc84438e3e3b4d3204a0d4f476e6d0f8a113e7c3b464e28c8ee0e6f8a28ae225efb8c424e417640f37da45d1cccd4cb455a4d262feafa8efa472dde415915cfaeedd78b46adaebc216384639604ab053d307f64f2b07701b3fe991b3e83c0204412cef58a6d3619bf642b3b4ebbffc2e7be93654116e45dd7f1f5086a784b0b20e7e9a75b5ccc7fe7f465cb8f000af5fec1c89a47f58cad5273b19a5c252a9b2ecba4ffbb0e13ee408ef734bc1b317f832afddd53508eb0185f83a831509b13f2090c8cdae08aaaea2a66043cecef17dade59ffd1347f7a7553d4216533587313cbbf2d9cf5348b4cec86272c03410300b54da98bc383c4c09e3a85cd30e51ac0e8911a7e90dcc8288e4185b411997af49deac5816d6b7d830740cca96753fbee126639ced6853b8b0ad9bb89b4e2b1b4a8bbd83d8c36eac5030dfbf9179bf5904d9be44cd9a6a980dc791e664738ce7fdf457a298f1c81f0021e08696767674930c603ae91dc77b886b167d46a91430215f6a2d39481bdc591e9633ff97d2a3e1f8b", + }, + outputs{ + difficulty: 199996, + parallelism: 9, + input: "03107c068077a96519ceeaaf85ff66a81a2a4d2056376027d0d056695996682786fd18677f56983d214c868cd1b1a96ee89909e37f5258f7a093de2c0532d376c920e2ddd6bc9eaeee8d", + output: "00000007005bf4b19c5a000850af4b9a49790c06094f28b62d05919c2b9edbe73cc7272a27caec3a37ca6e5c454b3df67f0dd9457afdc858c0e1e416a3a05e24b2cf5fa4b0f5b6855a1eeeaa9e670170cfb0e77c3413ad297a9a4636053bcfc2f01c4cef25b93de265dcfa89624a509aa28e0ea17e720de8f0554281d4d0f8bfea1be543a0ffe746e3b3b2d08a9ada24b7a4466cea7b9a04fe7d058956eb3d9d2089bf73c1820eb3caa783b79db85f9b663c3609bb760789746f4636dc680bee36e538c5b6da93d825625847e42b0c7e0d6e62e4726cb0f0667c4fbe8395fef64de7290147aa7915376d00a7876f5fd343f43378c43a4ecfaad4e5301de670ad17a65c9cc7c10053a5285e536ba691b8b6c3a94f676240aa98faecae8bd605778c947663166d88c151b39cf26376e6e8d9a65090cea6feeaab15d60a95b995ddd90648359671207766569f84cee704bf7dc6c990934f6c37f043da9a1ee18355e63d7a42faf6f298e86b4c44c5e1817345fa1a82903c9903294c2cbfe2b7678b20decb11255b80001b9fcd6f31850c23165f958680bad11f245a8f92b7630cd67db6eb3908491368a355b76099881531ed9029419d162f6df94adb0c044385a5365c2abbef728e36302205dc152f7a7f042eee0e2888b7f376333b45fa6f8df9a2a83b2d1ce250b9bdc4c5864f90317298626071b229eb704a5267976933c2b5a606c77290123041030315da4aa4c0444ce45fc68781f9b75cbd726122d4c86fbf07d735c3bb559d96823059cb3b3f1b7772ede2d627dc818e8b75a5fbe155524392635592c9dd0c514bd46d4d6345defc7e02113c092ac7377436fee4f62f8bc7914960bfb9661055b559318a9d38b04e66c4d5d9bb1e437966369030f4e3bb9a6c4e6a77b9a3eceb24db2efe16f4b220c23cfdd604803f48da814b", + }, + outputs{ + difficulty: 199996, + parallelism: 9, + input: "0207df7628b6c526fade62e9e970dd867ee04f9c0051f8eb908e157f4c1a9f60f21d82cd1d0995fd5d01575eeee4775a6dbf50f74ff2a9254748ad3fca5728c54733748c112dab044ae3", + output: "00000006002b5546d888645337aca1b1bc1774fbd6de0c491ae18f98e5502411dc91969d397d85805e9aef9606fe2f5c6b6ae2c8c5cfbac02b713fa1e48767d2776cc1645d1a06fdc31a5941a47995681748587250c4afc5eb425cb2074df417bac3200c7a7f9fff5309093acc9cf33466c074fbbca626e34a3c5062d2e1bea022000cb7d90002941e5242b509a0fac0ff58927b44b483d856959e9bebf8fef01f83f86498877857a51d911c553137f81a8e2c9c04d7cb5042fa0441d819a893e4766bb9c19c989a26aa63edbf9d8c1363992097abcbfc8ce3276e8d51d799066565af13266b41e6b52e63ef13c7c69b4e966cdd7c26c83a366c7213ca0009fe80e27adb96b100194f06f7111df486826c9e350b0cea29ea1f11df4712db9486d7439823a53e0cbcb1349af325fb57e99f06648bee330f814b74cb024f808c3aa78d15f3bb47b08010a6c046eb733b56a9ae325922e419d3d6e1557835c84e210a035fd8a34a76f4a8b085f35167c1ddecc536d7ac8ced54eeac27219ac027748898b706d9901cfff634a7008ae2d9f75ca6c88e62505642cc6bf88fea9b013ceb2b39c3ed71df811b782b3e5e8ec90c3a03d50aa3487ae1faadc80021147777ceb6bb0abc13fe73da56bbf3f67c1b064a119ae42077b9c75a122acfe13aa0ca7f21031adeb7a7095e6046dc5a14da222296af72da90b28d9a5eff3c464d866e6c2dd7d863cb047f03107c068077a96519ceeaaf85ff66a81a2a4d2056376027d0d056695996682786fd18677f56983d214c868cd1b1a96ee89909e37f5258f7a093de2c0532d376c920e2ddd6bc9eaeee8d030cef6cf003a346b6d6b602855d9479572977ac9d6d88127fd30759aacb5aa4bb1e2f3fec1413c50b5db836682c75077d35c8ee7d0d89ffd2863f65bd4e38994c7438a6bb5166a27835", + }, + outputs{ + difficulty: 199996, + parallelism: 9, + input: "030a263504187eef37d44bd4e60ade1f997b55333be5440dabf587e9c44af6be4b07ddb66910225f98697eefc5f8f70ef875cc3d816e410c9da539b2ce422c67c2d97fb0cc8e78a5a842", + output: "00000003002497ee6925a82feb9d081c2852e518703a7049aef52d63107d2e8faeed0b691e749176eb67ffb7ac8a9350bdecacda657f15574df91d16af7ff8091f420c63c34e22a37766961b84519a0935889918efbf5ee5d809d8748d6e25537b34c5af074585a6966e9272fce642cd414bc90a41e03ab5f77ffaf92776e9551ebd5e67beffde41af6ad720845f2773ac5b2f06931c2c5ded1c021bcd56e4f20956f775f7435e6a1ca68e9a936cb9d2b20604a60c1ed1a1a7c65814d2e12e503ed5dfe877b615c8044620cfa730bf280ac284fdd13a7d6e8ffdeaebdfbd4c718c3e469ec5d4b4a39c9ef75a6383f7a6571892723a109c93321ba973315c52aa92c90fc92579001affc84ea811ce46e4cb927237f95591c5c99d78a02044dab2ccb1ead43eb8ad56139ad524ec05279169e6abcd0fc65f347dd3b582a7c9f07078ae5b36e7a429819912980647a8b8998e0ddb7b4de39006ec1470ada11bd9d8f222dfdb5fcf0b56b59c61e90e523836c24653c95ea0a4c063216b098404d33da619cdd699b2b600174c40819ba9759c2f75b87dc41489ef0fc2d03d0c4d5f121384503807108ce54cad57e66b77373d197aa0b448cbe753ac3793f525d579c50025cccff984b867ab52a954071dc9673795d25f1df02fca94f12f7447152f1e608e6572bb3ed00e099b649146b943252383d84edd41c912dec89d9e694a78b969382a446557877d0207df7628b6c526fade62e9e970dd867ee04f9c0051f8eb908e157f4c1a9f60f21d82cd1d0995fd5d01575eeee4775a6dbf50f74ff2a9254748ad3fca5728c54733748c112dab044ae30300bd23d012dd909126ce2b8aa326e0dc2878ed0070a8b0ce52f19823e1e524bfdf5a2f17089fbdfe31f6c7efd847dbbc010a0d344b9b9e29cc1453cd0b27d62dbd2ae14907c20d7f53", + }, + outputs{ + difficulty: 199996, + parallelism: 9, + input: "030cdb533b2a273470a0d6e523bd593fa436379253383643e25edaeb3f246509bc04de1bc605e4ae1d24bb2b563d3df9538503e4f523a0025a9b98f978f28542be275cfbc68e3dd2c11c", + output: "000000050033223274f728319b62551ffacffb98929174fe45d706a807f6b9d24d0aa5058f70ec1120220f44f5db7a28f19ea79bf04228e5b7d4b3657eb5e1e9d9eff5db46d4a93b3f15974733d80ed7c448866778417930cad80866e11a1b93dd2a19e36f50594eee5c9cf22beacff8ac4cf2d2af3cac8b9e64ef707a8eecc60b0b27a50effd30fc94e28cc973383827b49602c4e0e945182d5262eb7a72865e476903851bffb14a282215e908fd7e5e6442fd1eedf9c67e55cc69646ca5822996dbbd79274191872476ecd184f53b4931a2607198f749e122f53391e234a8d6e06aa6383e17ba6bbb148a08349486cbbc0b52d5b7bde91a1f6b90064aec0cda75281bfcc0900334a1f7529f5f425aefedfee42de34abb518c8f4f2352b01d0f817a88edcfc5528a49ce267d0650798bd5ac1008616e530d945fdc6537bfe790ba808dcb446a889e6d52673f3a0267e59f129d058530a90ea0c42c8707bf534c0688c2df597be668b985fe2b865ecf6e344184c709731defa097f30c53f378bb99af8f3ee04faffdac3aed27b86503817765ee28d05e4d0bc70df027beb644e4a98af7d431c47ed21a54a6763cf23ad0ec199ad8f36d3a54793006bb7e1db4acca0d229aec27fb7c95ad7096309b1364029703e4b17ab74ad325f9ab643ba78e745f7955615c61d2d2440617f6c254dd1164d50864ae435206025c348446256bf1959b139b09be7030a263504187eef37d44bd4e60ade1f997b55333be5440dabf587e9c44af6be4b07ddb66910225f98697eefc5f8f70ef875cc3d816e410c9da539b2ce422c67c2d97fb0cc8e78a5a8420308bab2657c9562aa861a7266d89ecffaa875d16557115797ffda69175673a256626fe20995f4575b328ac2580194d6327c1fa6467abfba97959bcd2e3675715d925f7bfa5e895dc093", + }, + outputs{ + difficulty: 199997, + parallelism: 9, + input: "0302dce6047bd6ef1489f053ef3a3382b29d977cca63d11bd651828d21a3d2dc11b8f861b8555b5df9214dd32c6ca6062775043812a534d1a4ef6fa524747afbc6ce369859b76068bf2d", + output: "000000000018eb563cc2f7b96afb90243bda952a783c1c8886335220de9cc36121ffef5e79f2970e1a1dc5363d90de0b956134c0a9f19524f69b9fa00d1a7345a9523a0df07c4b67e6fa6dbf3a24c27550337a68e957b930074c7d4d6364fe9d245e853272593370d6edbeb68b54902a61ccbf245c70784bdf548bb48e6f939786725383d20006ecb0dcb7d3cf5474d7bd56a0f7c50e312ee4ab5b744a3b88e7929a6b6df62e17be656e4d3cc48b49cda862a54deb49fea254807d011ff7e5f7e3dc358c17dfd3c04e8e46857f2d632646ccdce1be28680049f07d3501703d29837e587111d03d305eb867d04724b84ea7321502c7b49c27b537700676dbec2bb9994ffecbb500043d4c16235bf2981593d61ea8e7c8d6b80761146851111207a0806e0f88c83cc4e89a96aed6b88fa1ba4cf843d2f0f2fe0d31525716a5c3a87a889cd6a92daf5b53f7e5c40834077b6e18d32b04408331c2935751ca2591dd1dbaf766c84c3ae37bac06612d00222821414d8c69898580db082fcce5cbc37fe7956d0e8aa6690002e8dbda4caaca14f726b4174a68e63d6a401386401049e60a68d88bb998fe05d493f0197bbb006ad81355c5ea6a141aeca06850cb7a859179c7d5f83c0c7d057136865181a9c0f00c4132168668af3fac3ab2ed6bfdb99bb0ee60b3eacf9093ee3a40cc1d487c40a08d26f64c8edbb5d6239f795a4bea7a6262415790bc39a3030cdb533b2a273470a0d6e523bd593fa436379253383643e25edaeb3f246509bc04de1bc605e4ae1d24bb2b563d3df9538503e4f523a0025a9b98f978f28542be275cfbc68e3dd2c11c02030fb1d3b3d186038043e1e235451c9c1952355ae246126d435a107cc148577076b93039612157e506ca7d88c9727a1b53026b0f362c99c0f47b67cd40b2cffdbc364c8bf683340e02", + }, + outputs{ + difficulty: 199997, + parallelism: 9, + input: "0208b7df2a2214415b9a60d2c526556ccbead4297f29a1c02a7490fc53c1e04f60fb5a1f2ad31f45d9bfd025b93b501147dd048afc436982abb4311afd48f74e9a50f9771d523ac77f42", + output: "000000070049b1ca38d1e705e74c427fee6c963fb7d503c16adb25b003a85dc9b3d21c805dbc41fa7ae4a76315798c69c2a031cd24495e354695f8b25524889d57c59db6a2080f5abf962956cc27ff077adbbb9051f0292d9f6de5eb0f16630b9f86eee00c381bf9db16801672115c09745c3c1e9a286b4d7a917e5dd7038327f8930c6a0a0010fcdd9bc511db1bad75d1a3079b6556aeb0539c608da64a8419a9d8aad8dc7d95619949168fef509fb7194ef3cb75bf78d54f9f367943a939e63c50028609135b7b12f4f901b0e1f16f551a41a7b413e0b62d707b1e1ddea478c257bc5fe4c1cfe93c13588ae1d4800d7667660a244ccd641ec6f4ec98e7df79811c1695bf1700070c731d4d8d22832d6b06b3a4b1671098d45a0e135f6452e2271b18b36c4f4f3308895b0da6181153c64799f47330630cbde1b04fccdea211725b0ec5779d6810c0a9b36fac3eb6b4efbb04335bb8f3fc56923e6161d1b10b0c8d884e9c1e6673b06527be595c2f673c4623f694e7d5dd24821f6c86f2805c528860d4457434fffe62ac30201cdfad1c952a508d329ee951f777b1ce7c82c909a2eb96989b502474764c8f9397ea23dbfbc2ac58a4a9e0481905b1f434a1cd45f77fd62a24fdb8a025fd8a4269aac95d9795e6a84a5d84419191ef165315e37f4d64164d7f9c9461ae4a13d9c05618458fa24c97735dbf61aaac951fd4624959d930ee4248ab930302dce6047bd6ef1489f053ef3a3382b29d977cca63d11bd651828d21a3d2dc11b8f861b8555b5df9214dd32c6ca6062775043812a534d1a4ef6fa524747afbc6ce369859b76068bf2d0303330b216c27fd2baf6dc229bccf77459d90b341306c3756050bb9de38d3d7c17b231d3732cdbd6e1c688fb1806446e3a31546e07e02c738dfcd303d04935c0619c46161d3f34a304f", + }, + outputs{ + difficulty: 199997, + parallelism: 9, + input: "0209d8668b2dc552b92b15f8631e5a03fb5643b978d389f02cf0549352b576af287600988a4ab922c62d1708a13f3e6f368165a92217cdbf0b6886e8b1e9cd9e32b3fefbee27b3972f9a", + output: "00000002000cccae2c789fc30debfc119d41cbd8169ca346aa9892d916706596ca2a6816162b51006047211fb7329105f7b614fe1b6f8cdadf7816db959f6a8905c2609dbca11614a4754876b481f0fc9d2accbcb76c8b7e61d1ef3ff531571f824f7a8008a82b72c71967e94d77ea0c32a6f6fc98681be72d70cd1cfd210ecde4fdeaa9f5000b90aebee045d65026d4eca1ce6698b8f7ff4a5d51b8677e905ac424780aa68a50d4ec8d03e0c189c60960699d98934e503185afbf2199490a4d75184603c125b24b18006f47d3be99d9bd46c194da90b0337a89c6cf7f36f71dc66bfc9bf84f64ba27e66d2b2b98fc05c9d8f4574851c27c7d97bd1d61c5403376134e7b8555000a890fb75c3d10269d770abbfa7903078c24ef7a846ecf2cdb6e37717c9eced87bf052fda415f361b9772358ade2fc652847356a88d4b1cbe43404d620cd5fcca818cc0d89aa550956265f2f525a5288ee162310ddea056a4e6989f89e7c8f8d82249702f4f70cb71160c59a2e1dbb71e5d201ebde6c1177a2448951bde396e2fffb95d5c7b3ae237ec7ac9609fff8191f704bada2fad97b6a530c18300c63cb8f7339b71b2c2cf1a87c0303be88781fffc587cf5b5abb635667aee4bbd63d26d6a71a6268e53cbbc8b0594e2adb758b48d92c2cb505e210119db3782618562459f58edbc9f4c1254921c3cbd71a9c55ae80b6df624bd0d74fafc7f19f5cdfceb50208b7df2a2214415b9a60d2c526556ccbead4297f29a1c02a7490fc53c1e04f60fb5a1f2ad31f45d9bfd025b93b501147dd048afc436982abb4311afd48f74e9a50f9771d523ac77f42030b89705907bba5fdf8199d2253a91106349f617b83cd7cc58f64c9b16b4f4a38356413d929cd076f0274dffdabf75a6fc910c84dc69531b341b073dc6cc12d287a60d3694f359e5568", + }, + outputs{ + difficulty: 199997, + parallelism: 9, + input: "0209754ce0f091bd3a2aab3c0e570d75cb1bc9b0f12f97408c02ce6cb7f3be806a49097a6004379dabb20c3d669c14ca132fa1d33eabc04d51a0aec8bb14a36ad611cc8f468ee1ceacb9", + output: "00000006002faaee4d6b4bb3a147545b05798e9a4ccade94db472ba5eb75409c5f260892ce93fe143fefae0cefbc1ce3e997956ce53699d89274585ad2c48f277ed42141bc0239a210bec7784c79abc0461e2b4482c2d464b194c66e4b64e5dd2eb31ea6daf0514b3340875dc0fd82d2544d355cb8161e72a191b4ccd7fe7ec7ec12accda8001d940491947fecaf023fd2692567c674b16283c47ed48c6a14d8f5c4394ce0e0fbf58d84bfd178ea658bbdda27a15536bf8a66687dd788d392c7274f140b42da24d60c89bcdf3c52f47f5ff93382407074d2b8c59d9c6478c5021a36d79f118e4343a0897d9fa78c4bc04338ef4a5afe63ad71634e4582092e696828e121dc23004c30bb4f69310173f3255ee5156616dd3996c810b92c93c234c010446aa2719850d237a559aeba5d67629c862e5d349e468cca9939b8a58a3f76089b048933ba88a407f236e8def855aed61d903dd9afbd5b62307ca8e76a68d5cb56867a63be44dee99ee7d5e81ef8b7cb71f2731758878c134d05cab36a688dec1d26ce16bdffeeafb5b9b47eb8277a4516a020c5ac5258ddc650ef1c1dd6c0773f88c6a677a41c6b06be4b882346dbca8b40f06b7a1c83fcfc0319740c73f8fc6a3096e17cf50fa4f0241a02512be9b031a1e938593a7313fa1c67526183efbc35582d23fa3d7f45c8b1eb0be9c25194f96ef313e6c40b7af5a600adb4bea52b073ddecc00970209d8668b2dc552b92b15f8631e5a03fb5643b978d389f02cf0549352b576af287600988a4ab922c62d1708a13f3e6f368165a92217cdbf0b6886e8b1e9cd9e32b3fefbee27b3972f9a02126cacb63b4416d0b7e915514be51ab5fa1ce52d5848dd4bab86494e792eab356479d4ebbfd388d3fc91f877576a69b9fd77360e76dc308f20bf555da3f397c2e224aeb90ce218b3bd", + }, + outputs{ + difficulty: 199998, + parallelism: 9, + input: "03108ce0880a08e4829c4f22b08cbb83c3a2c2ebf96b17a73e63eca0393ca2154deef8593ed7526dc081b5b8c2908bcdf77c90b763024202e867ef5b9cdba424b553c480283f37883169", + output: "000000020012f9522a0ddeb26e8b79634ce3a8a6f12cb232ac4ca4b99ab32197d7b45e345df65ee943b4df83bd0410c4f6b09438ed1fb079c72160dfdd2a81370ca5dba99024289f7ccdbf9829059d65c4a0f4c7bdf471532dc800efb3a3b78418b4114a443572d4fea3ded3cff123f52771479c61077b2ff3bbde03646736d537cfa56357ffed67af72a7fa6265a01ffed9056abbb6ae0e007177f95e9b03fc96f4cc620af8d39a57b34eb4b31d416cd54607bc040d553f696115ce91553cafd12b27032eac98350c72f2e9b7ae7507fed092d0db140f42174595bd7f1e816fcb0be0d4e3f009b582c05e0f18ac1f38d1096f256570e1236a8ee0240ec25fa045a6ccc5efa1006c1ccbc5945a6f7df65a59d29603681a3197624e32e569d01440273353b98e767efa8d67a25cd0e8922687d239fd27cf10fd19093720929c27a6540dfcdfc06874e68d6ce93aa2be913007fc7e106951053c062c43c1c8fd565aaa8a7e9ce37c0271e1ae27ebdeed072e752d093ddc87c38e5d5c7787fd70dfacac0af6fbaed00056487ba93b530abac3afc541e8a08e4776ffa76da55a04c909a40288c4b6ade07bfa5cc0e1162d5e3918289d0cb4312c1c6c86e16f07fb3d628a679d4f8fe448192fa0e7840e615c8206f67bf6a455824068cd386ba66f0db36c97515ef01996bea1f68beb2d52976820b5065b56fe852191758bfc1947af4d6ea1ee5de9c38d0209754ce0f091bd3a2aab3c0e570d75cb1bc9b0f12f97408c02ce6cb7f3be806a49097a6004379dabb20c3d669c14ca132fa1d33eabc04d51a0aec8bb14a36ad611cc8f468ee1ceacb902031644b62ff748cccda708a3aceb0d6fa3f130f88c50ee908e743701d5afe5a80a41e5ccf2a955bff226928e874d9369c40cc05e53c9f695b6d017db080208a9f789e6553dd5d82771", + }, + outputs{ + difficulty: 199998, + parallelism: 9, + input: "0301e5982538525094f79e237ba1de225644f29f145d10e4a51b000e43c2cca99980ab79e269d2f29035aff89f080f452d070b53576e7d9ecda4bd33205b60ea128c533d9f74f780c008", + output: "00000003006f376d5f1ba9e3ca5dbc96df77818fd63a1dac68c20418f208655c99ec96738697293b8b5bee2f833097f34cddaa1844aed4f42e980ddb4098b08068bc5e1a4e921ba7e14a441b6db302847ea3d05fe4c1b31b7ea70e3ba3f945384d668e00b5f496d1e1e20efd01da2c2676f8d69da5eb036e01f60d095d3769556ed44424380062090586404de3fea0988382c3ba11a83b8cd8f2a8d72c2461d6eec2befba7466de31d2be68a5cc68f3404c3abf0fa1c0af4ecfcfbeb8e49356e2f07a7d579b47748c0639a26d0cbc847c4549cafae555ccdca47cfb50875012cfea734bf365d4705ddfd8fc6c8a0a63b481c48d58e6f96320f46da3ec10b39caf4602e8d4db50062aef40b92c9d03bf4835d1898608f8834629f1903ed4e9647f8b63879257ed18072ea39f2166b024ef8209b191b88fc0f9c6b77a919b61a0ec38f23541f92c431a1ff207f260148b17dafe4090a69a7fdd8e9bf234b3a7a68e50809ce654647cbc6643dd8aa58e597bef0903318dd730b9c962b9ab94d1ee3138b70e5177b7cffcd2135102f201c64371eed7553473d26238ad98abeecb9b5165a38a16e694c4ef45a10946f1e983b7a8589e876c1a3e5aca55774171a7c4c3e7c1d914f629a7399beb88395a528d5cf05a558b238aeeccdc8924dfa8838f8ef1878e3354d7c8697fd3137f4358cf47ab8f9da37defc8009550802f767edf38e4819eaad4f7b5303108ce0880a08e4829c4f22b08cbb83c3a2c2ebf96b17a73e63eca0393ca2154deef8593ed7526dc081b5b8c2908bcdf77c90b763024202e867ef5b9cdba424b553c480283f378831690209e1b71f0d383fd06c421c2fffc6e69292ecea8788971c46cbb1db69519bfc8291771590c1fba04d7be5e214a5feb37d4efaff175b571947514e1e082d1fa2e8bf367fc04474d977ae", + }, + outputs{ + difficulty: 199998, + parallelism: 9, + input: "0210ccfa95f48725f71473c9528e74565bac8ba52c85e4bc3ebd456b767830d011d78cec65222beade1669bebc60fc8f987d7c64aa3fababffb24ec2c498817848a13a86bedebdf02245", + output: "000000050054cc0dde2a3e533c6b61876c4dfa48fff4a4100440bb3161ef670178bc9e9ac117ebd9ec35eb4101e0456c005904a73490a94a1af8e54e7175a0914b15e73b00bc1e3cdee773ce72e4015b463f5433c7300e638f03fa86eae02cf43ecf71ab352a7852a71f4a79b383715c69d70c6074d675ec2a85b9493ba63ab871dc12fdf20020954a5895de97a2fe4cf1b412a133621ab9240810e272deec92daa8186723bcc3714f2402af67ba733656ed8ce7473831bc0f617aa93da4f1f87b0156552db8fc19a1dc44662cf51752ab0ffb6b8081ab15cb2a1e045edcabae1e7bdaebe92ee6f628109a577300f45bc69c67e4ee57a7e2c596e850e63bb54fa67d5d6a29510006ef65b070d0e1da5a23eb9084077a31148885ba2db562c5900227bcec139288b4690cb5938d3b06227d8d70194ee61bd136f8ef6c70c13378fd2987c4a10e97a915230686ac06c162c0b8d2f4946512b923e9b1b312d6501e288bd91b1cd250bdcb1966b751ba03042a29e9b9f219eeecf45e61ffe9e7d3911f1a68f4072706fff955f5e567dc0227fb4980f40202f178109da3d68831598e3e7f3be0dafc9ce6074021cac88604a7122f2b01cf99134569b654d09b2cf07aa0d0799c70ca4bb31bc3ecc91787d37b83b8957eab8695dc617d300fde85eefdcca248e6a571570d7dfa7f957c4a5449e101f20aa0530b61f7b5f30de82808ad34f254e0b8e4ac7b0301e5982538525094f79e237ba1de225644f29f145d10e4a51b000e43c2cca99980ab79e269d2f29035aff89f080f452d070b53576e7d9ecda4bd33205b60ea128c533d9f74f780c008020651a32bd493758a99cf34eb197df22d3c6efcc39e3d1e2906888a465088bbbf24a8d87622ad490c135799c42e9e8b4a89a660c5c29ee14791d02dd75efbaacdb8d74b1ed1471e867c", + }, + outputs{ + difficulty: 199998, + parallelism: 9, + input: "020ad6e7d5d48888e7cd5ae0aa06d486ca8a577d03d78ec37ecaa1ec5454ba124c32d1b228518af0f62347c6b0bd4e2efc361d57e31a8496684d83c5e0f7d32af3046548d6f388c394ea", + output: "0000000600623d19f31c55d72829f4161a254528df823bf62086af81139c35fa470423ae311f35a16071ea14a1eecebf94fb8d8a54bfeabbe7806eebadd66cb9a196c4f5f83d0bc6914892db0f00629aea4ad43ea5246d9ad7272ad1135ddf4bca5c65ebdcabe948b93477817d1200d5eea9a6bfc450245c2591b2ab9f8bb611db734de8f3005d914a3efde8cbcb5187f3bd91b41e0c1fde9063b8cec52163c47d2421922d837058ee3ca5af95262d483acc7cec4568e36a40cb6db9393b99f3672af10ac0a82d19f2a9e66b296f3800900bda3dd3a1d6ed4ba4514177d2bc9fe2ef7e38c1e767e09640a669d39acd2791b7ddd289f8415d4af92c0981674771560ab8fd500100592e6a748ca27d1f43d198aa40a5720bf2642fa525cb9f5a38e5d27662ea3b114cc1a5b9fb717d89ba7a2dd48ee8ee65e615bb8a01c66b518f3733e2f0575b4d81ac1995de4ab844372d5455e3fec224c5858cc6d6043999f0f8e252ed3235a48eaad4a0f9f5a2ac7463ab4a83135d39df3b7023886d9b011904ffaa8495ccc2000d49b95b66a98249e4ab4638299f4da4eb6c9063eae434a80c4c85ccdf28247f6b030a9fee36773ad075dca8816e8a11178fc3dbb64cd4028a5c8e63166d7c8279ba2d0fa4280921b692a10366898f44e17ff989612b244000915376ee9dd3739fea0552b732cb7c90d4a999740eef4d7b0149805e0ed16a6736de090c97afc10210ccfa95f48725f71473c9528e74565bac8ba52c85e4bc3ebd456b767830d011d78cec65222beade1669bebc60fc8f987d7c64aa3fababffb24ec2c498817848a13a86bedebdf022450209e086ddf9a017c0e762e7064bd7e1de6a08f5983c2d874ece74c750efacae376e6808610ba2b5b4abe76896443fb881ea27c45ee7b1bfae837d58fa72191666cde31290f481ec37aa", + }, + outputs{ + difficulty: 199999, + parallelism: 9, + input: "020c3fb205ce2e972732a32e85184463bf57856cd38432381c008aca6a32fb01785ebbef306c748d6ff6e5a88b0635c274f24c1b8d5b250a8f7e24a4df849e7551bd1f9a6bec5b98a9af", + output: "000000070036c5b41271c3a360e9851ce63e794c0b56e0c0c27661dadaabc1df1986ecbec87daf83b8cf73b8eb374ebec60606bacfd2bc4e641ea17663c416905720fba40500468dcc9e0c19491590c71ee3777ac9d41882b278aa340b6c19c8066c8c9b1b6a9bcbb882b17795a6c4c271d5f7c247712e7ddf92d4195069f0c18a98ea72f7ffdb4db8213ce7e316396c61d9744c0811b6d1c8473f7f36f9012834575caa0875b4c04b28e78330ef884933b858669590fe312f461cfc89e633b36f4ce99db5f6f0cb51de374b51b81f7f9af198c822d77041721352b3bfc6133d62265457274b2200d212f4dbed480a024a9e5c442779491996967d79117b59ca62a3c523384d0046e24b99dbe8d6dce50f42590cf98ffadd8f8d96d7ab5ce2aee875fecd3d99e3de6a8f3dde3724ca083d63839766ee1ea1a48148a8d47de85b158a55d204b4df59c3e4f28bb1288a32946f3b5447c6040199d2f5d2101c44cf93ddecc9fca893166e4dae59b468323f214bc762c260df38f8e9f3f36acec212e6ca364a31391effc64caf6016f49a1eaa58652ebd135c5883bf7a02843386f10fb229492794720e7f2cf839efaa275a9e36d6e2c19e35e881cd2960ff513ebcc6527695ff5bec8515b91b1c0008c8f2e31b69f05de5804b8149d11655f76a3558e5a75bf034891a8f1710e2641714043771942243b7759effd6093075bac85a1aa82cbd08c11b63020ad6e7d5d48888e7cd5ae0aa06d486ca8a577d03d78ec37ecaa1ec5454ba124c32d1b228518af0f62347c6b0bd4e2efc361d57e31a8496684d83c5e0f7d32af3046548d6f388c394ea03076e7869ff2cf25f23389b17dbc24d82f706db9bfb103e4c66c2bd3430dc3bd552c5deac0e50243f3e11c55d9531a16806483e5bece5dbef5ba47585e986c1b8af7d328c5ac499df28", + }, + outputs{ + difficulty: 199999, + parallelism: 9, + input: "03007f7390c7a7fd1812e7109e50d0598d7a12a8ed1a3364e937ebafde3011c2d5cc83e2ee9d46cf04c216ca3271a15a5ff11a023276931e14bf72d776730905dc5dc756a2ce2c78d83d", + output: "00000007002ebb7b3a574cfbe7ca7d0980d651e080e942f2b32d377698d6570348a3edb0411b8155d9e7566cd33c2749b4e5ebdad6efb26352a7717d3deda63f97ddba2381a89a5066069da540f2cc5f642311faaf145244ad8b5c6285e7640037b8038970cdc468068d8da14e29e941aa9099dbd7297efd972be7965eb0dcaa1f3eeccfc6ffe0d706c31e688397931d0518dcd673366c54abca430272b3d51012fe6fa94fb89307543fb1f89b6ce41f26d53d300eb09b92ebd9d772cf560f722379bbec5b8b80d59862b87a952bea662ef7d01fa7edee7e678e8543d676e1a54e47a6bc6fc4f7dd8e1589efefdf56f87e718f7853250f06cc546913c2e2d9b6688e750a4d55000117629571951173e8f9a22f450a7f2430e4aa66c67e1c103bdfdcbcc37fed3e10c3b485c9467e7b40c1d2538f247eede7fd5a86a1bb70acded7cb3185e06c97747d2b5cb9805520b38569f32eaac8590a1f21c8d1c2367517ae1d44f3b8f7271cd62b107a461dc5bc8146001503854a620d7099591898d27b04ede38eb94a6effffb7f73ceb535c57934beefc62361a924924a7aad172b44ae8dc4e04d1f3ba8fa1bc3b05b71a58ef640bb53650d527e0be54bcfe59ac0ae6109663ead2bdcc779cb26f36668c2df4c16c7475621fdf6b8e9945b8820e9a2886305235e94d2b30fef8588ad6e33402e08ca84a75bcc950bc89d75b1a76ebf7d1bba08e84b3c495020c3fb205ce2e972732a32e85184463bf57856cd38432381c008aca6a32fb01785ebbef306c748d6ff6e5a88b0635c274f24c1b8d5b250a8f7e24a4df849e7551bd1f9a6bec5b98a9af0203dda1fe12234be05cd3593998afd01065cfd5fba0bd50ede15c352675d946043c9f4e55f58677dd06a86af924767195c94c8341fbf50e007efb3b338a1602bb7716cc4b4ce56174f4", + }, + outputs{ + difficulty: 199999, + parallelism: 9, + input: "030f06cb11f299fb3f391feb3f7109f8cc7710df9c90d2d3f33e42715a672928ab85c67b56d60017dfd74c8ac23bdfc4146ea80b831ef94ac66fe4a9fecb29bcec236df1f2f6a08ef404", + output: "0000000300108232036aeb1c3473a1127596b2b8aca995d43d3f44b2745c30c5f4cf90e94cc0a6540a710e3d8e778ddbf75791b3ec218c4d3cd83ecaabc047699b59598dd7db48ce9d61a37005cc28c91c2c9c168bfd7d4e4a1e391e654644576f9f172e4c0836352ac3606725df8134779a8f574a67d55b0d9ac7e16cdbbd4a4af89755b6fff3430c2d13849a13f423a5d02332dc17c3f19f8eb5ce5a6e00617ab2700b73ff1338ed576c7e27ebadd32e96c7ed81b3f79142bef21c347154a0fefde5c45c3a13254a50d0f822d89f726b52a830db2d6337009ae42b965e04c828bab2be0b45cf4976a6cbb8533e4dc3006a8bfa09e50dc1f1b538c01d5216ccbb1e7b064c2b0017f789f09500ff3cb38452077f0d8bd96c90cd5b6787baa58fc5cee1752d9e2b7ae70f203da2ade7dc329d3ea3bfcb1f7348b7450d6b055c117fa71da7a3bdac91fb0364e0576d988f23b9e358b6831c29abe511adee27d890ce2170cd98ea425efd83debbc09d9c50dcb86f70e562ab319648aace92a34e445b01960acf006b00169d19aa98999f94553522c5ee7945041ae519b40640f6293fdb6444024fbb7e85f4eb96caddf40a2814a3678eca01c9c6601ce433258ac6d02f59cbdda1d2f90d295f594a897736eddb279e487d24998b2c112a4dbcdea0a47be80af9c2e6194f9d5e88ace75cdc8945997cdae4d572e6cc2d1397e645013c9f50b07a80d13103007f7390c7a7fd1812e7109e50d0598d7a12a8ed1a3364e937ebafde3011c2d5cc83e2ee9d46cf04c216ca3271a15a5ff11a023276931e14bf72d776730905dc5dc756a2ce2c78d83d02049646ebfcf2a25a94b1dd905e0cddf2357700e96eb3d97d81a4763bcb3cbbdcf5a489cbd7f1709565e04a95fd6bf845421852d52fa138a0f3e076ad0298b8a35abd2bdc81275d0baa", + }, + outputs{ + difficulty: 199999, + parallelism: 9, + input: "030ec329bec327756dae350871d7003d74cbe593f5cf842e845bbf96a5c059d36746778f7a717d34b2ee5504331bcdde4689899ce4c7654e2ba57be3babc303a4bdaf8021e2d73df6c1c", + output: "000000020031695e88df108a6622b7159abd4cac3f531749228b5dffa945cce0c889d7159993176f0489c69639073b08f7acdc776df8f49799a1647f94d835c6222a02b17bae86e889ff7403150a543752208e33bcd7fdbb91ce2219c941e7e4a57ac50ce4d2e3086fffbfcdf4a805f125fb241ed020d06600412a2f8151c64adc19da2cc4002fc7cfd1a23c5ae1d5ff5d51181cb7d141baf4ebe549339e1ee3582a21f43eda8585ecfeace3e96b13906ba49e21f13abc71545f911f2f53b4a332b09e5eaa3c713c3ecabb33d6d4f632707903a94f4a69132e119510f0b538de816a60cf712ed4a33c92b4cc3ffad2297c6fc5aaada5dc8bd5ba2befe82a925fc58ca75e2bdf0022fa33cd5e33f286e34382a3498f18c491aa9dd84c7a29a096afeee705c44ba7c0465cf4d0a8416c7cdd15406272883615aa5f17eef10e09dd47848180530c1d6402ef596067c54a1b40b3b67d1c8ba4201d9e9718bc9e8cbab4fee15a16c255402cb494b0403bc80b73cdee874dc368c32ce3a6a154926f64032c0221f6bab6ffe8e54d9b46136d45530a829913a9f869fabc7311d31d0502b9ec87a481dae9ff8f6a19b243cba5d43a9bb7b2dec65d38f7381cda8a6bf586bd9d61eb0c56d2b7fd768380dc91123e8409217ee467c465467dcaa6016b6653cf34e043584b1383c51771cbc03f1935913434b0616e9f67f729fd99b9fe893d60b64a26d6e4cd6d030f06cb11f299fb3f391feb3f7109f8cc7710df9c90d2d3f33e42715a672928ab85c67b56d60017dfd74c8ac23bdfc4146ea80b831ef94ac66fe4a9fecb29bcec236df1f2f6a08ef4040306606d8d231322923764e33cfd1e7599d8d33a7269bd1392e056beae8f366df37b2437b109318bb59a50be45a7944750bcab82b5ae76816aa3a71a5f87c42b51f2bdee5a1c1c2c3b94", + }, + outputs{ + difficulty: 200000, + parallelism: 9, + input: "0302c561752737c6c397b8250644c2ac7bde84daf44901ce7183b4b947b8e9741cb0ab9d75ea45effa5916b9be5127c149d3cde31428ad90528b6341d071e442c9585ea4dfc987a6dc40", + output: "00000006004c4af754d80526e0e1ebfa98271030d656a3bb1e84951774e55247779470b36b1b64dde70a86a8a7d638b6f038201c540895824010302bc48ea6f2f066429b951339ea872ec9928763006a7712a21d5ca94b21dea5f587d1d9fb202ddf8f41ef4b54bb7ea3305a7bf8dfce1fc8644da522973641d50df52d76072e0b73f42101001e0d4c4ca3f345a9050e97ce844c9c83f7e9f6c10d10a03d6265e2565d8e7b6a47cd288dcb19ce172372d029f174f81eff36d5cab41a23c686980233bcc5557af222b5a84cc1e8c81f0eb90a38b8f44de8cb4d85684d839427ec1bd3b51fbe16dea170e0084e9106e540b817a10f5fba8fdf42ff3707f542e6649ffde6021b6b001d1adeca15392a5710fda068adaf38819697d2ffc555a000915b13505a85f1282c2a5afb5e4aeb1ba9bac31aec4c8f592ee174378a8c2ada4dca8599f06db798d1a9ff1caae8d99ddb507d71d07709d34a2244a49bade361d402fe63d7ced10bed1c72760b6aa7857c9203c413874766b42dd9319d8db0e7f8d02f6165de010e0016410f28275a965ac3913efe9af8a5887a967ee48704c3c21d1d9acf2dfb13525039572486bfe16ec095b581e0bdfe5b2c6fe39c5e8bd6e92d01ffc8cda8ae5a03b431bca81fe603711b56159a8b547b8fdd3ee94f7c586bf61094ab135c735d3954ca139808dda8b0776e0b8868470528fef0b611797b55c5f4dab6b8535e5f030ec329bec327756dae350871d7003d74cbe593f5cf842e845bbf96a5c059d36746778f7a717d34b2ee5504331bcdde4689899ce4c7654e2ba57be3babc303a4bdaf8021e2d73df6c1c0203f4dab27e20ea2ccb4b015153d7e4e421ea074692de65099c508de4f5f56f5ecd963c92f8242416adbe5b6babf45998803004284a96819bc8e2e3b88f5cf004a49535613d19e386d9", + }, + outputs{ + difficulty: 200000, + parallelism: 9, + input: "020544baa32d229284890a78cbb986e66cf9b7b2900f6b32c6a38fcef54022fbd085e25cc17e4abbc733389469909a9c0792f65c32606f79cac8c539dc53bb90f221a2fba9b01684a59a", + output: "00000008002e5538c6cd8ab5e607aba2aae7af7be072338485b1c5d67e3be42b2cba2bc2dbb7bfcdf9ae93c02858c562af6ed504448e0097b3bac756aca971627b84fcc8cb32cc388f071d4ad1bac03dcdaf15df2337e448b72196592b5a296f0cc39a3c7d6faccfe8b3fa526484f688939de7215e655b24d19bbe11284270e24e9e8a5a6a00077d204a6666d4b7aaf0cd3d39c20e57a1163fedae3e9af2d8de7a6325d3ba4be9299dfb69f1238c7879e797ec1294aacb09e59b6a261b414a920dd6f5ef966417b864c9b76b9384813d8cd74fd4f971248d8e6ceb56f3f6c5a0053b0fc71e0797ea1d28ed848095367d859e860d578a15f31fc21ad54df67bbf4afa18faa85f002f23f870751ffeb631a264297e588ae83a186445994ac722caa5aff59db6cefc59e18e85027af0cc5a6d07d7eece550fc48f702036303b1457fd110bc6b672d80d758a41ede491f6843525e38adc3783c51e8fc404fb5b7da1e50d2f81b73c98f69d95036f6abb961e312163c37e25c528bf2fdf14dcaf39b81fc280c673037f001f733d470ee7c92858c858e149bfae46121040eed862ed9443d674950cb0068b0bcdebdb4b43aeb4393c29cf351ce7353306d040cf34f284b15f2c033591e74e71b18b405a04764154ad7c847bc382757addcfe788a8384a5ee78aa08af8948944cb0b995e34847040ab4141b1649fd87363e9151edd48a051d7f2c69a7948630302c561752737c6c397b8250644c2ac7bde84daf44901ce7183b4b947b8e9741cb0ab9d75ea45effa5916b9be5127c149d3cde31428ad90528b6341d071e442c9585ea4dfc987a6dc40020db3cbaeb32effe68e5300b8afed5a2269db4f2b606ec79178b84768594b3feaf7bf16c648953ab56532cb9ae2dde93ceedcfed57011ba7d14b5c592db1296605431c321ba9eb78c3f", + }, + outputs{ + difficulty: 200000, + parallelism: 9, + input: "03007dfafe46a1fbae1f8ec17e3845a40379eacf33fc55f2b31bb43c6702fa22b18e7a8eddc71f0b2071c6ba62fff55f8c442a1f46a73f40abef1f79d26930cb82761cc6884f3a8d01df", + output: "00000004006611f70b23d589f0dd59480f6c0ffda84585804e77b72b23bf4cf69276f2605c429032151fa5197bf5a71527bf90b30a126f73d85e31f2a0e801ff61fef4853a1771c8515fd4cd4111254e3af4a15f28fdb12accae276f9e4f08145608e566059d897290793d80a998de521be75e247826b97714556b542f89b241b6197bb196ffeeefa93de8cd6dc96c3d419d3c8f54aa4f7422222bf7c6d854f6f004ffd91d09df4ebfef8b3156939aadcbfe0bfcc787ac0f0f23d01fd73e39bf9740d41676283dca33be40a7cc16dde181ba592a901ba576e4b7f152c03efdba8719607db95f721bca6f9a83216f23dd4080ca09f299ec7ac90743da531e5d6a4a18b2d1c8e7007d0b86ef0cebb060a4634a30765d9a2979f15e636f440d81d1ec83b83a45ff328e016ad7332f6b7df5f12447edc83f99a81728d5ba789f9e1c47ab95fa2c8512fff2fdcf927389e530d68fdecb052a784d09d398897aff9f8e9557335eed70fb1fb1ce02fc4c466e2859ff048ceece145c3d71da74baf9604b02310fbbdc509bff840d4494f9a4f151a0db542cfc865c8c926cad74143c29d0f1919bb5ae420656db7b322a8f5dfa249ed31e96f469fb8d78f9632c4deeb9bad2e7b21248414477f099aece1e0ea5837ecb8b9a4017f97baaea4220d8c989175feb9322c2d8bcad5a9eb65bc09b468e2b2e88d65609022c248987ec46bd8992a3f595fd68bc4f61020544baa32d229284890a78cbb986e66cf9b7b2900f6b32c6a38fcef54022fbd085e25cc17e4abbc733389469909a9c0792f65c32606f79cac8c539dc53bb90f221a2fba9b01684a59a0309e3db6fd2db1ab498fb241c7d4678a6823b6baffea872a4690f95162f43a35f8a419e04d5b6fcab5b09953918b33d559c246e68105aebcd63dcefb6f984a0c924e353498aee75efa4", + }, + outputs{ + difficulty: 200000, + parallelism: 9, + input: "0023a13255cf438bc18d375d1f926640b97afca1fc7cb08ae76b6e42049cf5af68f4f4acec24d40f59f806b67aeea2fdb26addcd84fbca49aab3f01ad04335a7fa8c3c7a4a83885a5a0d93a7f157d4c2a5e33849ebe5332c3583f75b43ea18168a7af7be9f6242cdcacf4860c34ce3d5f006f8cb1eeed892c2c94468167bc734700021635fd3eaef29394df1a24b5bb3f02728817cd5bb9a20ca60abe36d4634d1dd9cbd6cdf05b6253eb292d222c31feb930e50163697f7fee2010b81d76243d1b9b416c65afc1030678ff1533cffb0fd7a21b2a6b7ef4c14baa60587902b1a4ef6bbb1b24ae167ceffb1a81fc8272bacff8678e7d5aef881ef8e83a8885d7660c500443b4e30500f7f45f8c9ebadb41d719d9fe2b6f63608eced684def604a9af1ffea97a966944b1eb70f18d4f1be022d26ba5afd9041b7a7a5c420a171cbd10a1ce67a96c8119764d2b148bf01079fade867a7769d8abc20f34c533f253dec6cbba068269f1381ad262b6d2e14169373b8382cbd2ddfe4dd884f40cafdaf342872001dbdbdb8a10f87e8753085200f645747a13413dc3fc17da38892edaa07a422397bc01cb3d3f4a1c44dc644cb584deb5816df4b310f7e3d34e92421a5b050195ca9510cc990f796ff32065d4d4c17aef990c4b26962a8138755c673b0e0cadd24a74ac316c250e0f2817383210355a7a856e999a9bf8241d34819f0449967548f", + output: "000000010065aef44165e5d1a62e113a632df7b756e2557ed801a775e5b33ec710d57ec1daa242acec3be10e747509eb1f4e118f9185535a2f476e8d973f399d5cbe7148905d5cd0e982f789a7aaec5925ef5eb1df313932fa6df9accf24b1240ba3228cb5c7b82fd316ee67cf57feb34b57dbe5c7f65ecb7d1888e9db7781fb57df7b976900299837fd3296c33c69adfe0a1adf90a27ad1d30233908dc1b431f827b59e6604e729756a7143e2ffcba3e92d6bcccf5d09d193315858f8035db9de433858c9755ee726cf4d5ff783445c83c3ad2fffefb5493297ab989a52676512df201baf5b531daebb1a538dbc42cad570ad824d278e0600a77ed434325c4fe130fddd44f5003e1391fcfa858aa614e6c46a6d5984752fa040c58e9501cd3a9c53b09592497155a9e220c1407589a6941c708f8ffbc973daa9a4c42bc906ec3ae1aafcf533424254f42094c48171c48cf56e5a692a0e89fff28a8e27070c73b49516a5f90f6d6a41baeb6ba1e611872427733d0d271e860024db8f4410d125a917bc4fd438cefff33bd1c1e49b1f57f53fa8dd43ce072743d88f4804baa3fe42aa700a0598ab1d6699616521b102f502d55898e6f0733f3ca62ba5d5944bc6d717c2c44a4f0f9960637146fc23dd6dd644880924b3de08da910de57afd4a77ffc15b1313ec50376919e2840f032c80f84e510834bce95a23139aabbbc7229636bf9432587505b303007dfafe46a1fbae1f8ec17e3845a40379eacf33fc55f2b31bb43c6702fa22b18e7a8eddc71f0b2071c6ba62fff55f8c442a1f46a73f40abef1f79d26930cb82761cc6884f3a8d01df0204ed8a69e286683d3059412ad78c915d73b4f3a47d818e337e85352cb750cfcbc7a3a953ce438ec6c04aae4d57dd612e7c3f932d2605eca9e11aa4e670d86c698762b5a1aaabb8d247", + }, + } + + slices.Reverse(outputs) + + peerPrivKey, err := hex.DecodeString("8bdc6de5a6781375b2915a74ccc97c0572ca69766ae41dba40170ee88313ade030ad5e5f4fe4ca111141d54c60e2c73ccbc51e1442366446b3a678a36247e9d0889b384a4e7ce9a6323fe3a386446ec1214d374a42d55fb741d4888f74fbfe60cf2595da44b659eae88db06210bc33c88000") + if err != nil { + t.FailNow() + } + + privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey) + if err != nil { + t.FailNow() + } + + pub := privKey.GetPublic() + pubkey, err := pub.Raw() + if err != nil { + t.FailNow() + } + + peerId, err := peer.IDFromPublicKey(pub) + if err != nil { + t.FailNow() + } + + addrBI, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + t.FailNow() + } + + addr := addrBI.FillBytes(make([]byte, 32)) + + batchCount := 0 + for i := len(outputs) - 1; i >= 0; i-- { + parallelism, inputhex, outputhex := outputs[i].parallelism, outputs[i].input, outputs[i].output + input, _ := hex.DecodeString(inputhex) + output, _ := hex.DecodeString(outputhex) + p := []byte{} + p = binary.BigEndian.AppendUint32(p, uint32(i)) + p = binary.BigEndian.AppendUint32(p, parallelism) + p = binary.BigEndian.AppendUint64(p, uint64(len(input))) + p = append(p, input...) + p = binary.BigEndian.AppendUint64(p, uint64(len(output))) + p = append(p, output...) + + proofs = append(proofs, p) + + batchCount++ + if batchCount == 10 || i == 0 { + payload := []byte("mint") + for _, i := range proofs { + payload = append(payload, i...) + } + + sig, err := privKey.Sign(payload) + if err != nil { + panic(err) + } + + a, err := d.handleMint( + &protobufs.MintCoinRequest{ + Proofs: proofs, + Signature: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: pubkey, + }, + Signature: sig, + }, + }, + ) + + assert.NoError(t, err) + + fmt.Printf("check %x\n", addr) + fr, prfs, err := app.CoinStore.GetPreCoinProofsForOwner(addr) + assert.Len(t, prfs, 1) + assert.Len(t, fr, 1) + for _, prf := range prfs { + if prf.IndexProof != nil { + resume, err = GetAddressOfPreCoinProof(prf) + assert.ElementsMatch(t, a, resume) + assert.NoError(t, err) + } + } + assert.NoError(t, err) + assert.NotEqual(t, resume, make([]byte, 32)) + batchCount = 0 + proofs = [][]byte{ + []byte("pre-dusk"), + resume, + } + } + } + + req := <-d.messageProcessorCh + + assert.NotNil(t, req) + message := &protobufs.Message{} + + err = proto.Unmarshal(req.Data, message) + assert.NoError(t, err) + appMsg := &anypb.Any{} + err = proto.Unmarshal(message.Payload, appMsg) + assert.NoError(t, err) + tr := &protobufs.TokenRequest{} + err = proto.Unmarshal(appMsg.Value, tr) + assert.NoError(t, err) + + d.stagedTransactions = &protobufs.TokenRequests{ + Requests: []*protobufs.TokenRequest{tr}, + } + // confirm operation cannot occur twice: + d.stagedTransactions.Requests = append( + d.stagedTransactions.Requests, + d.stagedTransactions.Requests[0], + ) + app, success, fail, err := app.ApplyTransitions(1, d.stagedTransactions, true) + assert.NoError(t, err) + + assert.Len(t, success.Requests, 1) + assert.Len(t, fail.Requests, 1) + + txn, _ := app.CoinStore.NewTransaction() + for i, o := range app.TokenOutputs.Outputs { + switch e := o.Output.(type) { + case *protobufs.TokenOutput_Coin: + a, err := GetAddressOfCoin(e.Coin, 1, uint64(i)) + assert.NoError(t, err) + err = app.CoinStore.PutCoin(txn, 1, a, e.Coin) + assert.NoError(t, err) + case *protobufs.TokenOutput_DeletedCoin: + c, err := app.CoinStore.GetCoinByAddress(txn, e.DeletedCoin.Address) + assert.NoError(t, err) + err = app.CoinStore.DeleteCoin(txn, e.DeletedCoin.Address, c) + assert.NoError(t, err) + case *protobufs.TokenOutput_Proof: + a, err := GetAddressOfPreCoinProof(e.Proof) + assert.NoError(t, err) + err = app.CoinStore.PutPreCoinProof(txn, 1, a, e.Proof) + assert.NoError(t, err) + case *protobufs.TokenOutput_DeletedProof: + a, err := GetAddressOfPreCoinProof(e.DeletedProof) + assert.NoError(t, err) + c, err := app.CoinStore.GetPreCoinProofByAddress(a) + assert.NoError(t, err) + err = app.CoinStore.DeletePreCoinProof(txn, a, c) + assert.NoError(t, err) + } + } + err = txn.Commit() + // confirm updated app state does fail transition + _, _, _, err = app.ApplyTransitions(1, d.stagedTransactions, false) + assert.Error(t, err) + + _, _, coin, err := app.CoinStore.GetCoinsForOwner(addr) + assert.Len(t, coin, 1) + assert.Equal(t, append(make([]byte, 28), 0x27, 0xe9, 0x49, 0x00), coin[0].Amount) +} + +func GetAddressOfCoin( + coin *protobufs.Coin, + frameNumber uint64, + seqno uint64, +) ([]byte, error) { + eval := []byte{} + eval = append(eval, application.TOKEN_ADDRESS...) + eval = binary.BigEndian.AppendUint64(eval, frameNumber) + if frameNumber != 0 { + eval = binary.BigEndian.AppendUint64(eval, seqno) + } + eval = append(eval, coin.Amount...) + eval = append(eval, coin.Intersection...) + eval = binary.BigEndian.AppendUint32(eval, 0) + eval = append(eval, coin.Owner.GetImplicitAccount().Address...) + addressBI, err := poseidon.HashBytes(eval) + if err != nil { + return nil, err + } + + return addressBI.FillBytes(make([]byte, 32)), nil +} diff --git a/node/consensus/master/broadcast_messaging.go b/node/consensus/master/broadcast_messaging.go index 2dd30d4..e2fe211 100644 --- a/node/consensus/master/broadcast_messaging.go +++ b/node/consensus/master/broadcast_messaging.go @@ -34,17 +34,6 @@ func (e *MasterClockConsensusEngine) handleMessage(message *pb.Message) error { return errors.Wrap(err, "handle message") } - switch any.TypeUrl { - case protobufs.ClockFrameType: - if err := e.handleClockFrameData( - message.From, - any, - ); err != nil { - return errors.Wrap(err, "handle message") - } - return nil - } - return errors.Wrap(errors.New("invalid message"), "handle message") } @@ -166,11 +155,6 @@ func (e *MasterClockConsensusEngine) publishProof( ) e.masterTimeReel.Insert(frame, false) - - err := e.publishMessage(e.filter, frame) - if err != nil { - return errors.Wrap(err, "publish proof") - } } e.state = consensus.EngineStateCollecting diff --git a/node/consensus/master/master_clock_consensus_engine.go b/node/consensus/master/master_clock_consensus_engine.go index 4eea18d..da70de3 100644 --- a/node/consensus/master/master_clock_consensus_engine.go +++ b/node/consensus/master/master_clock_consensus_engine.go @@ -51,9 +51,7 @@ type MasterClockConsensusEngine struct { syncingTarget []byte engineMx sync.Mutex seenFramesMx sync.Mutex - historicFramesMx sync.Mutex seenFrames []*protobufs.ClockFrame - historicFrames []*protobufs.ClockFrame clockStore store.ClockStore masterTimeReel *qtime.MasterTimeReel @@ -70,7 +68,7 @@ type MasterClockConsensusEngine struct { var _ consensus.ConsensusEngine = (*MasterClockConsensusEngine)(nil) -var MASTER_CLOCK_RATE = uint32(1000000) +var MASTER_CLOCK_RATE = uint32(160000) func NewMasterClockConsensusEngine( engineConfig *config.EngineConfig, @@ -185,14 +183,6 @@ func (e *MasterClockConsensusEngine) Start() <-chan error { panic(err) } - frame, err := e.masterTimeReel.Head() - if err != nil { - panic(err) - } - - e.logger.Info("building historic frame cache") - e.buildHistoricFrameCache(frame) - go func() { for { select { @@ -360,43 +350,6 @@ func ( return e.frameChan } -func (e *MasterClockConsensusEngine) buildHistoricFrameCache( - latestFrame *protobufs.ClockFrame, -) { - e.historicFrames = []*protobufs.ClockFrame{} - - if latestFrame.FrameNumber != 0 { - min := uint64(0) - if latestFrame.FrameNumber-255 > min && latestFrame.FrameNumber > 255 { - min = latestFrame.FrameNumber - 255 - } - - iter, err := e.clockStore.RangeMasterClockFrames( - e.filter, - min, - latestFrame.FrameNumber-1, - ) - if err != nil { - panic(err) - } - - for iter.First(); iter.Valid(); iter.Next() { - frame, err := iter.Value() - if err != nil { - panic(err) - } - - e.historicFrames = append(e.historicFrames, frame) - } - - if err = iter.Close(); err != nil { - panic(err) - } - } - - e.historicFrames = append(e.historicFrames, latestFrame) -} - func (e *MasterClockConsensusEngine) addPeerManifestReport( peerId []byte, report *protobufs.SelfTestReport, diff --git a/node/consensus/master/peer_messaging.go b/node/consensus/master/peer_messaging.go index 65ada79..4eac311 100644 --- a/node/consensus/master/peer_messaging.go +++ b/node/consensus/master/peer_messaging.go @@ -35,7 +35,7 @@ func (e *MasterClockConsensusEngine) Sync( panic(err) } - if masterFrame.FrameNumber < from || len(e.historicFrames) == 0 { + if masterFrame.FrameNumber < from { e.logger.Debug( "peer asked for undiscovered frame", zap.Uint64("frame_number", request.FramesRequest.FromFrameNumber), diff --git a/node/consensus/time/data_time_reel.go b/node/consensus/time/data_time_reel.go index 97fbb67..6d9a266 100644 --- a/node/consensus/time/data_time_reel.go +++ b/node/consensus/time/data_time_reel.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/hex" "math/big" - "sort" "sync" lru "github.com/hashicorp/golang-lru/v2" @@ -39,6 +38,7 @@ type DataTimeReel struct { logger *zap.Logger clockStore store.ClockStore frameProver crypto.FrameProver + exec func(txn store.Transaction, frame *protobufs.ClockFrame) error origin []byte initialInclusionProof *crypto.InclusionAggregateProof @@ -48,12 +48,12 @@ type DataTimeReel struct { headDistance *big.Int lruFrames *lru.Cache[string, string] proverTries []*tries.RollingFrecencyCritbitTrie - pending map[uint64][]*pendingFrame - incompleteForks map[uint64][]*pendingFrame - frames chan *pendingFrame - newFrameCh chan *protobufs.ClockFrame - badFrameCh chan *protobufs.ClockFrame - done chan bool + // pending map[uint64][]*pendingFrame + incompleteForks map[uint64][]*pendingFrame + frames chan *pendingFrame + newFrameCh chan *protobufs.ClockFrame + badFrameCh chan *protobufs.ClockFrame + done chan bool } func NewDataTimeReel( @@ -62,6 +62,7 @@ func NewDataTimeReel( clockStore store.ClockStore, engineConfig *config.EngineConfig, frameProver crypto.FrameProver, + exec func(txn store.Transaction, frame *protobufs.ClockFrame) error, origin []byte, initialInclusionProof *crypto.InclusionAggregateProof, initialProverKeys [][]byte, @@ -82,6 +83,10 @@ func NewDataTimeReel( panic("engine config is nil") } + if exec == nil { + panic("execution function is nil") + } + if frameProver == nil { panic("frame prover is nil") } @@ -98,16 +103,17 @@ func NewDataTimeReel( engineConfig: engineConfig, clockStore: clockStore, frameProver: frameProver, + exec: exec, origin: origin, initialInclusionProof: initialInclusionProof, initialProverKeys: initialProverKeys, lruFrames: cache, - pending: make(map[uint64][]*pendingFrame), - incompleteForks: make(map[uint64][]*pendingFrame), - frames: make(chan *pendingFrame), - newFrameCh: make(chan *protobufs.ClockFrame), - badFrameCh: make(chan *protobufs.ClockFrame), - done: make(chan bool), + // pending: make(map[uint64][]*pendingFrame), + incompleteForks: make(map[uint64][]*pendingFrame), + frames: make(chan *pendingFrame), + newFrameCh: make(chan *protobufs.ClockFrame), + badFrameCh: make(chan *protobufs.ClockFrame), + done: make(chan bool), } } @@ -131,11 +137,20 @@ func (d *DataTimeReel) Start() error { d.headDistance, err = d.GetDistance(frame) } + d.running = true go d.runLoop() return nil } +func (d *DataTimeReel) SetHead(frame *protobufs.ClockFrame) { + if d.running == true { + panic("internal test function should never be called outside of tests") + } + + d.head = frame +} + func (d *DataTimeReel) Head() (*protobufs.ClockFrame, error) { return d.head, nil } @@ -154,11 +169,11 @@ func (d *DataTimeReel) Insert(frame *protobufs.ClockFrame, isSync bool) error { zap.String("output_tag", hex.EncodeToString(frame.Output[:64])), ) - if d.lruFrames.Contains(string(frame.Output[:64])) { - return nil - } + // if d.lruFrames.Contains(string(frame.Output[:64])) { + // return nil + // } - d.lruFrames.Add(string(frame.Output[:64]), string(frame.ParentSelector)) + // d.lruFrames.Add(string(frame.Output[:64]), string(frame.ParentSelector)) parent := new(big.Int).SetBytes(frame.ParentSelector) selector, err := frame.GetSelector() @@ -168,16 +183,18 @@ func (d *DataTimeReel) Insert(frame *protobufs.ClockFrame, isSync bool) error { distance, _ := d.GetDistance(frame) - d.storePending(selector, parent, distance, frame) + if d.head.FrameNumber < frame.FrameNumber { + d.storePending(selector, parent, distance, frame) - if !isSync { - go func() { - d.frames <- &pendingFrame{ - selector: selector, - parentSelector: parent, - frameNumber: frame.FrameNumber, - } - }() + if d.head.FrameNumber+1 == frame.FrameNumber { + go func() { + d.frames <- &pendingFrame{ + selector: selector, + parentSelector: parent, + frameNumber: frame.FrameNumber, + } + }() + } } return nil @@ -253,6 +270,17 @@ func (d *DataTimeReel) createGenesisFrame() ( panic(err) } + err = txn.Commit() + if err != nil { + txn.Abort() + panic(err) + } + + txn, err = d.clockStore.NewTransaction() + if err != nil { + panic(err) + } + if err := d.clockStore.CommitDataClockFrame( d.filter, 0, @@ -273,7 +301,6 @@ func (d *DataTimeReel) createGenesisFrame() ( // Main data consensus loop func (d *DataTimeReel) runLoop() { - d.running = true for { select { case frame := <-d.frames: @@ -297,11 +324,11 @@ func (d *DataTimeReel) runLoop() { if d.head.FrameNumber < rawFrame.FrameNumber { d.logger.Debug("frame is higher") - parent := new(big.Int).SetBytes(rawFrame.ParentSelector) - selector, err := rawFrame.GetSelector() - if err != nil { - panic(err) - } + // parent := new(big.Int).SetBytes(rawFrame.ParentSelector) + // selector, err := rawFrame.GetSelector() + // if err != nil { + // panic(err) + // } distance, err := d.GetDistance(rawFrame) if err != nil { @@ -309,27 +336,14 @@ func (d *DataTimeReel) runLoop() { panic(err) } - d.addPending(selector, parent, frame.frameNumber) + // d.addPending(selector, parent, frame.frameNumber) d.processPending(d.head, frame) continue } - headSelector, err := d.head.GetSelector() - if err != nil { - panic(err) - } - // If the frame has a gap from the head or is not descendent, mark it as // pending: if rawFrame.FrameNumber-d.head.FrameNumber != 1 { - d.logger.Debug( - "frame has has gap, fork choice", - zap.Bool("has_gap", rawFrame.FrameNumber-d.head.FrameNumber != 1), - zap.String("parent_selector", parent.Text(16)), - zap.String("head_selector", headSelector.Text(16)), - ) - - d.forkChoice(rawFrame, distance) d.processPending(d.head, frame) continue } @@ -345,60 +359,68 @@ func (d *DataTimeReel) runLoop() { continue } - distance, err := d.GetDistance(rawFrame) - if err != nil { - panic(err) - } - d.logger.Debug( - "frame is same height", - zap.String("head_distance", d.headDistance.Text(16)), - zap.String("distance", distance.Text(16)), - ) - - // Optimization: if competing frames share a parent we can short-circuit - // fork choice - if bytes.Equal(d.head.ParentSelector, rawFrame.ParentSelector) && - distance.Cmp(d.headDistance) < 0 { - d.logger.Debug( - "frame shares parent, has shorter distance, short circuit", - ) - d.totalDistance.Sub(d.totalDistance, d.headDistance) - d.setHead(rawFrame, distance) - d.processPending(d.head, frame) - continue - } + // temp: remove fork choice until prover ring testing + // distance, err := d.GetDistance(rawFrame) + // if err != nil { + // panic(err) + // } + // d.logger.Debug( + // "frame is same height", + // zap.String("head_distance", d.headDistance.Text(16)), + // zap.String("distance", distance.Text(16)), + // ) + + // // Optimization: if competing frames share a parent we can short-circuit + // // fork choice + // if bytes.Equal(d.head.ParentSelector, rawFrame.ParentSelector) && + // distance.Cmp(d.headDistance) < 0 { + // d.logger.Debug( + // "frame shares parent, has shorter distance, short circuit", + // ) + // d.totalDistance.Sub(d.totalDistance, d.headDistance) + // d.setHead(rawFrame, distance) + // d.processPending(d.head, frame) + // continue + // } // Choose fork - d.forkChoice(rawFrame, distance) + // d.forkChoice(rawFrame, distance) d.processPending(d.head, frame) } else { - d.logger.Debug("frame is lower height") - - // tag: dusk – we should have some kind of check here to avoid brutal - // thrashing - existing, _, err := d.clockStore.GetDataClockFrame( - d.filter, - rawFrame.FrameNumber, - true, - ) - if err != nil { - // if this returns an error it's either not found (which shouldn't - // happen without corruption) or pebble is borked, either way, panic - panic(err) - } - - // It's a fork, but it's behind. We need to stash it until it catches - // up (or dies off) - if !bytes.Equal(existing.Output, rawFrame.Output) { - d.logger.Debug("is fork, add pending") - parent, selector, err := rawFrame.GetParentAndSelector() - if err != nil { - panic(err) - } - - d.addPending(selector, parent, frame.frameNumber) - d.processPending(d.head, frame) - } + // d.logger.Debug("frame is lower height") + + // existing, _, err := d.clockStore.GetDataClockFrame( + // d.filter, + // rawFrame.FrameNumber, + // true, + // ) + // if err != nil { + // // if this returns an error it's either not found (which shouldn't + // // happen without corruption) or pebble is borked, either way, panic + // panic(err) + // } + + // if !bytes.Equal(existing.Output, rawFrame.Output) { + // parent, selector, err := rawFrame.GetParentAndSelector() + // if err != nil { + // panic(err) + // } + + // if bytes.Equal(existing.ParentSelector, rawFrame.ParentSelector) { + // ld := d.getTotalDistance(existing) + // rd := d.getTotalDistance(rawFrame) + // if rd.Cmp(ld) < 0 { + // d.forkChoice(rawFrame, rd) + // d.processPending(d.head, frame) + // } else { + // d.addPending(selector, parent, frame.frameNumber) + // d.processPending(d.head, frame) + // } + // } else { + // d.addPending(selector, parent, frame.frameNumber) + // d.processPending(d.head, frame) + // } + // } } case <-d.done: return @@ -406,49 +428,49 @@ func (d *DataTimeReel) runLoop() { } } -func (d *DataTimeReel) addPending( - selector *big.Int, - parent *big.Int, - frameNumber uint64, -) { - d.logger.Debug( - "add pending", - zap.Uint64("head_frame_number", d.head.FrameNumber), - zap.Uint64("add_frame_number", frameNumber), - zap.String("selector", selector.Text(16)), - zap.String("parent", parent.Text(16)), - ) - - if d.head.FrameNumber <= frameNumber { - if _, ok := d.pending[frameNumber]; !ok { - d.pending[frameNumber] = []*pendingFrame{} - } - - // avoid heavy thrashing - for _, frame := range d.pending[frameNumber] { - if frame.selector.Cmp(selector) == 0 { - d.logger.Debug("exists in pending already") - return - } - } - } - - if d.head.FrameNumber <= frameNumber { - d.logger.Debug( - "accumulate in pending", - zap.Int("pending_neighbors", len(d.pending[frameNumber])), - ) - - d.pending[frameNumber] = append( - d.pending[frameNumber], - &pendingFrame{ - selector: selector, - parentSelector: parent, - frameNumber: frameNumber, - }, - ) - } -} +// func (d *DataTimeReel) addPending( +// selector *big.Int, +// parent *big.Int, +// frameNumber uint64, +// ) { +// // d.logger.Debug( +// // "add pending", +// // zap.Uint64("head_frame_number", d.head.FrameNumber), +// // zap.Uint64("add_frame_number", frameNumber), +// // zap.String("selector", selector.Text(16)), +// // zap.String("parent", parent.Text(16)), +// // ) + +// if d.head.FrameNumber <= frameNumber { +// if _, ok := d.pending[frameNumber]; !ok { +// d.pending[frameNumber] = []*pendingFrame{} +// } + +// // avoid heavy thrashing +// for _, frame := range d.pending[frameNumber] { +// if frame.selector.Cmp(selector) == 0 { +// d.logger.Debug("exists in pending already") +// return +// } +// } +// } + +// if d.head.FrameNumber <= frameNumber { +// // d.logger.Debug( +// // "accumulate in pending", +// // zap.Int("pending_neighbors", len(d.pending[frameNumber])), +// // ) + +// d.pending[frameNumber] = append( +// d.pending[frameNumber], +// &pendingFrame{ +// selector: selector, +// parentSelector: parent, +// frameNumber: frameNumber, +// }, +// ) +// } +// } func (d *DataTimeReel) storePending( selector *big.Int, @@ -494,62 +516,69 @@ func (d *DataTimeReel) processPending( frame *protobufs.ClockFrame, lastReceived *pendingFrame, ) { - d.logger.Debug( - "process pending", - zap.Int("pending_frame_numbers", len(d.pending)), - ) - frameNumbers := []uint64{} - for f := range d.pending { - frameNumbers = append(frameNumbers, f) - d.logger.Debug( - "pending per frame number", - zap.Uint64("pending_frame_number", f), - zap.Int("pending_frames", len(d.pending[f])), - ) - } - sort.Slice(frameNumbers, func(i, j int) bool { - return frameNumbers[i] > frameNumbers[j] - }) + // d.logger.Debug( + // "process pending", + // zap.Uint64("head_frame", frame.FrameNumber), + // zap.Uint64("last_received_frame", lastReceived.frameNumber), + // zap.Int("pending_frame_numbers", len(d.pending)), + // ) - lastSelector := lastReceived.selector - - for _, f := range frameNumbers { - if f < d.head.FrameNumber { - delete(d.pending, f) + for { + next := d.head.FrameNumber + 1 + sel, err := d.head.GetSelector() + if err != nil { + panic(err) } - nextPending := d.pending[f] - d.logger.Debug( - "checking frame set", - zap.Uint64("pending_frame_number", f), - zap.Uint64("frame_number", frame.FrameNumber), + selector := sel.FillBytes(make([]byte, 32)) + // d.logger.Debug( + // "checking frame set", + // zap.Uint64("pending_frame_number", f), + // zap.Uint64("frame_number", frame.FrameNumber), + // ) + // Pull the next + d.logger.Debug("try process next") + + //// todo: revise for prover rings + rawFrames, err := d.clockStore.GetStagedDataClockFramesForFrameNumber( + d.filter, + next, ) - if f < frame.FrameNumber { + if err != nil { + panic(err) + } + + found := false + for _, rawFrame := range rawFrames { + if !bytes.Equal(rawFrame.ParentSelector, selector) { + continue + } + d.logger.Debug( - "purging frame set", - zap.Uint64("pending_frame_number", f), - zap.Uint64("frame_number", frame.FrameNumber), + "processing frame", + zap.Uint64("frame_number", rawFrame.FrameNumber), + zap.String("output_tag", hex.EncodeToString(rawFrame.Output[:64])), + zap.Uint64("head_number", d.head.FrameNumber), + zap.String("head_output_tag", hex.EncodeToString(d.head.Output[:64])), ) - delete(d.pending, f) - continue - } - // Pull the next - for len(nextPending) != 0 { - d.logger.Debug("try process next") - next := nextPending[0] - d.pending[f] = d.pending[f][1:] - if f == lastReceived.frameNumber && next.selector.Cmp(lastSelector) == 0 { - d.pending[f] = append(d.pending[f], next) - if len(d.pending[f]) == 1 { - nextPending = nil + + distance, err := d.GetDistance(rawFrame) + if err != nil { + if !errors.Is(err, store.ErrNotFound) { + panic(err) } + continue } - go func() { - d.frames <- next - }() - return + // Otherwise set it as the next and process all pending + d.setHead(rawFrame, distance) + found = true + break + } + + if !found { + break } } } @@ -588,6 +617,11 @@ func (d *DataTimeReel) setHead(frame *protobufs.ClockFrame, distance *big.Int) { ); err != nil { panic(err) } + if err = d.exec(txn, frame); err != nil { + d.logger.Debug("invalid frame execution, unwinding", zap.Error(err)) + txn.Abort() + return + } if err = txn.Commit(); err != nil { panic(err) @@ -597,7 +631,10 @@ func (d *DataTimeReel) setHead(frame *protobufs.ClockFrame, distance *big.Int) { d.headDistance = distance go func() { - d.newFrameCh <- frame + select { + case d.newFrameCh <- frame: + default: + } }() } @@ -695,7 +732,7 @@ func (d *DataTimeReel) forkChoice( zap.Uint64("head_number", d.head.FrameNumber), zap.String("head_output_tag", hex.EncodeToString(d.head.Output[:64])), ) - parentSelector, selector, err := frame.GetParentAndSelector() + _, selector, err := frame.GetParentAndSelector() if err != nil { panic(err) } @@ -728,7 +765,7 @@ func (d *DataTimeReel) forkChoice( if err != nil { // If lineage cannot be verified, set it for later if errors.Is(err, store.ErrNotFound) { - d.addPending(selector, parentSelector, frame.FrameNumber) + // d.addPending(selector, parentSelector, frame.FrameNumber) return } else { panic(err) @@ -791,7 +828,7 @@ func (d *DataTimeReel) forkChoice( if err != nil { // If lineage cannot be verified, set it for later if errors.Is(err, store.ErrNotFound) { - d.addPending(selector, parentSelector, frame.FrameNumber) + // d.addPending(selector, parentSelector, frame.FrameNumber) return } else { panic(err) @@ -825,7 +862,7 @@ func (d *DataTimeReel) forkChoice( zap.String("right_total", rightTotal.Text(16)), zap.String("left_total", overweight.Text(16)), ) - d.addPending(selector, parentSelector, frame.FrameNumber) + // d.addPending(selector, parentSelector, frame.FrameNumber) return } @@ -897,7 +934,10 @@ func (d *DataTimeReel) forkChoice( ) go func() { - d.newFrameCh <- frame + select { + case d.newFrameCh <- frame: + default: + } }() } diff --git a/node/consensus/time/data_time_reel_test.go b/node/consensus/time/data_time_reel_test.go index 0f635b2..4c00e3c 100644 --- a/node/consensus/time/data_time_reel_test.go +++ b/node/consensus/time/data_time_reel_test.go @@ -3,6 +3,7 @@ package time_test import ( "bytes" "fmt" + "math/rand" "strings" "sync" "testing" @@ -139,38 +140,6 @@ func TestDataTimeReel(t *testing.T) { frame, err := m.Head() assert.NoError(t, err) - frames := []*protobufs.ClockFrame{} - wg := sync.WaitGroup{} - wg.Add(1) - frameCh := m.NewFrameCh() - go func() { - for i := 0; i < 40; i++ { - frames = append(frames, <-frameCh) - } - wg.Done() - }() - - // in order - for i := int64(0); i < 40; i++ { - frame, err = prover.ProveMasterClockFrame( - frame, - i+1, - 10, - []*protobufs.InclusionAggregateProof{}, - ) - assert.NoError(t, err) - - err := m.Insert(frame, false) - assert.NoError(t, err) - } - - wg.Wait() - - for i := 0; i < 40; i++ { - assert.NotNil(t, frames[i]) - assert.Equal(t, frames[i].FrameNumber, uint64(i+1)) - } - filterBytes := []byte{ 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, @@ -200,7 +169,8 @@ func TestDataTimeReel(t *testing.T) { Difficulty: 10, }, prover, - frames[0].Output, + func(txn store.Transaction, frame *protobufs.ClockFrame) error { return nil }, + bytes.Repeat([]byte{0x00}, 516), &qcrypto.InclusionAggregateProof{ InclusionCommitments: []*qcrypto.InclusionCommitment{}, AggregateCommitment: []byte{}, @@ -219,29 +189,25 @@ func TestDataTimeReel(t *testing.T) { datawg := sync.WaitGroup{} datawg.Add(1) dataFrameCh := d.NewFrameCh() - targetFrameParentSelector := []byte{} go func() { + loop: for { - frame := <-dataFrameCh - dataFrames = append(dataFrames, frame) - if frame.FrameNumber == 40 && bytes.Equal( - frame.ParentSelector, - targetFrameParentSelector, - ) { - break + select { + case frame := <-dataFrameCh: + dataFrames = append(dataFrames, frame) + if frame.FrameNumber == 500 { + break loop + } } - } datawg.Done() }() + prev := make([]byte, 32) // 1. z-dist optimal – proof submission is strictly master-frame evoked leader - for i := int64(0); i < 10; i++ { - masterSelector, err := frames[i].GetSelector() - assert.NoError(t, err) - + for i := int64(0); i < 100; i++ { proverSelection := proverTrie.FindNearest( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) optimalSigner, _ := keyManager.GetSigningKey( addrMap[string(proverSelection.External.Key)], @@ -255,18 +221,17 @@ func TestDataTimeReel(t *testing.T) { 10, ) d.Insert(frame, false) + prevBI, _ := frame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) } // 2. z-dist optimal, out of order – proof submission is strictly master-frame // evoked leader, but arrived completely backwards insertFrames := []*protobufs.ClockFrame{} - for i := int64(10); i < 20; i++ { - masterSelector, err := frames[i].GetSelector() - assert.NoError(t, err) - + for i := int64(100); i < 200; i++ { proverSelection := proverTrie.FindNearest( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) optimalSigner, _ := keyManager.GetSigningKey( addrMap[string(proverSelection.External.Key)], @@ -280,9 +245,12 @@ func TestDataTimeReel(t *testing.T) { 10, ) insertFrames = append(insertFrames, frame) + + prevBI, _ := frame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) } - for i := 9; i >= 0; i-- { + for i := 99; i >= 0; i-- { err := d.Insert(insertFrames[i], false) assert.NoError(t, err) } @@ -290,12 +258,9 @@ func TestDataTimeReel(t *testing.T) { // 3. 90% optimal, out of order insertFrames = []*protobufs.ClockFrame{} - for i := int64(20); i < 25; i++ { - masterSelector, err := frames[i].GetSelector() - assert.NoError(t, err) - + for i := int64(200); i < 300; i++ { proverSelection := proverTrie.FindNearest( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) optimalSigner, _ := keyManager.GetSigningKey( addrMap[string(proverSelection.External.Key)], @@ -309,13 +274,13 @@ func TestDataTimeReel(t *testing.T) { 10, ) d.Insert(frame, false) - } - masterSelector, err := frames[25].GetSelector() - assert.NoError(t, err) + prevBI, _ := frame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) + } proverSelections := proverTrie.FindNearestAndApproximateNeighbors( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) suboptimalSigner2, _ := keyManager.GetSigningKey( addrMap[string(proverSelections[2].External.Key)], @@ -327,17 +292,17 @@ func TestDataTimeReel(t *testing.T) { [][]byte{}, []*protobufs.InclusionAggregateProof{}, suboptimalSigner2, - 26, + 301, 10, ) insertFrames = append(insertFrames, frame) - for i := int64(26); i < 30; i++ { - masterSelector, err := frames[i].GetSelector() - assert.NoError(t, err) + prevBI, _ := frame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) + for i := int64(301); i < 400; i++ { proverSelection := proverTrie.FindNearest( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) optimalSigner, _ := keyManager.GetSigningKey( addrMap[string(proverSelection.External.Key)], @@ -351,9 +316,11 @@ func TestDataTimeReel(t *testing.T) { 10, ) insertFrames = append(insertFrames, frame) + prevBI, _ := frame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) } - for i := 4; i >= 0; i-- { + for i := 99; i >= 0; i-- { err := d.Insert(insertFrames[i], false) assert.NoError(t, err) } @@ -364,12 +331,9 @@ func TestDataTimeReel(t *testing.T) { conflictFrames := []*protobufs.ClockFrame{} optimalKeySet := [][]byte{} suppressedFrame := frame - for i := int64(30); i < 40; i++ { - masterSelector, err := frames[i].GetSelector() - assert.NoError(t, err) - + for i := int64(400); i < 500; i++ { proverSelections := proverTrie.FindNearestAndApproximateNeighbors( - masterSelector.FillBytes(make([]byte, 32)), + prev, ) optimalSigner, _ := keyManager.GetSigningKey( addrMap[string(proverSelections[0].External.Key)], @@ -391,10 +355,10 @@ func TestDataTimeReel(t *testing.T) { i+1, 10, ) + prevBI, _ := suppressedFrame.GetSelector() + prev = prevBI.FillBytes(make([]byte, 32)) + insertFrames = append(insertFrames, suppressedFrame) - if i == 39 { - targetFrameParentSelector = suppressedFrame.ParentSelector - } frame, err = prover.ProveDataClockFrame( frame, [][]byte{}, @@ -406,15 +370,20 @@ func TestDataTimeReel(t *testing.T) { conflictFrames = append(conflictFrames, frame) } - for i := 9; i >= 0; i-- { - err := d.Insert(conflictFrames[i], false) - // force linear ordering - gotime.Sleep(1 * gotime.Second) - assert.NoError(t, err) - } + rand.Shuffle(100, func(i, j int) { + insertFrames[i], insertFrames[j] = insertFrames[j], insertFrames[i] + }) + + // todo: restore with prover rings + // for i := 99; i >= 0; i-- { + // err := d.Insert(conflictFrames[i], false) + // // force linear ordering + // gotime.Sleep(1 * gotime.Second) + // assert.NoError(t, err) + // } // Someone is honest, but running backwards: - for i := 9; i >= 0; i-- { + for i := 99; i >= 0; i-- { err := d.Insert(insertFrames[i], false) gotime.Sleep(1 * gotime.Second) assert.NoError(t, err) @@ -422,7 +391,7 @@ func TestDataTimeReel(t *testing.T) { datawg.Wait() - assert.Equal(t, uint64(40), dataFrames[len(dataFrames)-1].FrameNumber) + assert.Equal(t, uint64(500), dataFrames[len(dataFrames)-1].FrameNumber) assert.Equal( t, optimalKeySet[len(optimalKeySet)-1], diff --git a/node/consensus/time/master_time_reel.go b/node/consensus/time/master_time_reel.go index f916d8c..aec5833 100644 --- a/node/consensus/time/master_time_reel.go +++ b/node/consensus/time/master_time_reel.go @@ -9,8 +9,6 @@ import ( "go.uber.org/zap" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/crypto" - "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" - "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" "source.quilibrium.com/quilibrium/monorepo/node/store" ) @@ -90,13 +88,10 @@ func (m *MasterTimeReel) Start() error { } rebuildGenesisFrame := false - if genesis != nil && genesis.Difficulty != 1000000 { + if genesis != nil && genesis.Difficulty != 160000 { m.logger.Info("rewinding time reel to genesis") err = m.clockStore.ResetMasterClockFrames(m.filter) - err = m.clockStore.ResetDataClockFrames( - p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3), - ) if err != nil { panic(err) } @@ -104,7 +99,7 @@ func (m *MasterTimeReel) Start() error { rebuildGenesisFrame = true } - if genesis == nil || rebuildGenesisFrame { + if genesis == nil || rebuildGenesisFrame || frame == nil { m.logger.Info("creating genesis frame") m.head = m.createGenesisFrame() } else { @@ -156,8 +151,8 @@ func (m *MasterTimeReel) createGenesisFrame() *protobufs.ClockFrame { } difficulty := m.engineConfig.Difficulty - if difficulty != 1000000 { - difficulty = 1000000 + if difficulty != 160000 { + difficulty = 160000 } frame, err := m.frameProver.CreateMasterGenesisFrame( diff --git a/node/execution/intrinsics/token/application/token_application.go b/node/execution/intrinsics/token/application/token_application.go index a710611..5886de1 100644 --- a/node/execution/intrinsics/token/application/token_application.go +++ b/node/execution/intrinsics/token/application/token_application.go @@ -1,19 +1,12 @@ package application import ( - "bytes" - "encoding/binary" - "math/big" + "crypto" - "github.com/iden3/go-iden3-crypto/poseidon" - pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" "github.com/pkg/errors" "go.uber.org/zap" - "golang.org/x/crypto/sha3" "google.golang.org/protobuf/proto" - "source.quilibrium.com/quilibrium/monorepo/node/crypto" - "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/protobufs" "source.quilibrium.com/quilibrium/monorepo/node/store" "source.quilibrium.com/quilibrium/monorepo/node/tries" @@ -30,6 +23,7 @@ var TOKEN_ADDRESS = []byte{ } type TokenApplication struct { + Beacon []byte TokenOutputs *protobufs.TokenOutputs Tries []*tries.RollingFrecencyCritbitTrie CoinStore store.CoinStore @@ -77,6 +71,7 @@ func GetOutputsFromClockFrame( } func MaterializeApplicationFromFrame( + privKey crypto.Signer, frame *protobufs.ClockFrame, tries []*tries.RollingFrecencyCritbitTrie, store store.CoinStore, @@ -87,7 +82,10 @@ func MaterializeApplicationFromFrame( return nil, errors.Wrap(err, "materialize application from frame") } + genesis := config.GetGenesis() + return &TokenApplication{ + Beacon: genesis.Beacon, TokenOutputs: tokenOutputs, Tries: tries, CoinStore: store, @@ -109,443 +107,13 @@ func (a *TokenApplication) ApplyTransitions( finalizedTransitions := &protobufs.TokenRequests{} failedTransitions := &protobufs.TokenRequests{} outputs := &protobufs.TokenOutputs{} + lockMap := map[string]struct{}{} for _, transition := range transitions.Requests { req: switch t := transition.Request.(type) { case *protobufs.TokenRequest_Announce: - var primary *protobufs.Ed448Signature - payload := []byte{} - - if t.Announce == nil || t.Announce.PublicKeySignaturesEd448 == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - for i, p := range t.Announce.PublicKeySignaturesEd448 { - if p.PublicKey == nil || p.Signature == nil || - p.PublicKey.KeyValue == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - if i == 0 { - primary = p - } else { - payload = append(payload, p.PublicKey.KeyValue...) - if err := p.Verify(primary.PublicKey.KeyValue); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - err, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - } - } - if primary == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - if err := primary.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - err, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if t.Announce.InitialProof != nil && - t.Announce.InitialProof.Proofs != nil { - payload = []byte("mint") - for _, p := range t.Announce.InitialProof.Proofs { - payload = append(payload, p...) - } - if err := t.Announce.InitialProof.Signature.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - pk, err := pcrypto.UnmarshalEd448PublicKey( - t.Announce.InitialProof.Signature.PublicKey.KeyValue, - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - peerId, err := peer.IDFromPublicKey(pk) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - addr, err := poseidon.HashBytes( - t.Announce.InitialProof.Signature.PublicKey.KeyValue, - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if len(t.Announce.InitialProof.Proofs) == 3 && - bytes.Equal( - t.Announce.InitialProof.Proofs[0], - []byte("pre-dusk"), - ) && bytes.Equal(t.Announce.InitialProof.Proofs[1], make([]byte, 32)) && - currentFrameNumber < 604800 { - delete := []*protobufs.TokenOutput{} - if !bytes.Equal(t.Announce.InitialProof.Proofs[1], make([]byte, 32)) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - data := t.Announce.InitialProof.Proofs[2] - if len(data) < 28 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - increment := binary.BigEndian.Uint32(data[:4]) - parallelism := binary.BigEndian.Uint32(data[8:12]) - inputLen := binary.BigEndian.Uint64(data[12:20]) - - if len(delete) != 0 { - if delete[0].GetDeletedProof().Difficulty-1 != increment { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - } - - if uint64(len(data[20:])) < inputLen+8 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - input := make([]byte, inputLen) - copy(input[:], data[20:20+inputLen]) - - outputLen := binary.BigEndian.Uint64(data[20+inputLen : 20+inputLen+8]) - - if uint64(len(data[20+inputLen+8:])) < outputLen { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - output := make([]byte, outputLen) - copy(output[:], data[20+inputLen+8:]) - dataProver := crypto.NewKZGInclusionProver(a.Logger) - wesoProver := crypto.NewWesolowskiFrameProver(a.Logger) - index := binary.BigEndian.Uint32(output[:4]) - indexProof := output[4:520] - kzgCommitment := output[520:594] - kzgProof := output[594:668] - ip := sha3.Sum512(indexProof) - - v, err := dataProver.VerifyRaw( - ip[:], - kzgCommitment, - int(index), - kzgProof, - nearestApplicablePowerOfTwo(uint64(parallelism)), - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !v { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - wp := []byte{} - wp = append(wp, peerId...) - wp = append(wp, input...) - v = wesoProver.VerifyPreDuskChallengeProof( - wp, - increment, - index, - indexProof, - ) - if !v { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - pomwBasis := big.NewInt(1200000) - - reward := new(big.Int).Mul(pomwBasis, big.NewInt(int64(parallelism))) - if len(delete) != 0 { - reward.Add( - reward, - new(big.Int).SetBytes(delete[0].GetDeletedProof().Amount), - ) - } - - if increment != 0 { - add := &protobufs.PreCoinProof{ - Amount: reward.FillBytes(make([]byte, 32)), - Index: index, - IndexProof: indexProof, - Commitment: kzgCommitment, - Proof: append(append([]byte{}, kzgProof...), indexProof...), - Parallelism: parallelism, - Difficulty: increment, - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - } - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Proof{ - Proof: add, - }, - }) - } else { - add := &protobufs.Coin{ - Amount: reward.FillBytes(make([]byte, 32)), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - } - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: add, - }, - }) - } - outputs.Outputs = append(outputs.Outputs, delete...) - } else { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - } - case *protobufs.TokenRequest_Merge: - newCoin := &protobufs.Coin{} - newTotal := new(big.Int) - newIntersection := make([]byte, 1024) - payload := []byte("merge") - if t.Merge == nil || t.Merge.Coins == nil || t.Merge.Signature == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - for _, c := range t.Merge.Coins { - if c.Address == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - payload = append(payload, c.Address...) - } - if t.Merge.Signature.PublicKey == nil || - t.Merge.Signature.Signature == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - if err := t.Merge.Signature.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - err, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - addr, err := poseidon.HashBytes(t.Merge.Signature.PublicKey.KeyValue) + success, err := a.handleAnnounce(currentFrameNumber, lockMap, t.Announce) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( @@ -559,43 +127,17 @@ func (a *TokenApplication) ApplyTransitions( ) break req } - pk, err := pcrypto.UnmarshalEd448PublicKey( - t.Merge.Signature.PublicKey.KeyValue, + outputs.Outputs = append(outputs.Outputs, success...) + finalizedTransitions.Requests = append( + finalizedTransitions.Requests, + transition, ) + case *protobufs.TokenRequest_Merge: + success, err := a.handleMerge(currentFrameNumber, lockMap, t.Merge) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - peerId, err := peer.IDFromPublicKey(pk) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - altAddr, err := poseidon.HashBytes([]byte(peerId)) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), + err, "apply transitions", ) } @@ -605,118 +147,13 @@ func (a *TokenApplication) ApplyTransitions( ) break req } - - owner := &protobufs.AccountRef{} - deleted := []*protobufs.TokenOutput{} - for _, c := range t.Merge.Coins { - coin, err := a.CoinStore.GetCoinByAddress(c.Address) - if err != nil && !skipFailures { - if !skipFailures { - return nil, nil, nil, errors.Wrap(err, "apply transitions") - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - addr.FillBytes(make([]byte, 32)), - ) && !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - altAddr.FillBytes(make([]byte, 32)), - ) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid owner"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - newTotal.Add(newTotal, new(big.Int).SetBytes(coin.Amount)) - for i := range coin.Intersection { - newIntersection[i] |= coin.Intersection[i] - } - owner = coin.Owner - deleted = append(deleted, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_DeletedCoin{ - DeletedCoin: c, - }, - }) - } - newCoin.Amount = newTotal.FillBytes(make([]byte, 32)) - newCoin.Intersection = newIntersection - newCoin.Owner = owner - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: newCoin, - }, - }) - outputs.Outputs = append(outputs.Outputs, deleted...) + outputs.Outputs = append(outputs.Outputs, success...) finalizedTransitions.Requests = append( finalizedTransitions.Requests, transition, ) case *protobufs.TokenRequest_Split: - newCoins := []*protobufs.Coin{} - newAmounts := []*big.Int{} - payload := []byte{} - if t.Split.Signature.PublicKey == nil || - t.Split.Signature.Signature == nil || - t.Split.OfCoin == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - coin, err := a.CoinStore.GetCoinByAddress(t.Split.OfCoin.Address) - if err != nil && !skipFailures { - if !skipFailures { - return nil, nil, nil, errors.Wrap(err, "apply transitions") - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - payload = append(payload, []byte("split")...) - payload = append(payload, t.Split.OfCoin.Address...) - for _, a := range t.Split.Amounts { - payload = append(payload, a...) - } - - if err := t.Split.Signature.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - err, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - addr, err := poseidon.HashBytes(t.Split.Signature.PublicKey.KeyValue) + success, err := a.handleSplit(currentFrameNumber, lockMap, t.Split) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( @@ -730,155 +167,13 @@ func (a *TokenApplication) ApplyTransitions( ) break req } - - pk, err := pcrypto.UnmarshalEd448PublicKey( - t.Split.Signature.PublicKey.KeyValue, - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - peerId, err := peer.IDFromPublicKey(pk) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - altAddr, err := poseidon.HashBytes([]byte(peerId)) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - addr.FillBytes(make([]byte, 32)), - ) && !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - altAddr.FillBytes(make([]byte, 32)), - ) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid owner"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - amounts := t.Split.Amounts - total := new(big.Int) - for _, amount := range amounts { - amountBI := new(big.Int).SetBytes(amount) - newAmounts = append(newAmounts, amountBI) - total.Add(total, amountBI) - newCoins = append(newCoins, &protobufs.Coin{ - Amount: amountBI.FillBytes(make([]byte, 32)), - Owner: coin.Owner, - Intersection: coin.Intersection, - }) - } - if new(big.Int).SetBytes(coin.Amount).Cmp(total) != 0 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid split"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - for _, c := range newCoins { - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: c, - }, - }) - } - - outputs.Outputs = append( - outputs.Outputs, - &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_DeletedCoin{ - DeletedCoin: t.Split.OfCoin, - }, - }, - ) + outputs.Outputs = append(outputs.Outputs, success...) finalizedTransitions.Requests = append( finalizedTransitions.Requests, transition, ) case *protobufs.TokenRequest_Transfer: - payload := []byte("transfer") - coin, err := a.CoinStore.GetCoinByAddress(t.Transfer.OfCoin.Address) - if err != nil && !skipFailures { - if !skipFailures { - return nil, nil, nil, errors.Wrap(err, "apply transitions") - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - payload = append(payload, t.Transfer.OfCoin.Address...) - payload = append( - payload, - t.Transfer.ToAccount.GetImplicitAccount().Address..., - ) - - if err := t.Transfer.Signature.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - err, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - addr, err := poseidon.HashBytes(t.Transfer.Signature.PublicKey.KeyValue) + success, err := a.handleTransfer(currentFrameNumber, lockMap, t.Transfer) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( @@ -892,174 +187,17 @@ func (a *TokenApplication) ApplyTransitions( ) break req } - - pk, err := pcrypto.UnmarshalEd448PublicKey( - t.Transfer.Signature.PublicKey.KeyValue, - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - peerId, err := peer.IDFromPublicKey(pk) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - altAddr, err := poseidon.HashBytes([]byte(peerId)) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - addr.FillBytes(make([]byte, 32)), - ) && !bytes.Equal( - coin.Owner.GetImplicitAccount().Address, - altAddr.FillBytes(make([]byte, 32)), - ) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid owner"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - newIntersection := coin.Intersection - for i, b := range p2p.GetBloomFilter( - addr.FillBytes(make([]byte, 32)), - 1024, - 3, - ) { - newIntersection[i] |= b - } - - outputs.Outputs = append( - outputs.Outputs, - &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: &protobufs.Coin{ - Amount: coin.Amount, - Intersection: newIntersection, - Owner: t.Transfer.ToAccount, - }, - }, - }, - &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_DeletedCoin{ - DeletedCoin: t.Transfer.OfCoin, - }, - }, - ) + outputs.Outputs = append(outputs.Outputs, success...) finalizedTransitions.Requests = append( finalizedTransitions.Requests, transition, ) case *protobufs.TokenRequest_Mint: - if t.Mint.Signature == nil || t.Mint.Signature.PublicKey == nil || - t.Mint.Signature.Signature == nil || - t.Mint.Proofs == nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - ErrInvalidStateTransition, - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - payload := []byte("mint") - for _, p := range t.Mint.Proofs { - payload = append(payload, p...) - } - if err := t.Mint.Signature.Verify(payload); err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - pk, err := pcrypto.UnmarshalEd448PublicKey( - t.Mint.Signature.PublicKey.KeyValue, - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - peerId, err := peer.IDFromPublicKey(pk) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - addr, err := poseidon.HashBytes(t.Mint.Signature.PublicKey.KeyValue) + success, err := a.handleMint(currentFrameNumber, lockMap, t.Mint) if err != nil { if !skipFailures { return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), + err, "apply transitions", ) } @@ -1069,396 +207,7 @@ func (a *TokenApplication) ApplyTransitions( ) break req } - - if len(t.Mint.Proofs) == 3 && - bytes.Equal( - t.Mint.Proofs[0], - []byte("pre-dusk"), - ) && (!bytes.Equal(t.Mint.Proofs[1], make([]byte, 32)) || - currentFrameNumber < 604800) { - delete := []*protobufs.TokenOutput{} - if !bytes.Equal(t.Mint.Proofs[1], make([]byte, 32)) { - pre, err := a.CoinStore.GetPreCoinProofByAddress(t.Mint.Proofs[1]) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - delete = append(delete, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_DeletedProof{ - DeletedProof: pre, - }, - }) - } - - data := t.Mint.Proofs[2] - if len(data) < 28 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - increment := binary.BigEndian.Uint32(data[:4]) - parallelism := binary.BigEndian.Uint32(data[8:12]) - inputLen := binary.BigEndian.Uint64(data[12:20]) - - if len(delete) != 0 { - if delete[0].GetDeletedProof().Difficulty-1 != increment { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - } - - if uint64(len(data[20:])) < inputLen+8 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - input := make([]byte, inputLen) - copy(input[:], data[20:20+inputLen]) - - outputLen := binary.BigEndian.Uint64(data[20+inputLen : 20+inputLen+8]) - - if uint64(len(data[20+inputLen+8:])) < outputLen { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - output := make([]byte, outputLen) - copy(output[:], data[20+inputLen+8:]) - dataProver := crypto.NewKZGInclusionProver(a.Logger) - wesoProver := crypto.NewWesolowskiFrameProver(a.Logger) - index := binary.BigEndian.Uint32(output[:4]) - indexProof := output[4:520] - kzgCommitment := output[520:594] - kzgProof := output[594:668] - ip := sha3.Sum512(indexProof) - - v, err := dataProver.VerifyRaw( - ip[:], - kzgCommitment, - int(index), - kzgProof, - nearestApplicablePowerOfTwo(uint64(parallelism)), - ) - if err != nil { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !v { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - wp := []byte{} - wp = append(wp, peerId...) - wp = append(wp, input...) - v = wesoProver.VerifyPreDuskChallengeProof( - wp, - increment, - index, - indexProof, - ) - if !v { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - pomwBasis := big.NewInt(1200000) - - reward := new(big.Int).Mul(pomwBasis, big.NewInt(int64(parallelism))) - if len(delete) != 0 { - reward.Add( - reward, - new(big.Int).SetBytes(delete[0].GetDeletedProof().Amount), - ) - } - - if increment != 0 { - add := &protobufs.PreCoinProof{ - Amount: reward.FillBytes(make([]byte, 32)), - Index: index, - IndexProof: indexProof, - Commitment: kzgCommitment, - Proof: append(append([]byte{}, kzgProof...), indexProof...), - Parallelism: parallelism, - Difficulty: increment, - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - } - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Proof{ - Proof: add, - }, - }) - } else { - add := &protobufs.Coin{ - Amount: reward.FillBytes(make([]byte, 32)), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - } - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: add, - }, - }) - } - outputs.Outputs = append(outputs.Outputs, delete...) - } else { - ring := -1 - addrBytes := addr.FillBytes(make([]byte, 32)) - for i, t := range a.Tries { - n := t.FindNearest(addrBytes) - if n != nil && bytes.Equal(n.External.Key, addrBytes) { - ring = i - } - } - if ring == -1 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - for _, p := range t.Mint.Proofs { - if len(p) < 516+len(peerId)+8+32 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - if !bytes.Equal(p[516:len(peerId)], []byte(peerId)) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - wesoProver := crypto.NewWesolowskiFrameProver(a.Logger) - - frameNumber := binary.BigEndian.Uint64( - p[516+len(peerId) : 516+len(peerId)+8], - ) - if frameNumber > currentFrameNumber { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - frames, proofs, err := a.CoinStore.GetPreCoinProofsForOwner( - addr.FillBytes(make([]byte, 32)), - ) - if err == nil { - none := true - for _, f := range frames { - if f == frameNumber { - none = false - break - } - } - - if !none { - for _, pr := range proofs { - if bytes.Equal(pr.Proof, p) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - } - } - } - - if !wesoProver.VerifyChallengeProof(p[516:], a.Difficulty, p[:516]) { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - scale := len(p2p.GetOnesIndices(p[516+len(peerId)+8 : 32])) - if scale == 0 { - if !skipFailures { - return nil, nil, nil, errors.Wrap( - errors.New("invalid data"), - "apply transitions", - ) - } - failedTransitions.Requests = append( - failedTransitions.Requests, - transition, - ) - break req - } - - ringFactor := big.NewInt(2) - ringFactor.Exp(ringFactor, big.NewInt(int64(ring)), nil) - storage := big.NewInt(int64(1024 / (256 / scale))) - unitFactor := big.NewInt(8000000000) - storage.Mul(storage, unitFactor) - storage.Quo(storage, ringFactor) - - outputs.Outputs = append(outputs.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Proof{ - Proof: &protobufs.PreCoinProof{ - Amount: storage.FillBytes(make([]byte, 32)), - Proof: p, - Difficulty: a.Difficulty, - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - }, - }, - }, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: &protobufs.Coin{ - Amount: storage.FillBytes(make([]byte, 32)), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - ImplicitType: 0, - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - }, - }, - }) - } - } + outputs.Outputs = append(outputs.Outputs, success...) finalizedTransitions.Requests = append( finalizedTransitions.Requests, transition, @@ -1471,27 +220,9 @@ func (a *TokenApplication) ApplyTransitions( return a, finalizedTransitions, failedTransitions, nil } -func nearestApplicablePowerOfTwo(number uint64) uint64 { - power := uint64(128) - if number > 2048 { - power = 65536 - } else if number > 1024 { - power = 2048 - } else if number > 128 { - power = 1024 - } - return power -} - func (a *TokenApplication) MaterializeStateFromApplication() ( *protobufs.TokenOutputs, error, ) { - var err error - state := &protobufs.TokenOutputs{} - if err != nil { - return nil, errors.Wrap(err, "materialize state from application") - } - - return state, nil + return a.TokenOutputs, nil } diff --git a/node/execution/intrinsics/token/application/token_handle_announce.go b/node/execution/intrinsics/token/application/token_handle_announce.go new file mode 100644 index 0000000..e3acfa9 --- /dev/null +++ b/node/execution/intrinsics/token/application/token_handle_announce.go @@ -0,0 +1,46 @@ +package application + +import ( + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *TokenApplication) handleAnnounce( + currentFrameNumber uint64, + lockMap map[string]struct{}, + t *protobufs.AnnounceProverRequest, +) ( + []*protobufs.TokenOutput, + error, +) { + var primary *protobufs.Ed448Signature + payload := []byte{} + + if t == nil || t.PublicKeySignaturesEd448 == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") + } + for i, p := range t.PublicKeySignaturesEd448 { + if p.PublicKey == nil || p.Signature == nil || + p.PublicKey.KeyValue == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") + } + if i == 0 { + primary = p + } else { + payload = append(payload, p.PublicKey.KeyValue...) + if err := p.Verify(primary.PublicKey.KeyValue); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") + } + } + } + if primary == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") + } + if err := primary.Verify(payload); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle announce") + } + + outputs := []*protobufs.TokenOutput{} + + return outputs, nil +} diff --git a/node/execution/intrinsics/token/application/token_handle_merge.go b/node/execution/intrinsics/token/application/token_handle_merge.go new file mode 100644 index 0000000..c4db1bd --- /dev/null +++ b/node/execution/intrinsics/token/application/token_handle_merge.go @@ -0,0 +1,120 @@ +package application + +import ( + "bytes" + "math/big" + + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *TokenApplication) handleMerge( + currentFrameNumber uint64, + lockMap map[string]struct{}, + t *protobufs.MergeCoinRequest, +) ([]*protobufs.TokenOutput, error) { + newCoin := &protobufs.Coin{} + newTotal := new(big.Int) + newIntersection := make([]byte, 1024) + payload := []byte("merge") + if t == nil || t.Coins == nil || t.Signature == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + addresses := [][]byte{} + for _, c := range t.Coins { + if c.Address == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + if _, touched := lockMap[string(c.Address)]; touched { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + for _, addr := range addresses { + if bytes.Equal(addr, c.Address) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + } + + addresses = append(addresses, c.Address) + payload = append(payload, c.Address...) + } + if t.Signature.PublicKey == nil || + t.Signature.Signature == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + if err := t.Signature.Verify(payload); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + owner := &protobufs.AccountRef{} + deleted := []*protobufs.TokenOutput{} + for _, c := range t.Coins { + coin, err := a.CoinStore.GetCoinByAddress(nil, c.Address) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + if !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + addr.FillBytes(make([]byte, 32)), + ) && !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + altAddr.FillBytes(make([]byte, 32)), + ) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle merge") + } + + newTotal.Add(newTotal, new(big.Int).SetBytes(coin.Amount)) + for i := range coin.Intersection { + newIntersection[i] |= coin.Intersection[i] + } + owner = coin.Owner + deleted = append(deleted, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_DeletedCoin{ + DeletedCoin: c, + }, + }) + } + newCoin.Amount = newTotal.FillBytes(make([]byte, 32)) + newCoin.Intersection = newIntersection + newCoin.Owner = owner + outputs := []*protobufs.TokenOutput{ + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: newCoin, + }, + }, + } + outputs = append(outputs, deleted...) + + for _, c := range t.Coins { + lockMap[string(c.Address)] = struct{}{} + } + + return outputs, nil +} diff --git a/node/execution/intrinsics/token/application/token_handle_mint.go b/node/execution/intrinsics/token/application/token_handle_mint.go new file mode 100644 index 0000000..bb09b58 --- /dev/null +++ b/node/execution/intrinsics/token/application/token_handle_mint.go @@ -0,0 +1,231 @@ +package application + +import ( + "bytes" + "encoding/binary" + "math/big" + + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +func (a *TokenApplication) handleMint( + currentFrameNumber uint64, + lockMap map[string]struct{}, + t *protobufs.MintCoinRequest, +) ([]*protobufs.TokenOutput, error) { + if t == nil || t.Proofs == nil || t.Signature == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + payload := []byte("mint") + for _, p := range t.Proofs { + payload = append(payload, p...) + } + if err := t.Signature.Verify(payload); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + addr, err := poseidon.HashBytes( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + // todo: set termination frame for this: + if len(t.Proofs) == 1 && a.Tries[0].Contains( + addr.FillBytes(make([]byte, 32)), + ) && bytes.Equal(t.Signature.PublicKey.KeyValue, a.Beacon) { + if len(t.Proofs[0]) != 64 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + if _, touched := lockMap[string(t.Proofs[0][32:])]; touched { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + _, pr, err := a.CoinStore.GetPreCoinProofsForOwner(t.Proofs[0][32:]) + if err != nil && !errors.Is(err, store.ErrNotFound) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + for _, p := range pr { + if p.IndexProof == nil && bytes.Equal(p.Amount, t.Proofs[0][:32]) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + } + + lockMap[string(t.Proofs[0][32:])] = struct{}{} + + outputs := []*protobufs.TokenOutput{ + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Proof{ + Proof: &protobufs.PreCoinProof{ + Amount: t.Proofs[0][:32], + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: t.Proofs[0][32:], + }, + }, + }, + Proof: t.Signature.Signature, + }, + }, + }, + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: t.Proofs[0][:32], + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: t.Proofs[0][32:], + }, + }, + }, + }, + }, + }, + } + return outputs, nil + } else if len(t.Proofs) != 3 && currentFrameNumber > 77000 { + if _, touched := lockMap[string(t.Signature.PublicKey.KeyValue)]; touched { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + ring := -1 + addrBytes := addr.FillBytes(make([]byte, 32)) + for i, t := range a.Tries { + n := t.FindNearest(addrBytes) + if n != nil && bytes.Equal(n.External.Key, addrBytes) { + ring = i + } + } + if ring == -1 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + outputs := []*protobufs.TokenOutput{} + for _, p := range t.Proofs { + if len(p) < 516+len(peerId)+8+32 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + if !bytes.Equal(p[516:len(peerId)], []byte(peerId)) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + wesoProver := crypto.NewWesolowskiFrameProver(a.Logger) + + frameNumber := binary.BigEndian.Uint64( + p[516+len(peerId) : 516+len(peerId)+8], + ) + if frameNumber > currentFrameNumber { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + frames, proofs, err := a.CoinStore.GetPreCoinProofsForOwner( + altAddr.FillBytes(make([]byte, 32)), + ) + if err == nil { + none := true + for _, f := range frames { + if f == frameNumber { + none = false + break + } + } + + if !none { + for _, pr := range proofs { + if bytes.Equal(pr.Proof, p) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + } + } + } + + if !wesoProver.VerifyChallengeProof(p[516:], a.Difficulty, p[:516]) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + scale := len(p2p.GetOnesIndices(p[516+len(peerId)+8 : 32])) + if scale == 0 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") + } + + ringFactor := big.NewInt(2) + ringFactor.Exp(ringFactor, big.NewInt(int64(ring)), nil) + storage := big.NewInt(int64(1024 / (256 / scale))) + unitFactor := big.NewInt(8000000000) + storage.Mul(storage, unitFactor) + storage.Quo(storage, ringFactor) + + outputs = append( + outputs, + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Proof{ + Proof: &protobufs.PreCoinProof{ + Amount: storage.FillBytes(make([]byte, 32)), + Proof: p, + Difficulty: a.Difficulty, + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: addr.FillBytes(make([]byte, 32)), + }, + }, + }, + }, + }, + }, + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: storage.FillBytes(make([]byte, 32)), + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + ImplicitType: 0, + Address: addr.FillBytes(make([]byte, 32)), + }, + }, + }, + }, + }, + }, + ) + } + lockMap[string(t.Signature.PublicKey.KeyValue)] = struct{}{} + return outputs, nil + } + + return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint") +} diff --git a/node/execution/intrinsics/token/application/token_handle_split.go b/node/execution/intrinsics/token/application/token_handle_split.go new file mode 100644 index 0000000..791677d --- /dev/null +++ b/node/execution/intrinsics/token/application/token_handle_split.go @@ -0,0 +1,126 @@ +package application + +import ( + "bytes" + "math/big" + + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *TokenApplication) handleSplit( + currentFrameNumber uint64, + lockMap map[string]struct{}, + t *protobufs.SplitCoinRequest, +) ([]*protobufs.TokenOutput, error) { + newCoins := []*protobufs.Coin{} + newAmounts := []*big.Int{} + payload := []byte{} + if t.Signature == nil || t.OfCoin == nil || t.OfCoin.Address == nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + coin, err := a.CoinStore.GetCoinByAddress(nil, t.OfCoin.Address) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + if _, touched := lockMap[string(t.OfCoin.Address)]; touched { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + payload = append(payload, []byte("split")...) + payload = append(payload, t.OfCoin.Address...) + + if len(t.Amounts) > 100 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + for _, a := range t.Amounts { + if len(a) > 32 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + payload = append(payload, a...) + } + + if err := t.Signature.Verify(payload); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + if !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + addr.FillBytes(make([]byte, 32)), + ) && !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + altAddr.FillBytes(make([]byte, 32)), + ) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + original := new(big.Int).SetBytes(coin.Amount) + amounts := t.Amounts + total := new(big.Int) + for _, amount := range amounts { + amountBI := new(big.Int).SetBytes(amount) + if amountBI.Cmp(original) >= 0 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + newAmounts = append(newAmounts, amountBI) + total.Add(total, amountBI) + newCoins = append(newCoins, &protobufs.Coin{ + Amount: amountBI.FillBytes(make([]byte, 32)), + Owner: coin.Owner, + Intersection: coin.Intersection, + }) + } + if original.Cmp(total) != 0 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle split") + } + + outputs := []*protobufs.TokenOutput{} + for _, c := range newCoins { + outputs = append(outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: c, + }, + }) + } + + outputs = append( + outputs, + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_DeletedCoin{ + DeletedCoin: t.OfCoin, + }, + }, + ) + + lockMap[string(t.OfCoin.Address)] = struct{}{} + + return outputs, nil +} diff --git a/node/execution/intrinsics/token/application/token_handle_transfer.go b/node/execution/intrinsics/token/application/token_handle_transfer.go new file mode 100644 index 0000000..52a4150 --- /dev/null +++ b/node/execution/intrinsics/token/application/token_handle_transfer.go @@ -0,0 +1,107 @@ +package application + +import ( + "bytes" + + "github.com/iden3/go-iden3-crypto/poseidon" + pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *TokenApplication) handleTransfer( + currentFrameNumber uint64, + lockMap map[string]struct{}, + t *protobufs.TransferCoinRequest, +) ([]*protobufs.TokenOutput, error) { + payload := []byte("transfer") + if t == nil || t.Signature == nil || t.OfCoin == nil || + t.OfCoin.Address == nil || len(t.OfCoin.Address) != 32 || + t.ToAccount == nil || t.ToAccount.GetImplicitAccount() == nil || + t.ToAccount.GetImplicitAccount().Address == nil || + len(t.ToAccount.GetImplicitAccount().Address) != 32 { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + if _, touched := lockMap[string(t.OfCoin.Address)]; touched { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + coin, err := a.CoinStore.GetCoinByAddress(nil, t.OfCoin.Address) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + payload = append(payload, t.OfCoin.Address...) + payload = append( + payload, + t.ToAccount.GetImplicitAccount().Address..., + ) + + if err := t.Signature.Verify(payload); err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + addr, err := poseidon.HashBytes(t.Signature.PublicKey.KeyValue) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + pk, err := pcrypto.UnmarshalEd448PublicKey( + t.Signature.PublicKey.KeyValue, + ) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + peerId, err := peer.IDFromPublicKey(pk) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + altAddr, err := poseidon.HashBytes([]byte(peerId)) + if err != nil { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + if !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + addr.FillBytes(make([]byte, 32)), + ) && !bytes.Equal( + coin.Owner.GetImplicitAccount().Address, + altAddr.FillBytes(make([]byte, 32)), + ) { + return nil, errors.Wrap(ErrInvalidStateTransition, "handle transfer") + } + + newIntersection := coin.Intersection + for i, b := range p2p.GetBloomFilter( + addr.FillBytes(make([]byte, 32)), + 1024, + 3, + ) { + newIntersection[i] |= b + } + + outputs := []*protobufs.TokenOutput{ + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: coin.Amount, + Intersection: newIntersection, + Owner: t.ToAccount, + }, + }, + }, + &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_DeletedCoin{ + DeletedCoin: t.OfCoin, + }, + }, + } + + lockMap[string(t.OfCoin.Address)] = struct{}{} + return outputs, nil +} diff --git a/node/execution/intrinsics/token/token_addressing.go b/node/execution/intrinsics/token/token_addressing.go new file mode 100644 index 0000000..f5c8dd7 --- /dev/null +++ b/node/execution/intrinsics/token/token_addressing.go @@ -0,0 +1,54 @@ +package token + +import ( + "encoding/binary" + + "github.com/iden3/go-iden3-crypto/poseidon" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func GetAddressOfCoin( + coin *protobufs.Coin, + frameNumber uint64, + seqno uint64, +) ([]byte, error) { + eval := []byte{} + eval = append(eval, application.TOKEN_ADDRESS...) + eval = binary.BigEndian.AppendUint64(eval, frameNumber) + if frameNumber != 0 { + eval = binary.BigEndian.AppendUint64(eval, seqno) + } + eval = append(eval, coin.Amount...) + eval = append(eval, coin.Intersection...) + eval = binary.BigEndian.AppendUint32(eval, 0) + eval = append(eval, coin.Owner.GetImplicitAccount().Address...) + addressBI, err := poseidon.HashBytes(eval) + if err != nil { + return nil, err + } + + return addressBI.FillBytes(make([]byte, 32)), nil +} + +func GetAddressOfPreCoinProof( + proof *protobufs.PreCoinProof, +) ([]byte, error) { + eval := []byte{} + eval = append(eval, application.TOKEN_ADDRESS...) + eval = append(eval, proof.Amount...) + eval = binary.BigEndian.AppendUint32(eval, proof.Index) + eval = append(eval, proof.IndexProof...) + eval = append(eval, proof.Commitment...) + eval = append(eval, proof.Proof...) + eval = binary.BigEndian.AppendUint32(eval, proof.Parallelism) + eval = binary.BigEndian.AppendUint32(eval, proof.Difficulty) + eval = binary.BigEndian.AppendUint32(eval, 0) + eval = append(eval, proof.Owner.GetImplicitAccount().Address...) + addressBI, err := poseidon.HashBytes(eval) + if err != nil { + return nil, err + } + + return addressBI.FillBytes(make([]byte, 32)), nil +} diff --git a/node/execution/intrinsics/token/token_execution_engine.go b/node/execution/intrinsics/token/token_execution_engine.go index bdbeca7..8ff7b77 100644 --- a/node/execution/intrinsics/token/token_execution_engine.go +++ b/node/execution/intrinsics/token/token_execution_engine.go @@ -3,27 +3,18 @@ package token import ( "bytes" "crypto" - _ "embed" - "encoding/binary" "encoding/hex" - "encoding/json" - "fmt" - "strconv" "strings" "sync" gotime "time" "github.com/iden3/go-iden3-crypto/poseidon" pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/mr-tron/base58" "github.com/pkg/errors" - "github.com/shopspring/decimal" "go.uber.org/zap" - "golang.org/x/crypto/sha3" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" - "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus/data" "source.quilibrium.com/quilibrium/monorepo/node/consensus/time" @@ -54,8 +45,6 @@ type TokenExecutionEngine struct { peerChannels map[string]*p2p.PublicP2PChannel activeClockFrame *protobufs.ClockFrame alreadyPublishedShare bool - seenMessageMap map[string]bool - seenMessageMx sync.Mutex intrinsicFilter []byte frameProver qcrypto.FrameProver peerSeniority map[string]uint64 @@ -63,7 +52,7 @@ type TokenExecutionEngine struct { func NewTokenExecutionEngine( logger *zap.Logger, - engineConfig *config.EngineConfig, + cfg *config.Config, keyManager keys.KeyManager, pubSub p2p.PubSub, frameProver qcrypto.FrameProver, @@ -80,7 +69,7 @@ func NewTokenExecutionEngine( panic(errors.New("logger is nil")) } - seed, err := hex.DecodeString(engineConfig.GenesisSeed) + seed, err := hex.DecodeString(cfg.Engine.GenesisSeed) if err != nil { panic(err) } @@ -97,33 +86,87 @@ func NewTokenExecutionEngine( if err != nil && errors.Is(err, store.ErrNotFound) { origin, inclusionProof, proverKeys, peerSeniority = CreateGenesisState( logger, - engineConfig, + cfg.Engine, nil, inclusionProver, coinStore, + uint(cfg.P2P.Network), ) + if err := coinStore.SetMigrationVersion( + config.GetGenesis().GenesisSeedHex, + ); err != nil { + panic(err) + } genesisCreated = true } else if err != nil { panic(err) + } else { + err := coinStore.Migrate( + intrinsicFilter, + config.GetGenesis().GenesisSeedHex, + ) + if err != nil { + panic(err) + } + _, err = clockStore.GetEarliestDataClockFrame(intrinsicFilter) + if err != nil && errors.Is(err, store.ErrNotFound) { + origin, inclusionProof, proverKeys, peerSeniority = CreateGenesisState( + logger, + cfg.Engine, + nil, + inclusionProver, + coinStore, + uint(cfg.P2P.Network), + ) + genesisCreated = true + } + } + + e := &TokenExecutionEngine{ + logger: logger, + engineConfig: cfg.Engine, + keyManager: keyManager, + clockStore: clockStore, + coinStore: coinStore, + keyStore: keyStore, + pubSub: pubSub, + inclusionProver: inclusionProver, + frameProver: frameProver, + participantMx: sync.Mutex{}, + peerChannels: map[string]*p2p.PublicP2PChannel{}, + alreadyPublishedShare: false, + intrinsicFilter: intrinsicFilter, + peerSeniority: peerSeniority, } dataTimeReel := time.NewDataTimeReel( intrinsicFilter, logger, clockStore, - engineConfig, + cfg.Engine, frameProver, + func(txn store.Transaction, frame *protobufs.ClockFrame) error { + if err := e.VerifyExecution(frame); err != nil { + return err + } + if err := e.ProcessFrame(txn, frame); err != nil { + return err + } + + return nil + }, origin, inclusionProof, proverKeys, ) - clock := data.NewDataClockConsensusEngine( - engineConfig, + e.clock = data.NewDataClockConsensusEngine( + cfg, logger, keyManager, clockStore, coinStore, + dataProofStore, keyStore, pubSub, frameProver, @@ -137,26 +180,6 @@ func NewTokenExecutionEngine( peerSeniority, ) - e := &TokenExecutionEngine{ - logger: logger, - clock: clock, - engineConfig: engineConfig, - keyManager: keyManager, - clockStore: clockStore, - coinStore: coinStore, - keyStore: keyStore, - pubSub: pubSub, - inclusionProver: inclusionProver, - frameProver: frameProver, - participantMx: sync.Mutex{}, - peerChannels: map[string]*p2p.PublicP2PChannel{}, - alreadyPublishedShare: false, - seenMessageMx: sync.Mutex{}, - seenMessageMap: map[string]bool{}, - intrinsicFilter: intrinsicFilter, - peerSeniority: peerSeniority, - } - peerId := e.pubSub.GetPeerID() addr, err := poseidon.HashBytes(peerId) if err != nil { @@ -166,7 +189,7 @@ func NewTokenExecutionEngine( addrBytes := addr.FillBytes(make([]byte, 32)) e.peerIdHash = addrBytes provingKey, _, publicKeyBytes, provingKeyAddress := e.clock.GetProvingKey( - engineConfig, + cfg.Engine, ) e.provingKey = provingKey e.proverPublicKey = publicKeyBytes @@ -246,44 +269,6 @@ func NewTokenExecutionEngine( ) } - inc, _, _, err := dataProofStore.GetLatestDataTimeProof( - e.pubSub.GetPeerID(), - ) - _, parallelism, input, output, err := dataProofStore.GetDataTimeProof( - e.pubSub.GetPeerID(), - inc, - ) - if err == nil { - proof := []byte{} - proof = binary.BigEndian.AppendUint32(proof, inc) - proof = binary.BigEndian.AppendUint32(proof, parallelism) - proof = binary.BigEndian.AppendUint64(proof, uint64(len(input))) - proof = append(proof, input...) - proof = binary.BigEndian.AppendUint64(proof, uint64(len(output))) - proof = append(proof, output...) - announce.Announce.InitialProof = &protobufs.MintCoinRequest{} - announce.Announce.InitialProof.Proofs = [][]byte{ - []byte("pre-dusk"), - make([]byte, 32), - proof, - } - payload := []byte("mint") - for _, p := range announce.Announce.InitialProof.Proofs { - payload = append(payload, p...) - } - sig, err := e.pubSub.SignMessage(payload) - if err != nil { - panic(err) - } - - announce.Announce.InitialProof.Signature = &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - Signature: sig, - } - } - req := &protobufs.TokenRequest{ Request: announce, } @@ -294,95 +279,63 @@ func NewTokenExecutionEngine( }() } else { f, _, err := e.clockStore.GetLatestDataClockFrame(e.intrinsicFilter) - if err == nil { - msg := []byte("resume") - msg = binary.BigEndian.AppendUint64(msg, f.FrameNumber) - msg = append(msg, e.intrinsicFilter...) - sig, err := e.pubSub.SignMessage(msg) + fn, err := coinStore.GetLatestFrameProcessed() + if err != nil { + panic(err) + } + + if f.FrameNumber != fn && fn == 0 { + txn, err := coinStore.NewTransaction() if err != nil { panic(err) } - // need to wait for peering - gotime.Sleep(30 * gotime.Second) - e.publishMessage(e.intrinsicFilter, &protobufs.AnnounceProverResume{ - Filter: e.intrinsicFilter, - FrameNumber: f.FrameNumber, - PublicKeySignatureEd448: &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - Signature: sig, - }, - }) - } - } - - inc, _, _, err := dataProofStore.GetLatestDataTimeProof(pubSub.GetPeerID()) - if err != nil { - go func() { - addrBI, err := poseidon.HashBytes(pubSub.GetPeerID()) + err = coinStore.SetLatestFrameProcessed(txn, f.FrameNumber) if err != nil { + txn.Abort() panic(err) } - addr := addrBI.FillBytes(make([]byte, 32)) - - for { - _, proofs, err := coinStore.GetPreCoinProofsForOwner(addr) - if err == nil { - for _, proof := range proofs { - if proof.IndexProof != nil && len(proof.IndexProof) != 0 { - if proof.Difficulty < inc { - _, par, input, output, err := dataProofStore.GetDataTimeProof( - pubSub.GetPeerID(), - proof.Difficulty-1, - ) - if err == nil { - p := []byte{} - p = binary.BigEndian.AppendUint32(p, proof.Difficulty-1) - p = binary.BigEndian.AppendUint32(p, par) - p = binary.BigEndian.AppendUint64( - p, - uint64(len(input)), - ) - p = append(p, input...) - p = binary.BigEndian.AppendUint64(p, uint64(len(output))) - p = append(p, output...) - proofs := [][]byte{ - []byte("pre-dusk"), - make([]byte, 32), - p, - } - payload := []byte("mint") - for _, i := range proofs { - payload = append(payload, i...) - } - sig, err := e.pubSub.SignMessage(payload) - if err != nil { - panic(err) - } - e.publishMessage(e.intrinsicFilter, &protobufs.TokenRequest{ - Request: &protobufs.TokenRequest_Mint{ - Mint: &protobufs.MintCoinRequest{ - Proofs: proofs, - Signature: &protobufs.Ed448Signature{ - PublicKey: &protobufs.Ed448PublicKey{ - KeyValue: e.pubSub.GetPublicKey(), - }, - Signature: sig, - }, - }, - }, - }) - } - } - } - } - } - gotime.Sleep(10 * gotime.Second) + if err = txn.Commit(); err != nil { + panic(err) } - }() + } else if f.FrameNumber-fn == 1 && f.FrameNumber > fn { + txn, err := coinStore.NewTransaction() + if err != nil { + panic(err) + } + e.logger.Info( + "replaying last data frame", + zap.Uint64("frame_number", f.FrameNumber), + ) + e.ProcessFrame(txn, f) + if err = txn.Commit(); err != nil { + panic(err) + } + } + + if err == nil { + // msg := []byte("resume") + // msg = binary.BigEndian.AppendUint64(msg, f.FrameNumber) + // msg = append(msg, e.intrinsicFilter...) + // sig, err := e.pubSub.SignMessage(msg) + // if err != nil { + // panic(err) + // } + + // // need to wait for peering + // gotime.Sleep(30 * gotime.Second) + // e.publishMessage(e.intrinsicFilter, &protobufs.AnnounceProverResume{ + // Filter: e.intrinsicFilter, + // FrameNumber: f.FrameNumber, + // PublicKeySignatureEd448: &protobufs.Ed448Signature{ + // PublicKey: &protobufs.Ed448PublicKey{ + // KeyValue: e.pubSub.GetPublicKey(), + // }, + // Signature: sig, + // }, + // }) + } } return e @@ -407,523 +360,6 @@ func ( } } -var BridgeAddress = "1ac3290d57e064bdb5a57e874b59290226a9f9730d69f1d963600883789d6ee2" - -type BridgedPeerJson struct { - Amount string `json:"amount"` - Identifier string `json:"identifier"` - Variant string `json:"variant"` -} - -type FirstRetroJson struct { - PeerId string `json:"peerId"` - Reward string `json:"reward"` -} - -type SecondRetroJson struct { - PeerId string `json:"peerId"` - Reward string `json:"reward"` - JanPresence bool `json:"janPresence"` - FebPresence bool `json:"febPresence"` - MarPresence bool `json:"marPresence"` - AprPresence bool `json:"aprPresence"` - MayPresence bool `json:"mayPresence"` -} - -type ThirdRetroJson struct { - PeerId string `json:"peerId"` - Reward string `json:"reward"` -} - -type FourthRetroJson struct { - PeerId string `json:"peerId"` - Reward string `json:"reward"` -} - -//go:embed bridged.json -var bridgedPeersJsonBinary []byte - -//go:embed ceremony_vouchers.json -var ceremonyVouchersJsonBinary []byte - -//go:embed first_retro.json -var firstRetroJsonBinary []byte - -//go:embed second_retro.json -var secondRetroJsonBinary []byte - -//go:embed third_retro.json -var thirdRetroJsonBinary []byte - -//go:embed fourth_retro.json -var fourthRetroJsonBinary []byte - -// Creates a genesis state for the intrinsic -func CreateGenesisState( - logger *zap.Logger, - engineConfig *config.EngineConfig, - testProverKeys [][]byte, - inclusionProver qcrypto.InclusionProver, - coinStore store.CoinStore, -) ( - []byte, - *qcrypto.InclusionAggregateProof, - [][]byte, - map[string]uint64, -) { - genesis := config.GetGenesis() - if genesis == nil { - panic("genesis is nil") - } - - seed, err := hex.DecodeString(engineConfig.GenesisSeed) - if err != nil { - panic(err) - } - - logger.Info("creating genesis frame from message:") - for i, l := range strings.Split(string(seed), "|") { - if i == 0 { - logger.Info(l) - } else { - logger.Info(fmt.Sprintf("Blockstamp ending in 0x%x", l)) - } - } - - difficulty := engineConfig.Difficulty - if difficulty != 200000 { - difficulty = 200000 - } - - b := sha3.Sum256(seed) - v := vdf.New(difficulty, b) - - v.Execute() - o := v.GetOutput() - inputMessage := o[:] - - logger.Info("encoding all prior state") - - bridged := []*BridgedPeerJson{} - vouchers := []string{} - firstRetro := []*FirstRetroJson{} - secondRetro := []*SecondRetroJson{} - thirdRetro := []*ThirdRetroJson{} - fourthRetro := []*FourthRetroJson{} - - err = json.Unmarshal(bridgedPeersJsonBinary, &bridged) - if err != nil { - panic(err) - } - - err = json.Unmarshal(ceremonyVouchersJsonBinary, &vouchers) - if err != nil { - panic(err) - } - - err = json.Unmarshal(firstRetroJsonBinary, &firstRetro) - if err != nil { - panic(err) - } - - err = json.Unmarshal(secondRetroJsonBinary, &secondRetro) - if err != nil { - panic(err) - } - - err = json.Unmarshal(thirdRetroJsonBinary, &thirdRetro) - if err != nil { - panic(err) - } - - err = json.Unmarshal(fourthRetroJsonBinary, &fourthRetro) - if err != nil { - panic(err) - } - - bridgedAddrs := map[string]struct{}{} - - logger.Info("encoding bridged token state") - bridgeTotal := decimal.Zero - for _, b := range bridged { - amt, err := decimal.NewFromString(b.Amount) - if err != nil { - panic(err) - } - bridgeTotal = bridgeTotal.Add(amt) - bridgedAddrs[b.Identifier] = struct{}{} - } - - voucherTotals := map[string]decimal.Decimal{} - peerIdTotals := map[string]decimal.Decimal{} - peerSeniority := map[string]uint64{} - logger.Info("encoding first retro state") - for _, f := range firstRetro { - if _, ok := bridgedAddrs[f.PeerId]; !ok { - peerIdTotals[f.PeerId], err = decimal.NewFromString(f.Reward) - if err != nil { - panic(err) - } - } - - // these don't have decimals so we can shortcut - max := 157208 - actual, err := strconv.Atoi(f.Reward) - if err != nil { - panic(err) - } - - peerSeniority[f.PeerId] = uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) - } - - logger.Info("encoding voucher state") - for _, v := range vouchers { - if _, ok := bridgedAddrs[v]; !ok { - voucherTotals[v] = decimal.NewFromInt(50) - } - } - - logger.Info("encoding second retro state") - for _, f := range secondRetro { - if _, ok := bridgedAddrs[f.PeerId]; !ok { - existing, ok := peerIdTotals[f.PeerId] - - amount, err := decimal.NewFromString(f.Reward) - if err != nil { - panic(err) - } - - if !ok { - peerIdTotals[f.PeerId] = amount - } else { - peerIdTotals[f.PeerId] = existing.Add(amount) - } - } - - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 - } - - if f.JanPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) - } - - if f.FebPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 29) - } - - if f.MarPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) - } - - if f.AprPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) - } - - if f.MayPresence { - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) - } - } - - logger.Info("encoding third retro state") - for _, f := range thirdRetro { - existing, ok := peerIdTotals[f.PeerId] - - amount, err := decimal.NewFromString(f.Reward) - if err != nil { - panic(err) - } - - if !ok { - peerIdTotals[f.PeerId] = amount - } else { - peerIdTotals[f.PeerId] = existing.Add(amount) - } - - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 - } - - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) - } - - logger.Info("encoding fourth retro state") - for _, f := range fourthRetro { - existing, ok := peerIdTotals[f.PeerId] - - amount, err := decimal.NewFromString(f.Reward) - if err != nil { - panic(err) - } - - if !ok { - peerIdTotals[f.PeerId] = amount - } else { - peerIdTotals[f.PeerId] = existing.Add(amount) - } - - if _, ok := peerSeniority[f.PeerId]; !ok { - peerSeniority[f.PeerId] = 0 - } - - peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) - } - - genesisState := &protobufs.TokenOutputs{ - Outputs: []*protobufs.TokenOutput{}, - } - - factor, _ := decimal.NewFromString("8000000000") - bridgeAddressHex, err := hex.DecodeString(BridgeAddress) - if err != nil { - panic(err) - } - - totalExecutions := 0 - logger.Info( - "creating execution state", - zap.Int( - "coin_executions", - totalExecutions, - ), - ) - genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: &protobufs.Coin{ - Amount: bridgeTotal.Mul(factor).BigInt().FillBytes( - make([]byte, 32), - ), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - Address: bridgeAddressHex, - }, - }, - }, - }, - }, - }) - totalExecutions++ - - for peerId, total := range peerIdTotals { - if totalExecutions%1000 == 0 { - logger.Info( - "creating execution state", - zap.Int( - "coin_executions", - totalExecutions, - ), - ) - } - peerBytes, err := base58.Decode(peerId) - if err != nil { - panic(err) - } - - addr, err := poseidon.HashBytes(peerBytes) - if err != nil { - panic(err) - } - - genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: &protobufs.Coin{ - Amount: total.Mul(factor).BigInt().FillBytes( - make([]byte, 32), - ), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - }, - }, - }) - totalExecutions++ - } - - for voucher, total := range voucherTotals { - if totalExecutions%1000 == 0 { - logger.Info( - "creating execution state", - zap.Int( - "coin_executions", - totalExecutions, - ), - ) - } - keyBytes, err := hex.DecodeString(voucher[2:]) - if err != nil { - panic(err) - } - - addr, err := poseidon.HashBytes(keyBytes) - if err != nil { - panic(err) - } - - genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ - Output: &protobufs.TokenOutput_Coin{ - Coin: &protobufs.Coin{ - Amount: total.Mul(factor).BigInt().FillBytes( - make([]byte, 32), - ), - Intersection: make([]byte, 1024), - Owner: &protobufs.AccountRef{ - Account: &protobufs.AccountRef_ImplicitAccount{ - ImplicitAccount: &protobufs.ImplicitAccount{ - Address: addr.FillBytes(make([]byte, 32)), - }, - }, - }, - }, - }, - }) - totalExecutions++ - } - - logger.Info( - "serializing execution state to store, this may take some time...", - zap.Int( - "coin_executions", - totalExecutions, - ), - ) - txn, err := coinStore.NewTransaction() - for _, output := range genesisState.Outputs { - if err != nil { - panic(err) - } - - address, err := GetAddressOfCoin(output.GetCoin(), 0) - if err != nil { - panic(err) - } - err = coinStore.PutCoin( - txn, - 0, - address, - output.GetCoin(), - ) - if err != nil { - panic(err) - } - } - if err := txn.Commit(); err != nil { - panic(err) - } - - logger.Info("encoded transcript") - - outputBytes, err := proto.Marshal(genesisState) - if err != nil { - panic(err) - } - - intrinsicFilter := p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3) - - executionOutput := &protobufs.IntrinsicExecutionOutput{ - Address: intrinsicFilter, - Output: outputBytes, - Proof: seed, - } - - data, err := proto.Marshal(executionOutput) - if err != nil { - panic(err) - } - - logger.Debug("encoded execution output") - digest := sha3.NewShake256() - _, err = digest.Write(data) - if err != nil { - panic(err) - } - - expand := make([]byte, 1024) - _, err = digest.Read(expand) - if err != nil { - panic(err) - } - - commitment, err := inclusionProver.CommitRaw( - expand, - 16, - ) - if err != nil { - panic(err) - } - - logger.Debug("creating kzg proof") - proof, err := inclusionProver.ProveRaw( - expand, - int(expand[0]%16), - 16, - ) - if err != nil { - panic(err) - } - - logger.Info("finalizing execution proof") - - return inputMessage, &qcrypto.InclusionAggregateProof{ - InclusionCommitments: []*qcrypto.InclusionCommitment{ - &qcrypto.InclusionCommitment{ - TypeUrl: protobufs.IntrinsicExecutionOutputType, - Data: data, - Commitment: commitment, - }, - }, - AggregateCommitment: commitment, - Proof: proof, - }, [][]byte{genesis.Beacon}, map[string]uint64{} -} - -func GetAddressOfCoin( - coin *protobufs.Coin, - frameNumber uint64, -) ([]byte, error) { - eval := []byte{} - eval = append(eval, application.TOKEN_ADDRESS...) - eval = binary.BigEndian.AppendUint64(eval, frameNumber) - eval = append(eval, coin.Amount...) - eval = append(eval, coin.Intersection...) - eval = binary.BigEndian.AppendUint32(eval, 0) - eval = append(eval, coin.Owner.GetImplicitAccount().Address...) - addressBI, err := poseidon.HashBytes(eval) - if err != nil { - return nil, err - } - - return addressBI.FillBytes(make([]byte, 32)), nil -} - -func GetAddressOfPreCoinProof( - proof *protobufs.PreCoinProof, -) ([]byte, error) { - eval := []byte{} - eval = append(eval, application.TOKEN_ADDRESS...) - eval = append(eval, proof.Amount...) - eval = binary.BigEndian.AppendUint32(eval, proof.Index) - eval = append(eval, proof.IndexProof...) - eval = append(eval, proof.Commitment...) - eval = append(eval, proof.Proof...) - eval = binary.BigEndian.AppendUint32(eval, proof.Parallelism) - eval = binary.BigEndian.AppendUint32(eval, proof.Difficulty) - eval = binary.BigEndian.AppendUint32(eval, 0) - eval = append(eval, proof.Owner.GetImplicitAccount().Address...) - addressBI, err := poseidon.HashBytes(eval) - if err != nil { - return nil, err - } - - return addressBI.FillBytes(make([]byte, 32)), nil -} - // Start implements ExecutionEngine func (e *TokenExecutionEngine) Start() <-chan error { errChan := make(chan error) @@ -939,8 +375,6 @@ func (e *TokenExecutionEngine) Start() <-chan error { panic(err) } - go e.RunWorker() - errChan <- nil }() @@ -964,45 +398,18 @@ func (e *TokenExecutionEngine) ProcessMessage( message *protobufs.Message, ) ([]*protobufs.Message, error) { if bytes.Equal(address, e.GetSupportedApplications()[0].Address) { - e.logger.Debug("processing execution message") any := &anypb.Any{} if err := proto.Unmarshal(message.Payload, any); err != nil { return nil, errors.Wrap(err, "process message") } - switch any.TypeUrl { - case protobufs.ClockFrameType: - frame := &protobufs.ClockFrame{} - if err := any.UnmarshalTo(frame); err != nil { - return nil, errors.Wrap(err, "process message") - } - - if frame.FrameNumber < e.clock.GetFrame().FrameNumber { - return nil, nil - } - - if err := e.frameProver.VerifyDataClockFrame(frame); err != nil { - return nil, errors.Wrap(err, "process message") - } + e.logger.Debug( + "processing execution message", + zap.String("type", any.TypeUrl), + ) - if err := e.VerifyExecution(frame); err != nil { - return nil, errors.Wrap(err, "process message") - } + switch any.TypeUrl { case protobufs.TokenRequestType: - hash := sha3.Sum256(any.Value) - if any.TypeUrl == protobufs.TokenRequestType { - e.seenMessageMx.Lock() - ref := string(hash[:]) - if _, ok := e.seenMessageMap[ref]; !ok { - e.seenMessageMap[ref] = true - } else { - return nil, errors.Wrap( - errors.New("message already received"), - "process message", - ) - } - e.seenMessageMx.Unlock() - } if e.clock.IsInProverTrie(e.proverPublicKey) { payload, err := proto.Marshal(any) if err != nil { @@ -1016,7 +423,7 @@ func (e *TokenExecutionEngine) ProcessMessage( msg := &protobufs.Message{ Hash: h.Bytes(), - Address: e.provingKeyAddress, + Address: application.TOKEN_ADDRESS, Payload: payload, } return []*protobufs.Message{ @@ -1029,102 +436,117 @@ func (e *TokenExecutionEngine) ProcessMessage( return nil, nil } -func (e *TokenExecutionEngine) RunWorker() { - frameChan := e.clock.GetFrameChannel() - for { - select { - case frame := <-frameChan: - e.activeClockFrame = frame - e.logger.Info( - "evaluating next frame", - zap.Uint64( - "frame_number", - frame.FrameNumber, - ), +func (e *TokenExecutionEngine) ProcessFrame( + txn store.Transaction, + frame *protobufs.ClockFrame, +) error { + f, err := e.coinStore.GetLatestFrameProcessed() + if err != nil || f == frame.FrameNumber { + return errors.Wrap(err, "process frame") + } + + e.activeClockFrame = frame + e.logger.Info( + "evaluating next frame", + zap.Uint64( + "frame_number", + frame.FrameNumber, + ), + ) + app, err := application.MaterializeApplicationFromFrame( + e.provingKey, + frame, + e.clock.GetFrameProverTries(), + e.coinStore, + e.logger, + ) + if err != nil { + e.logger.Error( + "error while materializing application from frame", + zap.Error(err), + ) + return errors.Wrap(err, "process frame") + } + + e.logger.Debug( + "app outputs", + zap.Int("outputs", len(app.TokenOutputs.Outputs)), + ) + + for i, output := range app.TokenOutputs.Outputs { + switch o := output.Output.(type) { + case *protobufs.TokenOutput_Coin: + address, err := GetAddressOfCoin(o.Coin, frame.FrameNumber, uint64(i)) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") + } + err = e.coinStore.PutCoin( + txn, + frame.FrameNumber, + address, + o.Coin, ) - app, err := application.MaterializeApplicationFromFrame( - frame, - e.clock.GetFrameProverTries(), - e.coinStore, - e.logger, + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") + } + case *protobufs.TokenOutput_DeletedCoin: + coin, err := e.coinStore.GetCoinByAddress(txn, o.DeletedCoin.Address) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") + } + err = e.coinStore.DeleteCoin( + txn, + o.DeletedCoin.Address, + coin, ) if err != nil { - e.logger.Error( - "error while materializing application from frame", - zap.Error(err), - ) - panic(err) + txn.Abort() + return errors.Wrap(err, "process frame") } - - txn, err := e.coinStore.NewTransaction() + case *protobufs.TokenOutput_Proof: + address, err := GetAddressOfPreCoinProof(o.Proof) if err != nil { - panic(err) + txn.Abort() + return errors.Wrap(err, "process frame") } - - for _, output := range app.TokenOutputs.Outputs { - switch o := output.Output.(type) { - case *protobufs.TokenOutput_Coin: - address, err := GetAddressOfCoin(o.Coin, frame.FrameNumber) - if err != nil { - panic(err) - } - err = e.coinStore.PutCoin( - txn, - frame.FrameNumber, - address, - o.Coin, - ) - if err != nil { - panic(err) - } - case *protobufs.TokenOutput_DeletedCoin: - coin, err := e.coinStore.GetCoinByAddress(o.DeletedCoin.Address) - if err != nil { - panic(err) - } - err = e.coinStore.DeleteCoin( - txn, - o.DeletedCoin.Address, - coin, - ) - if err != nil { - panic(err) - } - case *protobufs.TokenOutput_Proof: - address, err := GetAddressOfPreCoinProof(o.Proof) - if err != nil { - panic(err) - } - err = e.coinStore.PutPreCoinProof( - txn, - frame.FrameNumber, - address, - o.Proof, - ) - if err != nil { - panic(err) - } - case *protobufs.TokenOutput_DeletedProof: - address, err := GetAddressOfPreCoinProof(o.DeletedProof) - if err != nil { - panic(err) - } - err = e.coinStore.DeletePreCoinProof( - txn, - address, - o.DeletedProof, - ) - if err != nil { - panic(err) - } - } + err = e.coinStore.PutPreCoinProof( + txn, + frame.FrameNumber, + address, + o.Proof, + ) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") } - - if err := txn.Commit(); err != nil { - panic(err) + case *protobufs.TokenOutput_DeletedProof: + address, err := GetAddressOfPreCoinProof(o.DeletedProof) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") + } + err = e.coinStore.DeletePreCoinProof( + txn, + address, + o.DeletedProof, + ) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") } } } + + err = e.coinStore.SetLatestFrameProcessed(txn, frame.FrameNumber) + if err != nil { + txn.Abort() + return errors.Wrap(err, "process frame") + } + + return nil } func (e *TokenExecutionEngine) publishMessage( @@ -1168,10 +590,6 @@ func (e *TokenExecutionEngine) publishMessage( func (e *TokenExecutionEngine) VerifyExecution( frame *protobufs.ClockFrame, ) error { - if e.clock.GetFrame().FrameNumber != frame.FrameNumber-1 { - return nil - } - if len(frame.AggregateProofs) > 0 { for _, proofs := range frame.AggregateProofs { for _, inclusion := range proofs.InclusionCommitments { @@ -1181,19 +599,18 @@ func (e *TokenExecutionEngine) VerifyExecution( return errors.Wrap(err, "verify execution") } - parent, err := e.clockStore.GetStagedDataClockFrame( + parent, tries, err := e.clockStore.GetDataClockFrame( append( p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3), ), frame.FrameNumber-1, - frame.ParentSelector, false, ) if err != nil && !errors.Is(err, store.ErrNotFound) { return errors.Wrap(err, "verify execution") } - if parent == nil { + if parent == nil && frame.FrameNumber != 0 { return errors.Wrap( errors.New("missing parent frame"), "verify execution", @@ -1201,8 +618,9 @@ func (e *TokenExecutionEngine) VerifyExecution( } a, err := application.MaterializeApplicationFromFrame( + e.provingKey, parent, - e.clock.GetFrameProverTries(), + tries, e.coinStore, e.logger, ) @@ -1210,14 +628,19 @@ func (e *TokenExecutionEngine) VerifyExecution( return errors.Wrap(err, "verify execution") } - a, _, _, err = a.ApplyTransitions(frame.FrameNumber, transition, false) + a, _, _, err = a.ApplyTransitions( + frame.FrameNumber, + transition, + false, + ) if err != nil { return errors.Wrap(err, "verify execution") } a2, err := application.MaterializeApplicationFromFrame( + e.provingKey, frame, - e.clock.GetFrameProverTries(), + tries, e.coinStore, e.logger, ) @@ -1227,7 +650,7 @@ func (e *TokenExecutionEngine) VerifyExecution( if len(a.TokenOutputs.Outputs) != len(a2.TokenOutputs.Outputs) { return errors.Wrap( - application.ErrInvalidStateTransition, + errors.New("mismatched outputs"), "verify execution", ) } @@ -1235,23 +658,9 @@ func (e *TokenExecutionEngine) VerifyExecution( for i := range a.TokenOutputs.Outputs { o1 := a.TokenOutputs.Outputs[i] o2 := a2.TokenOutputs.Outputs[i] - b1, err := proto.Marshal(o1) - if err != nil { - return errors.Wrap( - application.ErrInvalidStateTransition, - "verify execution", - ) - } - b2, err := proto.Marshal(o2) - if err != nil { - return errors.Wrap( - application.ErrInvalidStateTransition, - "verify execution", - ) - } - if !bytes.Equal(b1, b2) { + if !proto.Equal(o1, o2) { return errors.Wrap( - application.ErrInvalidStateTransition, + errors.New("mismatched messages"), "verify execution", ) } diff --git a/node/execution/intrinsics/token/token_genesis.go b/node/execution/intrinsics/token/token_genesis.go new file mode 100644 index 0000000..83f7de0 --- /dev/null +++ b/node/execution/intrinsics/token/token_genesis.go @@ -0,0 +1,627 @@ +package token + +import ( + _ "embed" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "strconv" + "strings" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/mr-tron/base58" + "github.com/shopspring/decimal" + "go.uber.org/zap" + "golang.org/x/crypto/sha3" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" + "source.quilibrium.com/quilibrium/monorepo/node/config" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +var BridgeAddress = "1ac3290d57e064bdb5a57e874b59290226a9f9730d69f1d963600883789d6ee2" + +type BridgedPeerJson struct { + Amount string `json:"amount"` + Identifier string `json:"identifier"` + Variant string `json:"variant"` +} + +type FirstRetroJson struct { + PeerId string `json:"peerId"` + Reward string `json:"reward"` +} + +type SecondRetroJson struct { + PeerId string `json:"peerId"` + Reward string `json:"reward"` + JanPresence bool `json:"janPresence"` + FebPresence bool `json:"febPresence"` + MarPresence bool `json:"marPresence"` + AprPresence bool `json:"aprPresence"` + MayPresence bool `json:"mayPresence"` +} + +type ThirdRetroJson struct { + PeerId string `json:"peerId"` + Reward string `json:"reward"` +} + +type FourthRetroJson struct { + PeerId string `json:"peerId"` + Reward string `json:"reward"` +} + +//go:embed bridged.json +var bridgedPeersJsonBinary []byte + +//go:embed ceremony_vouchers.json +var ceremonyVouchersJsonBinary []byte + +//go:embed first_retro.json +var firstRetroJsonBinary []byte + +//go:embed second_retro.json +var secondRetroJsonBinary []byte + +//go:embed third_retro.json +var thirdRetroJsonBinary []byte + +//go:embed fourth_retro.json +var fourthRetroJsonBinary []byte + +// Creates a genesis state for the intrinsic +func CreateGenesisState( + logger *zap.Logger, + engineConfig *config.EngineConfig, + testProverKeys [][]byte, + inclusionProver qcrypto.InclusionProver, + coinStore store.CoinStore, + network uint, +) ( + []byte, + *qcrypto.InclusionAggregateProof, + [][]byte, + map[string]uint64, +) { + genesis := config.GetGenesis() + if genesis == nil { + panic("genesis is nil") + } + + seed, err := hex.DecodeString(engineConfig.GenesisSeed) + if err != nil { + panic(err) + } + + logger.Info("creating genesis frame from message:") + for i, l := range strings.Split(string(seed), "|") { + if i == 0 { + logger.Info(l) + } else { + logger.Info(fmt.Sprintf("Blockstamp ending in 0x%x", l)) + } + } + + difficulty := engineConfig.Difficulty + if difficulty != 200000 { + difficulty = 200000 + } + + b := sha3.Sum256(seed) + v := vdf.New(difficulty, b) + + v.Execute() + o := v.GetOutput() + inputMessage := o[:] + + logger.Info("encoding all prior state") + + if network == 0 { + bridged := []*BridgedPeerJson{} + vouchers := []string{} + firstRetro := []*FirstRetroJson{} + secondRetro := []*SecondRetroJson{} + thirdRetro := []*ThirdRetroJson{} + fourthRetro := []*FourthRetroJson{} + + err = json.Unmarshal(bridgedPeersJsonBinary, &bridged) + if err != nil { + panic(err) + } + + err = json.Unmarshal(ceremonyVouchersJsonBinary, &vouchers) + if err != nil { + panic(err) + } + + err = json.Unmarshal(firstRetroJsonBinary, &firstRetro) + if err != nil { + panic(err) + } + + err = json.Unmarshal(secondRetroJsonBinary, &secondRetro) + if err != nil { + panic(err) + } + + err = json.Unmarshal(thirdRetroJsonBinary, &thirdRetro) + if err != nil { + panic(err) + } + + err = json.Unmarshal(fourthRetroJsonBinary, &fourthRetro) + if err != nil { + panic(err) + } + + bridgedAddrs := map[string]struct{}{} + + logger.Info("encoding bridged token state") + bridgeTotal := decimal.Zero + for _, b := range bridged { + amt, err := decimal.NewFromString(b.Amount) + if err != nil { + panic(err) + } + bridgeTotal = bridgeTotal.Add(amt) + bridgedAddrs[b.Identifier] = struct{}{} + } + + voucherTotals := map[string]decimal.Decimal{} + peerIdTotals := map[string]decimal.Decimal{} + peerSeniority := map[string]uint64{} + logger.Info("encoding first retro state") + for _, f := range firstRetro { + if _, ok := bridgedAddrs[f.PeerId]; !ok { + peerIdTotals[f.PeerId], err = decimal.NewFromString(f.Reward) + if err != nil { + panic(err) + } + } + + // these don't have decimals so we can shortcut + max := 157208 + actual, err := strconv.Atoi(f.Reward) + if err != nil { + panic(err) + } + + peerSeniority[f.PeerId] = uint64(10 * 6 * 60 * 24 * 92 / (max / actual)) + } + + logger.Info("encoding voucher state") + for _, v := range vouchers { + if _, ok := bridgedAddrs[v]; !ok { + voucherTotals[v] = decimal.NewFromInt(50) + } + } + + logger.Info("encoding second retro state") + for _, f := range secondRetro { + if _, ok := bridgedAddrs[f.PeerId]; !ok { + existing, ok := peerIdTotals[f.PeerId] + + amount, err := decimal.NewFromString(f.Reward) + if err != nil { + panic(err) + } + + if !ok { + peerIdTotals[f.PeerId] = amount + } else { + peerIdTotals[f.PeerId] = existing.Add(amount) + } + } + + if _, ok := peerSeniority[f.PeerId]; !ok { + peerSeniority[f.PeerId] = 0 + } + + if f.JanPresence { + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + } + + if f.FebPresence { + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 29) + } + + if f.MarPresence { + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + } + + if f.AprPresence { + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) + } + + if f.MayPresence { + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + } + } + + logger.Info("encoding third retro state") + for _, f := range thirdRetro { + existing, ok := peerIdTotals[f.PeerId] + + amount, err := decimal.NewFromString(f.Reward) + if err != nil { + panic(err) + } + + if !ok { + peerIdTotals[f.PeerId] = amount + } else { + peerIdTotals[f.PeerId] = existing.Add(amount) + } + + if _, ok := peerSeniority[f.PeerId]; !ok { + peerSeniority[f.PeerId] = 0 + } + + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 30) + } + + logger.Info("encoding fourth retro state") + for _, f := range fourthRetro { + existing, ok := peerIdTotals[f.PeerId] + + amount, err := decimal.NewFromString(f.Reward) + if err != nil { + panic(err) + } + + if !ok { + peerIdTotals[f.PeerId] = amount + } else { + peerIdTotals[f.PeerId] = existing.Add(amount) + } + + if _, ok := peerSeniority[f.PeerId]; !ok { + peerSeniority[f.PeerId] = 0 + } + + peerSeniority[f.PeerId] = peerSeniority[f.PeerId] + (10 * 6 * 60 * 24 * 31) + } + + genesisState := &protobufs.TokenOutputs{ + Outputs: []*protobufs.TokenOutput{}, + } + + factor, _ := decimal.NewFromString("8000000000") + bridgeAddressHex, err := hex.DecodeString(BridgeAddress) + if err != nil { + panic(err) + } + + totalExecutions := 0 + logger.Info( + "creating execution state", + zap.Int( + "coin_executions", + totalExecutions, + ), + ) + genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: bridgeTotal.Mul(factor).BigInt().FillBytes( + make([]byte, 32), + ), + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + Address: bridgeAddressHex, + }, + }, + }, + }, + }, + }) + totalExecutions++ + + for peerId, total := range peerIdTotals { + if totalExecutions%1000 == 0 { + logger.Info( + "creating execution state", + zap.Int( + "coin_executions", + totalExecutions, + ), + ) + } + peerBytes, err := base58.Decode(peerId) + if err != nil { + panic(err) + } + + addr, err := poseidon.HashBytes(peerBytes) + if err != nil { + panic(err) + } + + genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: total.Mul(factor).BigInt().FillBytes( + make([]byte, 32), + ), + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + Address: addr.FillBytes(make([]byte, 32)), + }, + }, + }, + }, + }, + }) + totalExecutions++ + } + + for voucher, total := range voucherTotals { + if totalExecutions%1000 == 0 { + logger.Info( + "creating execution state", + zap.Int( + "coin_executions", + totalExecutions, + ), + ) + } + keyBytes, err := hex.DecodeString(voucher[2:]) + if err != nil { + panic(err) + } + + addr, err := poseidon.HashBytes(keyBytes) + if err != nil { + panic(err) + } + + genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: total.Mul(factor).BigInt().FillBytes( + make([]byte, 32), + ), + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + Address: addr.FillBytes(make([]byte, 32)), + }, + }, + }, + }, + }, + }) + totalExecutions++ + } + + logger.Info( + "serializing execution state to store, this may take some time...", + zap.Int( + "coin_executions", + totalExecutions, + ), + ) + txn, err := coinStore.NewTransaction() + for _, output := range genesisState.Outputs { + if err != nil { + panic(err) + } + + address, err := GetAddressOfCoin(output.GetCoin(), 0, 0) + if err != nil { + panic(err) + } + err = coinStore.PutCoin( + txn, + 0, + address, + output.GetCoin(), + ) + if err != nil { + panic(err) + } + } + if err := txn.Commit(); err != nil { + panic(err) + } + + logger.Info("encoded transcript") + + outputBytes, err := proto.Marshal(genesisState) + if err != nil { + panic(err) + } + + intrinsicFilter := p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3) + + executionOutput := &protobufs.IntrinsicExecutionOutput{ + Address: intrinsicFilter, + Output: outputBytes, + Proof: seed, + } + + data, err := proto.Marshal(executionOutput) + if err != nil { + panic(err) + } + + logger.Debug("encoded execution output") + digest := sha3.NewShake256() + _, err = digest.Write(data) + if err != nil { + panic(err) + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + panic(err) + } + + commitment, err := inclusionProver.CommitRaw( + expand, + 16, + ) + if err != nil { + panic(err) + } + + logger.Debug("creating kzg proof") + proof, err := inclusionProver.ProveRaw( + expand, + int(expand[0]%16), + 16, + ) + if err != nil { + panic(err) + } + + logger.Info("finalizing execution proof") + + return inputMessage, &qcrypto.InclusionAggregateProof{ + InclusionCommitments: []*qcrypto.InclusionCommitment{ + &qcrypto.InclusionCommitment{ + TypeUrl: protobufs.IntrinsicExecutionOutputType, + Data: data, + Commitment: commitment, + }, + }, + AggregateCommitment: commitment, + Proof: proof, + }, [][]byte{genesis.Beacon}, map[string]uint64{} + } else { + logger.Info( + "THIS IS A TESTNET GENESIS, DO NOT CONNECT THIS NODE TO MAINNET", + ) + + genesisState := &protobufs.TokenOutputs{ + Outputs: []*protobufs.TokenOutput{}, + } + + addr, err := poseidon.HashBytes(genesis.Beacon) + if err != nil { + panic(err) + } + + factor, _ := new(big.Int).SetString("8000000000", 10) + + genesisState.Outputs = append(genesisState.Outputs, &protobufs.TokenOutput{ + Output: &protobufs.TokenOutput_Coin{ + Coin: &protobufs.Coin{ + Amount: factor.Mul(factor, big.NewInt(0x0fffffff)).FillBytes( + make([]byte, 32), + ), + Intersection: make([]byte, 1024), + Owner: &protobufs.AccountRef{ + Account: &protobufs.AccountRef_ImplicitAccount{ + ImplicitAccount: &protobufs.ImplicitAccount{ + Address: addr.FillBytes(make([]byte, 32)), + }, + }, + }, + }, + }, + }) + + logger.Info("serializing execution state to store") + txn, err := coinStore.NewTransaction() + for _, output := range genesisState.Outputs { + if err != nil { + panic(err) + } + + address, err := GetAddressOfCoin(output.GetCoin(), 0, 0) + if err != nil { + panic(err) + } + err = coinStore.PutCoin( + txn, + 0, + address, + output.GetCoin(), + ) + if err != nil { + panic(err) + } + } + if err := txn.Commit(); err != nil { + panic(err) + } + + logger.Info("encoded transcript") + + outputBytes, err := proto.Marshal(genesisState) + if err != nil { + panic(err) + } + + intrinsicFilter := p2p.GetBloomFilter(application.TOKEN_ADDRESS, 256, 3) + + executionOutput := &protobufs.IntrinsicExecutionOutput{ + Address: intrinsicFilter, + Output: outputBytes, + Proof: seed, + } + + data, err := proto.Marshal(executionOutput) + if err != nil { + panic(err) + } + + logger.Debug("encoded execution output") + digest := sha3.NewShake256() + _, err = digest.Write(data) + if err != nil { + panic(err) + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + panic(err) + } + + commitment, err := inclusionProver.CommitRaw( + expand, + 16, + ) + if err != nil { + panic(err) + } + + logger.Debug("creating kzg proof") + proof, err := inclusionProver.ProveRaw( + expand, + int(expand[0]%16), + 16, + ) + if err != nil { + panic(err) + } + + logger.Info("finalizing execution proof") + + return inputMessage, &qcrypto.InclusionAggregateProof{ + InclusionCommitments: []*qcrypto.InclusionCommitment{ + &qcrypto.InclusionCommitment{ + TypeUrl: protobufs.IntrinsicExecutionOutputType, + Data: data, + Commitment: commitment, + }, + }, + AggregateCommitment: commitment, + Proof: proof, + }, [][]byte{genesis.Beacon}, map[string]uint64{} + } +} diff --git a/node/go.mod b/node/go.mod index c321a8e..38e72e8 100644 --- a/node/go.mod +++ b/node/go.mod @@ -26,7 +26,6 @@ replace source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub => ../go- replace github.com/cockroachdb/pebble => ../pebble require ( - filippo.io/edwards25519 v1.0.0-rc.1 github.com/cockroachdb/pebble v0.0.0-20231210175920-b4d301aeb46a github.com/deiu/rdf2go v0.0.0-20240619132609-81222e324bb9 github.com/libp2p/go-libp2p v0.35.4 @@ -42,6 +41,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/deiu/gon3 v0.0.0-20230411081920-f0f8f879f597 // indirect github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect github.com/linkeddata/gojsonld v0.0.0-20170418210642-4f5db6791326 // indirect @@ -165,7 +165,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect @@ -178,7 +178,7 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect diff --git a/node/main.go b/node/main.go index 7919902..c330c67 100644 --- a/node/main.go +++ b/node/main.go @@ -195,7 +195,7 @@ func main() { count++ } - if count < len(config.Signatories)/2+len(config.Signatories)%2 { + if count < ((len(config.Signatories)-4)/2)+((len(config.Signatories)-4)%2) { fmt.Printf("Quorum on signatures not met") os.Exit(1) } @@ -273,7 +273,7 @@ func main() { if !*dbConsole && *core == 0 { config.PrintLogo() - config.PrintVersion() + config.PrintVersion(uint8(*network)) fmt.Println(" ") } @@ -332,7 +332,7 @@ func main() { } if *core != 0 { - runtime.GOMAXPROCS(2) + // runtime.GOMAXPROCS(2) rdebug.SetGCPercent(9999) if nodeConfig.Engine.DataWorkerMemoryLimit == 0 { @@ -429,7 +429,7 @@ func main() { return } - runtime.GOMAXPROCS(1) + // runtime.GOMAXPROCS(1) if nodeConfig.ListenGRPCMultiaddr != "" { srv, err := rpc.NewRPCServer( @@ -661,7 +661,8 @@ func printNodeInfo(cfg *config.Config) { conn, err := app.ConnectToNode(cfg) if err != nil { - panic(err) + fmt.Println("Could not connect to node. If it is still booting, please wait.") + os.Exit(1) } defer conn.Close() diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index d56bec1..507a945 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -30,6 +30,7 @@ import ( "github.com/libp2p/go-libp2p/p2p/discovery/util" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" "github.com/libp2p/go-libp2p/p2p/net/connmgr" + "github.com/libp2p/go-libp2p/p2p/net/swarm" "github.com/mr-tron/base58" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" @@ -69,7 +70,7 @@ var BITMASK_ALL = []byte{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, } -var ANNOUNCE_PREFIX = "quilibrium-2.0.0-dusk-" +var ANNOUNCE_PREFIX = "quilibrium-2.0.2-dusk-" func getPeerID(p2pConfig *config.P2PConfig) peer.ID { peerPrivKey, err := hex.DecodeString(p2pConfig.PeerPrivKey) @@ -91,6 +92,80 @@ func getPeerID(p2pConfig *config.P2PConfig) peer.ID { return id } +func NewBlossomSubStreamer( + p2pConfig *config.P2PConfig, + logger *zap.Logger, +) *BlossomSub { + ctx := context.Background() + + opts := []libp2pconfig.Option{ + libp2p.ListenAddrStrings(p2pConfig.ListenMultiaddr), + } + + bootstrappers := []peer.AddrInfo{} + + peerinfo, err := peer.AddrInfoFromString("/ip4/185.209.178.191/udp/8336/quic-v1/p2p/QmcKQjpQmLpbDsiif2MuakhHFyxWvqYauPsJDaXnLav7PJ") + if err != nil { + panic(err) + } + + bootstrappers = append(bootstrappers, *peerinfo) + + var privKey crypto.PrivKey + if p2pConfig.PeerPrivKey != "" { + peerPrivKey, err := hex.DecodeString(p2pConfig.PeerPrivKey) + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + + privKey, err = crypto.UnmarshalEd448PrivateKey(peerPrivKey) + if err != nil { + panic(errors.Wrap(err, "error unmarshaling peerkey")) + } + + opts = append(opts, libp2p.Identity(privKey)) + } + + bs := &BlossomSub{ + ctx: ctx, + logger: logger, + bitmaskMap: make(map[string]*blossomsub.Bitmask), + signKey: privKey, + peerScore: make(map[string]int64), + isBootstrapPeer: false, + network: p2pConfig.Network, + } + + h, err := libp2p.New(opts...) + if err != nil { + panic(errors.Wrap(err, "error constructing p2p")) + } + + logger.Info("established peer id", zap.String("peer_id", h.ID().String())) + + kademliaDHT := initDHT( + ctx, + p2pConfig, + logger, + h, + false, + bootstrappers, + ) + routingDiscovery := routing.NewRoutingDiscovery(kademliaDHT) + util.Advertise(ctx, routingDiscovery, getNetworkNamespace(p2pConfig.Network)) + + if err != nil { + panic(err) + } + + peerID := h.ID() + bs.peerID = peerID + bs.h = h + bs.signKey = privKey + + return bs +} + func NewBlossomSub( p2pConfig *config.P2PConfig, logger *zap.Logger, @@ -181,6 +256,13 @@ func NewBlossomSub( panic(err) } + opts = append( + opts, + libp2p.SwarmOpts( + swarm.WithIPv6BlackHoleConfig(false, 0, 0), + swarm.WithUDPBlackHoleConfig(false, 0, 0), + ), + ) opts = append(opts, libp2p.ConnectionManager(cm)) opts = append(opts, libp2p.ResourceManager(rm)) } @@ -215,7 +297,7 @@ func NewBlossomSub( verifyReachability(p2pConfig) - discoverPeers(p2pConfig, ctx, logger, h, routingDiscovery) + discoverPeers(p2pConfig, ctx, logger, h, routingDiscovery, true) // TODO: turn into an option flag for console logging, this is too noisy for // default logging behavior @@ -236,6 +318,23 @@ func NewBlossomSub( blossomsub.WithStrictSignatureVerification(true), } + if len(p2pConfig.DirectPeers) > 0 { + logger.Info("Found direct peers in config") + directPeers := []peer.AddrInfo{} + for _, peerAddr := range p2pConfig.DirectPeers { + peerinfo, err := peer.AddrInfoFromString(peerAddr) + if err != nil { + panic(err) + } + logger.Info("Adding direct peer", zap.String("peer", peerinfo.ID.String())) + directPeers = append(directPeers, *peerinfo) + } + + if len(directPeers) > 0 { + blossomOpts = append(blossomOpts, blossomsub.WithDirectPeers(directPeers)) + } + } + if tracer != nil { blossomOpts = append(blossomOpts, blossomsub.WithEventTracer(tracer)) } @@ -278,6 +377,18 @@ func NewBlossomSub( bs.h = h bs.signKey = privKey + go func() { + for { + time.Sleep(30 * time.Second) + for _, b := range bs.bitmaskMap { + if len(b.ListPeers()) < 4 { + discoverPeers(p2pConfig, bs.ctx, logger, bs.h, routingDiscovery, false) + break + } + } + } + }() + return bs } @@ -481,19 +592,12 @@ func initDHT( var kademliaDHT *dht.IpfsDHT var err error if isBootstrapPeer { - if p2pConfig.Network == 0 { - panic( - "this release is for normal peers only, if you are running a " + - "bootstrap node, please use v2.0-bootstrap", - ) - } else { - kademliaDHT, err = dht.New( - ctx, - h, - dht.Mode(dht.ModeServer), - dht.BootstrapPeers(bootstrappers...), - ) - } + kademliaDHT, err = dht.New( + ctx, + h, + dht.Mode(dht.ModeServer), + dht.BootstrapPeers(bootstrappers...), + ) } else { kademliaDHT, err = dht.New( ctx, @@ -546,6 +650,19 @@ func initDHT( return kademliaDHT } +func (b *BlossomSub) Reconnect(peerId []byte) error { + peer := peer.ID(peerId) + info := b.h.Peerstore().PeerInfo(peer) + b.h.ConnManager().Unprotect(info.ID, "bootstrap") + time.Sleep(10 * time.Second) + if err := b.h.Connect(b.ctx, info); err != nil { + return errors.Wrap(err, "reconnect") + } + + b.h.ConnManager().Protect(info.ID, "bootstrap") + return nil +} + func (b *BlossomSub) GetPeerScore(peerId []byte) int64 { b.peerScoreMx.Lock() score := b.peerScore[string(peerId)] @@ -559,6 +676,16 @@ func (b *BlossomSub) SetPeerScore(peerId []byte, score int64) { b.peerScoreMx.Unlock() } +func (b *BlossomSub) AddPeerScore(peerId []byte, scoreDelta int64) { + b.peerScoreMx.Lock() + if _, ok := b.peerScore[string(peerId)]; !ok { + b.peerScore[string(peerId)] = scoreDelta + } else { + b.peerScore[string(peerId)] = b.peerScore[string(peerId)] + scoreDelta + } + b.peerScoreMx.Unlock() +} + func (b *BlossomSub) GetBitmaskPeers() map[string][]string { peers := map[string][]string{} @@ -772,6 +899,16 @@ func verifyReachability(cfg *config.P2PConfig) bool { if r.Error != "" { fmt.Println("Reachability check failed: " + r.Error) + if transport == "quic" { + fmt.Println("WARNING!") + fmt.Println("WARNING!") + fmt.Println("WARNING!") + fmt.Println("You failed reachability with QUIC enabled. Consider switching to TCP") + fmt.Println("WARNING!") + fmt.Println("WARNING!") + fmt.Println("WARNING!") + time.Sleep(5 * time.Second) + } return false } @@ -785,6 +922,7 @@ func discoverPeers( logger *zap.Logger, h host.Host, routingDiscovery *routing.RoutingDiscovery, + init bool, ) { logger.Info("initiating peer discovery") @@ -803,7 +941,7 @@ func discoverPeers( if peer.ID == h.ID() || h.Network().Connectedness(peer.ID) == network.Connected || h.Network().Connectedness(peer.ID) == network.Limited { - continue + return } logger.Debug("found peer", zap.String("peer_id", peer.ID.String())) @@ -819,25 +957,17 @@ func discoverPeers( "connected to peer", zap.String("peer_id", peer.ID.String()), ) - if len(h.Network().Peers()) >= 6 { - break - } } } } - discover() - - go func() { - for { - time.Sleep(5 * time.Second) - if len(h.Network().Peers()) < 6 { - discover() - } - } - }() + if init { + go discover() + } else { + discover() + } - logger.Info("completed initial peer discovery") + logger.Info("completed peer discovery") } func mergeDefaults(p2pConfig *config.P2PConfig) blossomsub.BlossomSubParams { diff --git a/node/p2p/pubsub.go b/node/p2p/pubsub.go index aff95cf..4f5104c 100644 --- a/node/p2p/pubsub.go +++ b/node/p2p/pubsub.go @@ -35,4 +35,6 @@ type PubSub interface { GetPublicKey() []byte GetPeerScore(peerId []byte) int64 SetPeerScore(peerId []byte, score int64) + AddPeerScore(peerId []byte, scoreDelta int64) + Reconnect(peerId []byte) error } diff --git a/node/protobufs/data.pb.go b/node/protobufs/data.pb.go index 429a2f8..66ad28f 100644 --- a/node/protobufs/data.pb.go +++ b/node/protobufs/data.pb.go @@ -774,6 +774,179 @@ func (x *DataFrameResponse) GetProof() []byte { return nil } +type PreMidnightMintResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Increment uint32 `protobuf:"varint,2,opt,name=increment,proto3" json:"increment,omitempty"` +} + +func (x *PreMidnightMintResponse) Reset() { + *x = PreMidnightMintResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_data_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PreMidnightMintResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreMidnightMintResponse) ProtoMessage() {} + +func (x *PreMidnightMintResponse) ProtoReflect() protoreflect.Message { + mi := &file_data_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreMidnightMintResponse.ProtoReflect.Descriptor instead. +func (*PreMidnightMintResponse) Descriptor() ([]byte, []int) { + return file_data_proto_rawDescGZIP(), []int{11} +} + +func (x *PreMidnightMintResponse) GetAddress() []byte { + if x != nil { + return x.Address + } + return nil +} + +func (x *PreMidnightMintResponse) GetIncrement() uint32 { + if x != nil { + return x.Increment + } + return 0 +} + +type PreMidnightMintStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Owner []byte `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` +} + +func (x *PreMidnightMintStatusRequest) Reset() { + *x = PreMidnightMintStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_data_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PreMidnightMintStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreMidnightMintStatusRequest) ProtoMessage() {} + +func (x *PreMidnightMintStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_data_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreMidnightMintStatusRequest.ProtoReflect.Descriptor instead. +func (*PreMidnightMintStatusRequest) Descriptor() ([]byte, []int) { + return file_data_proto_rawDescGZIP(), []int{12} +} + +func (x *PreMidnightMintStatusRequest) GetOwner() []byte { + if x != nil { + return x.Owner + } + return nil +} + +type FrameRebroadcast struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + From uint64 `protobuf:"varint,1,opt,name=from,proto3" json:"from,omitempty"` + To uint64 `protobuf:"varint,2,opt,name=to,proto3" json:"to,omitempty"` + ClockFrames []*ClockFrame `protobuf:"bytes,3,rep,name=clock_frames,json=clockFrames,proto3" json:"clock_frames,omitempty"` + Random []byte `protobuf:"bytes,4,opt,name=random,proto3" json:"random,omitempty"` +} + +func (x *FrameRebroadcast) Reset() { + *x = FrameRebroadcast{} + if protoimpl.UnsafeEnabled { + mi := &file_data_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrameRebroadcast) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrameRebroadcast) ProtoMessage() {} + +func (x *FrameRebroadcast) ProtoReflect() protoreflect.Message { + mi := &file_data_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrameRebroadcast.ProtoReflect.Descriptor instead. +func (*FrameRebroadcast) Descriptor() ([]byte, []int) { + return file_data_proto_rawDescGZIP(), []int{13} +} + +func (x *FrameRebroadcast) GetFrom() uint64 { + if x != nil { + return x.From + } + return 0 +} + +func (x *FrameRebroadcast) GetTo() uint64 { + if x != nil { + return x.To + } + return 0 +} + +func (x *FrameRebroadcast) GetClockFrames() []*ClockFrame { + if x != nil { + return x.ClockFrames + } + return nil +} + +func (x *FrameRebroadcast) GetRandom() []byte { + if x != nil { + return x.Random + } + return nil +} + type ChallengeProofRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -786,7 +959,7 @@ type ChallengeProofRequest struct { func (x *ChallengeProofRequest) Reset() { *x = ChallengeProofRequest{} if protoimpl.UnsafeEnabled { - mi := &file_data_proto_msgTypes[11] + mi := &file_data_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -799,7 +972,7 @@ func (x *ChallengeProofRequest) String() string { func (*ChallengeProofRequest) ProtoMessage() {} func (x *ChallengeProofRequest) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[11] + mi := &file_data_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -812,7 +985,7 @@ func (x *ChallengeProofRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChallengeProofRequest.ProtoReflect.Descriptor instead. func (*ChallengeProofRequest) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{11} + return file_data_proto_rawDescGZIP(), []int{14} } func (x *ChallengeProofRequest) GetPeerId() []byte { @@ -840,7 +1013,7 @@ type ChallengeProofResponse struct { func (x *ChallengeProofResponse) Reset() { *x = ChallengeProofResponse{} if protoimpl.UnsafeEnabled { - mi := &file_data_proto_msgTypes[12] + mi := &file_data_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -853,7 +1026,7 @@ func (x *ChallengeProofResponse) String() string { func (*ChallengeProofResponse) ProtoMessage() {} func (x *ChallengeProofResponse) ProtoReflect() protoreflect.Message { - mi := &file_data_proto_msgTypes[12] + mi := &file_data_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -866,7 +1039,7 @@ func (x *ChallengeProofResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChallengeProofResponse.ProtoReflect.Descriptor instead. func (*ChallengeProofResponse) Descriptor() ([]byte, []int) { - return file_data_proto_rawDescGZIP(), []int{12} + return file_data_proto_rawDescGZIP(), []int{15} } func (x *ChallengeProofResponse) GetOutput() []byte { @@ -883,181 +1056,215 @@ var file_data_proto_rawDesc = []byte{ 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x1a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x0a, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, - 0x14, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6e, 0x6e, - 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x6c, 0x69, - 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x52, 0x08, 0x70, 0x65, 0x65, - 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xfa, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, - 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, - 0x75, 0x6c, 0x74, 0x69, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, - 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, - 0x78, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, - 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x22, 0xd4, 0x02, 0x0a, 0x12, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, - 0x6d, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, - 0x74, 0x6f, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x5a, 0x0a, - 0x16, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x52, 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6c, - 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x49, - 0x0a, 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, - 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, - 0x08, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x19, 0x53, 0x79, - 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x43, - 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x20, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, - 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, - 0x65, 0x73, 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, - 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, - 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, - 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x42, 0x0e, 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0xce, 0x01, 0x0a, 0x21, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, - 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x6f, 0x1a, 0x0a, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, 0x14, 0x44, 0x61, 0x74, + 0x61, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, + 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, + 0x74, 0x22, 0xfa, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x50, 0x65, 0x65, 0x72, 0x12, 0x17, + 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, + 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x22, 0xd4, + 0x02, 0x0a, 0x12, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0f, 0x66, 0x72, 0x6f, 0x6d, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x6f, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x16, 0x74, 0x72, 0x75, + 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, - 0x50, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, - 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x12, 0x49, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, - 0x64, 0x53, 0x79, 0x6e, 0x63, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x12, 0x52, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, + 0x14, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, + 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x4d, + 0x61, 0x70, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x49, 0x0a, 0x08, 0x73, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x08, 0x73, 0x65, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x97, 0x01, 0x0a, 0x19, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, + 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, + 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0xaa, 0x02, 0x0a, 0x20, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, + 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, + 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, + 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, - 0x2e, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, - 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x0a, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, - 0x68, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7b, 0x0a, 0x17, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, - 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x73, - 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x22, 0x38, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, - 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, - 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x11, - 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, - 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, - 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x77, - 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0e, 0x0a, 0x0c, + 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xce, 0x01, 0x0a, + 0x21, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, + 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, - 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, - 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x30, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6c, 0x6c, - 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0x84, 0x04, 0x0a, 0x0b, 0x44, 0x61, - 0x74, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x17, 0x47, 0x65, 0x74, - 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x2e, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x72, 0x65, 0x66, + 0x6c, 0x69, 0x67, 0x68, 0x74, 0x48, 0x00, 0x52, 0x09, 0x70, 0x72, 0x65, 0x66, 0x6c, 0x69, 0x67, + 0x68, 0x74, 0x12, 0x49, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, + 0x63, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0e, 0x0a, + 0x0c, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa1, 0x01, + 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x4d, 0x61, 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x52, 0x0a, + 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x63, + 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x4d, 0x61, 0x70, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x22, 0x7b, 0x0a, 0x17, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x67, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x0d, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x38, + 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, + 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, + 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, + 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x51, 0x0a, 0x17, 0x50, 0x72, + 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x34, 0x0a, + 0x1c, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6f, 0x77, + 0x6e, 0x65, 0x72, 0x22, 0x97, 0x01, 0x0a, 0x10, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x62, + 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, + 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x47, 0x0a, 0x0c, + 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, + 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x22, 0x77, 0x0a, + 0x15, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x45, 0x0a, 0x0b, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, - 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x30, - 0x01, 0x12, 0x9a, 0x01, 0x0a, 0x1d, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x30, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, + 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x32, 0xff, 0x05, 0x0a, 0x0b, 0x44, 0x61, 0x74, + 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x76, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, - 0x6d, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x6d, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x30, 0x01, + 0x12, 0x9a, 0x01, 0x0a, 0x1d, 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x73, 0x12, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3a, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, + 0x32, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, 0x50, + 0x32, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, + 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x3a, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6d, - 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, - 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x50, 0x32, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x62, 0x2e, - 0x50, 0x32, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, - 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0x8c, 0x01, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x43, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x7a, 0x0a, 0x17, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, - 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2e, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, - 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x74, 0x61, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x73, 0x0a, 0x15, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, + 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, + 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x4d, + 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x35, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x4d, + 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x4d, 0x69, 0x64, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x4d, 0x69, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x01, 0x0a, 0x0e, 0x44, + 0x61, 0x74, 0x61, 0x49, 0x50, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7a, 0x0a, + 0x17, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, + 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, + 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1072,7 +1279,7 @@ func file_data_proto_rawDescGZIP() []byte { return file_data_proto_rawDescData } -var file_data_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_data_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_data_proto_goTypes = []interface{}{ (*DataPeerListAnnounce)(nil), // 0: quilibrium.node.data.pb.DataPeerListAnnounce (*DataPeer)(nil), // 1: quilibrium.node.data.pb.DataPeer @@ -1085,43 +1292,52 @@ var file_data_proto_goTypes = []interface{}{ (*InclusionCommitmentsMap)(nil), // 8: quilibrium.node.data.pb.InclusionCommitmentsMap (*GetDataFrameRequest)(nil), // 9: quilibrium.node.data.pb.GetDataFrameRequest (*DataFrameResponse)(nil), // 10: quilibrium.node.data.pb.DataFrameResponse - (*ChallengeProofRequest)(nil), // 11: quilibrium.node.data.pb.ChallengeProofRequest - (*ChallengeProofResponse)(nil), // 12: quilibrium.node.data.pb.ChallengeProofResponse - (*ClockFrame)(nil), // 13: quilibrium.node.clock.pb.ClockFrame - (*Ed448Signature)(nil), // 14: quilibrium.node.keys.pb.Ed448Signature - (*ClockFramesPreflight)(nil), // 15: quilibrium.node.clock.pb.ClockFramesPreflight - (*ClockFramesRequest)(nil), // 16: quilibrium.node.clock.pb.ClockFramesRequest - (*P2PChannelEnvelope)(nil), // 17: quilibrium.node.channel.pb.P2PChannelEnvelope + (*PreMidnightMintResponse)(nil), // 11: quilibrium.node.data.pb.PreMidnightMintResponse + (*PreMidnightMintStatusRequest)(nil), // 12: quilibrium.node.data.pb.PreMidnightMintStatusRequest + (*FrameRebroadcast)(nil), // 13: quilibrium.node.data.pb.FrameRebroadcast + (*ChallengeProofRequest)(nil), // 14: quilibrium.node.data.pb.ChallengeProofRequest + (*ChallengeProofResponse)(nil), // 15: quilibrium.node.data.pb.ChallengeProofResponse + (*ClockFrame)(nil), // 16: quilibrium.node.clock.pb.ClockFrame + (*Ed448Signature)(nil), // 17: quilibrium.node.keys.pb.Ed448Signature + (*ClockFramesPreflight)(nil), // 18: quilibrium.node.clock.pb.ClockFramesPreflight + (*ClockFramesRequest)(nil), // 19: quilibrium.node.clock.pb.ClockFramesRequest + (*P2PChannelEnvelope)(nil), // 20: quilibrium.node.channel.pb.P2PChannelEnvelope + (*MintCoinRequest)(nil), // 21: quilibrium.node.node.pb.MintCoinRequest } var file_data_proto_depIdxs = []int32{ 1, // 0: quilibrium.node.data.pb.DataPeerListAnnounce.peer_list:type_name -> quilibrium.node.data.pb.DataPeer - 13, // 1: quilibrium.node.data.pb.DataCompressedSync.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 16, // 1: quilibrium.node.data.pb.DataCompressedSync.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame 6, // 2: quilibrium.node.data.pb.DataCompressedSync.proofs:type_name -> quilibrium.node.data.pb.InclusionProofsMap 7, // 3: quilibrium.node.data.pb.DataCompressedSync.segments:type_name -> quilibrium.node.data.pb.InclusionSegmentsMap - 14, // 4: quilibrium.node.data.pb.SyncRequestAuthentication.response:type_name -> quilibrium.node.keys.pb.Ed448Signature - 15, // 5: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight - 16, // 6: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest + 17, // 4: quilibrium.node.data.pb.SyncRequestAuthentication.response:type_name -> quilibrium.node.keys.pb.Ed448Signature + 18, // 5: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight + 19, // 6: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest 3, // 7: quilibrium.node.data.pb.DataCompressedSyncRequestMessage.authentication:type_name -> quilibrium.node.data.pb.SyncRequestAuthentication - 15, // 8: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight + 18, // 8: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.preflight:type_name -> quilibrium.node.clock.pb.ClockFramesPreflight 2, // 9: quilibrium.node.data.pb.DataCompressedSyncResponseMessage.response:type_name -> quilibrium.node.data.pb.DataCompressedSync 8, // 10: quilibrium.node.data.pb.InclusionProofsMap.commitments:type_name -> quilibrium.node.data.pb.InclusionCommitmentsMap - 13, // 11: quilibrium.node.data.pb.DataFrameResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame - 13, // 12: quilibrium.node.data.pb.ChallengeProofRequest.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame - 16, // 13: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:input_type -> quilibrium.node.clock.pb.ClockFramesRequest - 4, // 14: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:input_type -> quilibrium.node.data.pb.DataCompressedSyncRequestMessage - 17, // 15: quilibrium.node.data.pb.DataService.GetPublicChannel:input_type -> quilibrium.node.channel.pb.P2PChannelEnvelope - 9, // 16: quilibrium.node.data.pb.DataService.GetDataFrame:input_type -> quilibrium.node.data.pb.GetDataFrameRequest - 11, // 17: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:input_type -> quilibrium.node.data.pb.ChallengeProofRequest - 2, // 18: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSync - 5, // 19: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSyncResponseMessage - 17, // 20: quilibrium.node.data.pb.DataService.GetPublicChannel:output_type -> quilibrium.node.channel.pb.P2PChannelEnvelope - 10, // 21: quilibrium.node.data.pb.DataService.GetDataFrame:output_type -> quilibrium.node.data.pb.DataFrameResponse - 12, // 22: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:output_type -> quilibrium.node.data.pb.ChallengeProofResponse - 18, // [18:23] is the sub-list for method output_type - 13, // [13:18] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 16, // 11: quilibrium.node.data.pb.DataFrameResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame + 16, // 12: quilibrium.node.data.pb.FrameRebroadcast.clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 16, // 13: quilibrium.node.data.pb.ChallengeProofRequest.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame + 19, // 14: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:input_type -> quilibrium.node.clock.pb.ClockFramesRequest + 4, // 15: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:input_type -> quilibrium.node.data.pb.DataCompressedSyncRequestMessage + 20, // 16: quilibrium.node.data.pb.DataService.GetPublicChannel:input_type -> quilibrium.node.channel.pb.P2PChannelEnvelope + 9, // 17: quilibrium.node.data.pb.DataService.GetDataFrame:input_type -> quilibrium.node.data.pb.GetDataFrameRequest + 21, // 18: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:input_type -> quilibrium.node.node.pb.MintCoinRequest + 12, // 19: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:input_type -> quilibrium.node.data.pb.PreMidnightMintStatusRequest + 14, // 20: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:input_type -> quilibrium.node.data.pb.ChallengeProofRequest + 2, // 21: quilibrium.node.data.pb.DataService.GetCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSync + 5, // 22: quilibrium.node.data.pb.DataService.NegotiateCompressedSyncFrames:output_type -> quilibrium.node.data.pb.DataCompressedSyncResponseMessage + 20, // 23: quilibrium.node.data.pb.DataService.GetPublicChannel:output_type -> quilibrium.node.channel.pb.P2PChannelEnvelope + 10, // 24: quilibrium.node.data.pb.DataService.GetDataFrame:output_type -> quilibrium.node.data.pb.DataFrameResponse + 11, // 25: quilibrium.node.data.pb.DataService.HandlePreMidnightMint:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse + 11, // 26: quilibrium.node.data.pb.DataService.GetPreMidnightMintStatus:output_type -> quilibrium.node.data.pb.PreMidnightMintResponse + 15, // 27: quilibrium.node.data.pb.DataIPCService.CalculateChallengeProof:output_type -> quilibrium.node.data.pb.ChallengeProofResponse + 21, // [21:28] is the sub-list for method output_type + 14, // [14:21] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_data_proto_init() } @@ -1132,6 +1348,7 @@ func file_data_proto_init() { file_channel_proto_init() file_clock_proto_init() file_keys_proto_init() + file_node_proto_init() if !protoimpl.UnsafeEnabled { file_data_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DataPeerListAnnounce); i { @@ -1266,7 +1483,7 @@ func file_data_proto_init() { } } file_data_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChallengeProofRequest); i { + switch v := v.(*PreMidnightMintResponse); i { case 0: return &v.state case 1: @@ -1278,6 +1495,42 @@ func file_data_proto_init() { } } file_data_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PreMidnightMintStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_data_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrameRebroadcast); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_data_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChallengeProofRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_data_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChallengeProofResponse); i { case 0: return &v.state @@ -1305,7 +1558,7 @@ func file_data_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_data_proto_rawDesc, NumEnums: 0, - NumMessages: 13, + NumMessages: 16, NumExtensions: 0, NumServices: 2, }, diff --git a/node/protobufs/data.pb.gw.go b/node/protobufs/data.pb.gw.go index eaff4fc..9ecb32a 100644 --- a/node/protobufs/data.pb.gw.go +++ b/node/protobufs/data.pb.gw.go @@ -176,6 +176,74 @@ func local_request_DataService_GetDataFrame_0(ctx context.Context, marshaler run } +func request_DataService_HandlePreMidnightMint_0(ctx context.Context, marshaler runtime.Marshaler, client DataServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MintCoinRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.HandlePreMidnightMint(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DataService_HandlePreMidnightMint_0(ctx context.Context, marshaler runtime.Marshaler, server DataServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MintCoinRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.HandlePreMidnightMint(ctx, &protoReq) + return msg, metadata, err + +} + +func request_DataService_GetPreMidnightMintStatus_0(ctx context.Context, marshaler runtime.Marshaler, client DataServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq PreMidnightMintStatusRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetPreMidnightMintStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DataService_GetPreMidnightMintStatus_0(ctx context.Context, marshaler runtime.Marshaler, server DataServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq PreMidnightMintStatusRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetPreMidnightMintStatus(ctx, &protoReq) + return msg, metadata, err + +} + func request_DataIPCService_CalculateChallengeProof_0(ctx context.Context, marshaler runtime.Marshaler, client DataIPCServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ChallengeProofRequest var metadata runtime.ServerMetadata @@ -262,6 +330,56 @@ func RegisterDataServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_DataService_HandlePreMidnightMint_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/quilibrium.node.data.pb.DataService/HandlePreMidnightMint", runtime.WithHTTPPathPattern("/quilibrium.node.data.pb.DataService/HandlePreMidnightMint")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DataService_HandlePreMidnightMint_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataService_HandlePreMidnightMint_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_DataService_GetPreMidnightMintStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/quilibrium.node.data.pb.DataService/GetPreMidnightMintStatus", runtime.WithHTTPPathPattern("/quilibrium.node.data.pb.DataService/GetPreMidnightMintStatus")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DataService_GetPreMidnightMintStatus_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataService_GetPreMidnightMintStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -425,6 +543,50 @@ func RegisterDataServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_DataService_HandlePreMidnightMint_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/quilibrium.node.data.pb.DataService/HandlePreMidnightMint", runtime.WithHTTPPathPattern("/quilibrium.node.data.pb.DataService/HandlePreMidnightMint")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DataService_HandlePreMidnightMint_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataService_HandlePreMidnightMint_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_DataService_GetPreMidnightMintStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/quilibrium.node.data.pb.DataService/GetPreMidnightMintStatus", runtime.WithHTTPPathPattern("/quilibrium.node.data.pb.DataService/GetPreMidnightMintStatus")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DataService_GetPreMidnightMintStatus_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DataService_GetPreMidnightMintStatus_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -436,6 +598,10 @@ var ( pattern_DataService_GetPublicChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.data.pb.DataService", "GetPublicChannel"}, "")) pattern_DataService_GetDataFrame_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.data.pb.DataService", "GetDataFrame"}, "")) + + pattern_DataService_HandlePreMidnightMint_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.data.pb.DataService", "HandlePreMidnightMint"}, "")) + + pattern_DataService_GetPreMidnightMintStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.data.pb.DataService", "GetPreMidnightMintStatus"}, "")) ) var ( @@ -446,6 +612,10 @@ var ( forward_DataService_GetPublicChannel_0 = runtime.ForwardResponseStream forward_DataService_GetDataFrame_0 = runtime.ForwardResponseMessage + + forward_DataService_HandlePreMidnightMint_0 = runtime.ForwardResponseMessage + + forward_DataService_GetPreMidnightMintStatus_0 = runtime.ForwardResponseMessage ) // RegisterDataIPCServiceHandlerFromEndpoint is same as RegisterDataIPCServiceHandler but diff --git a/node/protobufs/data.proto b/node/protobufs/data.proto index fce0f47..f12f7d5 100644 --- a/node/protobufs/data.proto +++ b/node/protobufs/data.proto @@ -7,6 +7,7 @@ option go_package = "source.quilibrium.com/quilibrium/monorepo/node/protobufs"; import "channel.proto"; import "clock.proto"; import "keys.proto"; +import "node.proto"; message DataPeerListAnnounce { repeated DataPeer peer_list = 1; @@ -78,11 +79,29 @@ message DataFrameResponse { bytes proof = 2; } +message PreMidnightMintResponse { + bytes address = 1; + uint32 increment = 2; +} + +message PreMidnightMintStatusRequest { + bytes owner = 1; +} + +message FrameRebroadcast { + uint64 from = 1; + uint64 to = 2; + repeated quilibrium.node.clock.pb.ClockFrame clock_frames = 3; + bytes random = 4; +} + service DataService { rpc GetCompressedSyncFrames (quilibrium.node.clock.pb.ClockFramesRequest) returns (stream DataCompressedSync); rpc NegotiateCompressedSyncFrames (stream DataCompressedSyncRequestMessage) returns (stream DataCompressedSyncResponseMessage); rpc GetPublicChannel (stream quilibrium.node.channel.pb.P2PChannelEnvelope) returns (stream quilibrium.node.channel.pb.P2PChannelEnvelope); rpc GetDataFrame (GetDataFrameRequest) returns (DataFrameResponse); + rpc HandlePreMidnightMint (quilibrium.node.node.pb.MintCoinRequest) returns (PreMidnightMintResponse); + rpc GetPreMidnightMintStatus (PreMidnightMintStatusRequest) returns (PreMidnightMintResponse); } message ChallengeProofRequest { diff --git a/node/protobufs/data_grpc.pb.go b/node/protobufs/data_grpc.pb.go index 070803d..6589132 100644 --- a/node/protobufs/data_grpc.pb.go +++ b/node/protobufs/data_grpc.pb.go @@ -23,6 +23,8 @@ const ( DataService_NegotiateCompressedSyncFrames_FullMethodName = "/quilibrium.node.data.pb.DataService/NegotiateCompressedSyncFrames" DataService_GetPublicChannel_FullMethodName = "/quilibrium.node.data.pb.DataService/GetPublicChannel" DataService_GetDataFrame_FullMethodName = "/quilibrium.node.data.pb.DataService/GetDataFrame" + DataService_HandlePreMidnightMint_FullMethodName = "/quilibrium.node.data.pb.DataService/HandlePreMidnightMint" + DataService_GetPreMidnightMintStatus_FullMethodName = "/quilibrium.node.data.pb.DataService/GetPreMidnightMintStatus" ) // DataServiceClient is the client API for DataService service. @@ -33,6 +35,8 @@ type DataServiceClient interface { NegotiateCompressedSyncFrames(ctx context.Context, opts ...grpc.CallOption) (DataService_NegotiateCompressedSyncFramesClient, error) GetPublicChannel(ctx context.Context, opts ...grpc.CallOption) (DataService_GetPublicChannelClient, error) GetDataFrame(ctx context.Context, in *GetDataFrameRequest, opts ...grpc.CallOption) (*DataFrameResponse, error) + HandlePreMidnightMint(ctx context.Context, in *MintCoinRequest, opts ...grpc.CallOption) (*PreMidnightMintResponse, error) + GetPreMidnightMintStatus(ctx context.Context, in *PreMidnightMintStatusRequest, opts ...grpc.CallOption) (*PreMidnightMintResponse, error) } type dataServiceClient struct { @@ -146,6 +150,24 @@ func (c *dataServiceClient) GetDataFrame(ctx context.Context, in *GetDataFrameRe return out, nil } +func (c *dataServiceClient) HandlePreMidnightMint(ctx context.Context, in *MintCoinRequest, opts ...grpc.CallOption) (*PreMidnightMintResponse, error) { + out := new(PreMidnightMintResponse) + err := c.cc.Invoke(ctx, DataService_HandlePreMidnightMint_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *dataServiceClient) GetPreMidnightMintStatus(ctx context.Context, in *PreMidnightMintStatusRequest, opts ...grpc.CallOption) (*PreMidnightMintResponse, error) { + out := new(PreMidnightMintResponse) + err := c.cc.Invoke(ctx, DataService_GetPreMidnightMintStatus_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DataServiceServer is the server API for DataService service. // All implementations must embed UnimplementedDataServiceServer // for forward compatibility @@ -154,6 +176,8 @@ type DataServiceServer interface { NegotiateCompressedSyncFrames(DataService_NegotiateCompressedSyncFramesServer) error GetPublicChannel(DataService_GetPublicChannelServer) error GetDataFrame(context.Context, *GetDataFrameRequest) (*DataFrameResponse, error) + HandlePreMidnightMint(context.Context, *MintCoinRequest) (*PreMidnightMintResponse, error) + GetPreMidnightMintStatus(context.Context, *PreMidnightMintStatusRequest) (*PreMidnightMintResponse, error) mustEmbedUnimplementedDataServiceServer() } @@ -173,6 +197,12 @@ func (UnimplementedDataServiceServer) GetPublicChannel(DataService_GetPublicChan func (UnimplementedDataServiceServer) GetDataFrame(context.Context, *GetDataFrameRequest) (*DataFrameResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDataFrame not implemented") } +func (UnimplementedDataServiceServer) HandlePreMidnightMint(context.Context, *MintCoinRequest) (*PreMidnightMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method HandlePreMidnightMint not implemented") +} +func (UnimplementedDataServiceServer) GetPreMidnightMintStatus(context.Context, *PreMidnightMintStatusRequest) (*PreMidnightMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPreMidnightMintStatus not implemented") +} func (UnimplementedDataServiceServer) mustEmbedUnimplementedDataServiceServer() {} // UnsafeDataServiceServer may be embedded to opt out of forward compatibility for this service. @@ -277,6 +307,42 @@ func _DataService_GetDataFrame_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _DataService_HandlePreMidnightMint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MintCoinRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataServiceServer).HandlePreMidnightMint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DataService_HandlePreMidnightMint_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataServiceServer).HandlePreMidnightMint(ctx, req.(*MintCoinRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DataService_GetPreMidnightMintStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PreMidnightMintStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataServiceServer).GetPreMidnightMintStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DataService_GetPreMidnightMintStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataServiceServer).GetPreMidnightMintStatus(ctx, req.(*PreMidnightMintStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + // DataService_ServiceDesc is the grpc.ServiceDesc for DataService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -288,6 +354,14 @@ var DataService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetDataFrame", Handler: _DataService_GetDataFrame_Handler, }, + { + MethodName: "HandlePreMidnightMint", + Handler: _DataService_HandlePreMidnightMint_Handler, + }, + { + MethodName: "GetPreMidnightMintStatus", + Handler: _DataService_GetPreMidnightMintStatus_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/node/protobufs/node.pb.go b/node/protobufs/node.pb.go index ae78cb6..6488906 100644 --- a/node/protobufs/node.pb.go +++ b/node/protobufs/node.pb.go @@ -6293,6 +6293,7 @@ type TokensByAccountResponse struct { Coins []*Coin `protobuf:"bytes,1,rep,name=coins,proto3" json:"coins,omitempty"` FrameNumbers []uint64 `protobuf:"varint,2,rep,packed,name=frame_numbers,json=frameNumbers,proto3" json:"frame_numbers,omitempty"` + Addresses [][]byte `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` } func (x *TokensByAccountResponse) Reset() { @@ -6341,6 +6342,115 @@ func (x *TokensByAccountResponse) GetFrameNumbers() []uint64 { return nil } +func (x *TokensByAccountResponse) GetAddresses() [][]byte { + if x != nil { + return x.Addresses + } + return nil +} + +type GetPreCoinProofsByAccountRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (x *GetPreCoinProofsByAccountRequest) Reset() { + *x = GetPreCoinProofsByAccountRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[104] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPreCoinProofsByAccountRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPreCoinProofsByAccountRequest) ProtoMessage() {} + +func (x *GetPreCoinProofsByAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[104] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPreCoinProofsByAccountRequest.ProtoReflect.Descriptor instead. +func (*GetPreCoinProofsByAccountRequest) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{104} +} + +func (x *GetPreCoinProofsByAccountRequest) GetAddress() []byte { + if x != nil { + return x.Address + } + return nil +} + +type PreCoinProofsByAccountResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Proofs []*PreCoinProof `protobuf:"bytes,1,rep,name=proofs,proto3" json:"proofs,omitempty"` + FrameNumbers []uint64 `protobuf:"varint,2,rep,packed,name=frame_numbers,json=frameNumbers,proto3" json:"frame_numbers,omitempty"` +} + +func (x *PreCoinProofsByAccountResponse) Reset() { + *x = PreCoinProofsByAccountResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_node_proto_msgTypes[105] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PreCoinProofsByAccountResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreCoinProofsByAccountResponse) ProtoMessage() {} + +func (x *PreCoinProofsByAccountResponse) ProtoReflect() protoreflect.Message { + mi := &file_node_proto_msgTypes[105] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreCoinProofsByAccountResponse.ProtoReflect.Descriptor instead. +func (*PreCoinProofsByAccountResponse) Descriptor() ([]byte, []int) { + return file_node_proto_rawDescGZIP(), []int{105} +} + +func (x *PreCoinProofsByAccountResponse) GetProofs() []*PreCoinProof { + if x != nil { + return x.Proofs + } + return nil +} + +func (x *PreCoinProofsByAccountResponse) GetFrameNumbers() []uint64 { + if x != nil { + return x.FrameNumbers + } + return nil +} + var File_node_proto protoreflect.FileDescriptor var file_node_proto_rawDesc = []byte{ @@ -7473,232 +7583,255 @@ var file_node_proto_rawDesc = []byte{ 0x19, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x22, 0x73, 0x0a, 0x17, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x33, 0x0a, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x05, 0x63, - 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0c, 0x66, 0x72, 0x61, - 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x32, 0xd7, 0x01, 0x0a, 0x11, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x6b, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x72, 0x65, 0x73, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x17, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, + 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x33, 0x0a, 0x05, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x05, + 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0c, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x50, + 0x72, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x42, 0x79, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x1e, 0x50, 0x72, 0x65, 0x43, 0x6f, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, + 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x32, 0xd7, 0x01, + 0x0a, 0x11, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x6b, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x55, 0x0a, 0x04, - 0x53, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x30, 0x01, 0x32, 0xd6, 0x07, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, - 0x12, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x61, - 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, - 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x64, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, + 0x12, 0x55, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x32, 0xe8, 0x08, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, + 0x65, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, - 0x72, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x30, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x4d, 0x61, 0x6e, 0x69, - 0x66, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4d, 0x61, 0x6e, 0x69, 0x66, - 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0b, - 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, + 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6e, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, - 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x7a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x68, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x10, 0x47, 0x65, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x30, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, + 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x4d, + 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x62, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x25, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, + 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x84, 0x05, 0x0a, - 0x0e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x6f, 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, - 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, - 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x78, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x39, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x79, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, - 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x73, 0x0a, 0x09, 0x4c, 0x69, - 0x73, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, - 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x9d, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x45, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x72, 0x0a, 0x06, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x12, 0x38, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, + 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x8f, 0x01, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x39, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, - 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0x9e, 0x08, 0x0a, 0x0b, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x12, 0x34, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x6c, 0x6c, - 0x6f, 0x77, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, - 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x12, 0x38, 0x2e, 0x71, 0x75, - 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x12, 0x34, + 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x32, 0x84, 0x05, 0x0a, 0x0e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6f, 0x0a, 0x05, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, - 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x66, 0x0a, 0x04, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x69, - 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, + 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x12, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x73, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x0d, 0x4d, 0x75, 0x74, - 0x75, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x12, 0x3c, 0x2e, 0x71, 0x75, 0x69, - 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, - 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, - 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x86, - 0x01, 0x0a, 0x0e, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x12, 0x3d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x75, 0x74, 0x75, 0x61, - 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x6c, 0x0a, 0x06, 0x52, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x12, 0x35, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9d, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x45, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x12, 0x34, + 0x70, 0x62, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x06, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x12, + 0x38, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9e, 0x08, 0x0a, 0x0b, 0x43, 0x6f, + 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x12, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x70, 0x62, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, + 0x74, 0x12, 0x38, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, + 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x4d, + 0x65, 0x72, 0x67, 0x65, 0x12, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x04, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, - 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, - 0x70, 0x6c, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x72, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x37, 0x2e, 0x71, - 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xad, 0x02, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8b, 0x01, 0x0a, 0x07, - 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x44, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x69, + 0x6e, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x83, + 0x01, 0x0a, 0x0d, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x12, 0x3c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x30, 0x01, 0x12, 0x86, 0x01, 0x0a, 0x0e, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x3d, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, - 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x70, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x50, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x06, 0x52, 0x65, - 0x6a, 0x65, 0x63, 0x74, 0x12, 0x43, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x75, 0x74, + 0x75, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x6c, 0x0a, + 0x06, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x12, 0x35, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x05, 0x53, + 0x70, 0x6c, 0x69, 0x74, 0x12, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, - 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, + 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x43, + 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x12, 0x37, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, + 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xad, 0x02, 0x0a, 0x12, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x8b, 0x01, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x44, 0x2e, + 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x41, 0x70, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x88, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x43, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, 0x2e, 0x71, 0x75, 0x69, 0x6c, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xcf, 0x01, 0x0a, 0x09, 0x4e, + 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x60, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, + 0x62, 0x2e, 0x50, 0x75, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, + 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0b, 0x50, 0x75, + 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xcf, 0x01, 0x0a, 0x09, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x73, 0x12, 0x60, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, - 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x4e, - 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x2b, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, - 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, - 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, - 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x74, 0x50, 0x65, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x62, + 0x2e, 0x50, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -7713,7 +7846,7 @@ func file_node_proto_rawDescGZIP() []byte { return file_node_proto_rawDescData } -var file_node_proto_msgTypes = make([]protoimpl.MessageInfo, 104) +var file_node_proto_msgTypes = make([]protoimpl.MessageInfo, 106) var file_node_proto_goTypes = []interface{}{ (*GetFramesRequest)(nil), // 0: quilibrium.node.node.pb.GetFramesRequest (*GetFrameInfoRequest)(nil), // 1: quilibrium.node.node.pb.GetFrameInfoRequest @@ -7819,29 +7952,31 @@ var file_node_proto_goTypes = []interface{}{ (*SendMessageResponse)(nil), // 101: quilibrium.node.node.pb.SendMessageResponse (*GetTokensByAccountRequest)(nil), // 102: quilibrium.node.node.pb.GetTokensByAccountRequest (*TokensByAccountResponse)(nil), // 103: quilibrium.node.node.pb.TokensByAccountResponse - (*ClockFrame)(nil), // 104: quilibrium.node.clock.pb.ClockFrame - (*ClockFramesRequest)(nil), // 105: quilibrium.node.clock.pb.ClockFramesRequest - (*ClockFramesResponse)(nil), // 106: quilibrium.node.clock.pb.ClockFramesResponse - (*Ed448Signature)(nil), // 107: quilibrium.node.keys.pb.Ed448Signature + (*GetPreCoinProofsByAccountRequest)(nil), // 104: quilibrium.node.node.pb.GetPreCoinProofsByAccountRequest + (*PreCoinProofsByAccountResponse)(nil), // 105: quilibrium.node.node.pb.PreCoinProofsByAccountResponse + (*ClockFrame)(nil), // 106: quilibrium.node.clock.pb.ClockFrame + (*ClockFramesRequest)(nil), // 107: quilibrium.node.clock.pb.ClockFramesRequest + (*ClockFramesResponse)(nil), // 108: quilibrium.node.clock.pb.ClockFramesResponse + (*Ed448Signature)(nil), // 109: quilibrium.node.keys.pb.Ed448Signature } var file_node_proto_depIdxs = []int32{ - 104, // 0: quilibrium.node.node.pb.FramesResponse.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame - 104, // 1: quilibrium.node.node.pb.FrameInfoResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame + 106, // 0: quilibrium.node.node.pb.FramesResponse.truncated_clock_frames:type_name -> quilibrium.node.clock.pb.ClockFrame + 106, // 1: quilibrium.node.node.pb.FrameInfoResponse.clock_frame:type_name -> quilibrium.node.clock.pb.ClockFrame 7, // 2: quilibrium.node.node.pb.PeerInfoResponse.peer_info:type_name -> quilibrium.node.node.pb.PeerInfo 7, // 3: quilibrium.node.node.pb.PeerInfoResponse.uncooperative_peer_info:type_name -> quilibrium.node.node.pb.PeerInfo 7, // 4: quilibrium.node.node.pb.PutPeerInfoRequest.peer_info:type_name -> quilibrium.node.node.pb.PeerInfo 7, // 5: quilibrium.node.node.pb.PutPeerInfoRequest.uncooperative_peer_info:type_name -> quilibrium.node.node.pb.PeerInfo 9, // 6: quilibrium.node.node.pb.NetworkInfoResponse.network_info:type_name -> quilibrium.node.node.pb.NetworkInfo 17, // 7: quilibrium.node.node.pb.SelfTestReport.capabilities:type_name -> quilibrium.node.node.pb.Capability - 105, // 8: quilibrium.node.node.pb.SyncRequest.frames_request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest - 106, // 9: quilibrium.node.node.pb.SyncResponse.frames_response:type_name -> quilibrium.node.clock.pb.ClockFramesResponse + 107, // 8: quilibrium.node.node.pb.SyncRequest.frames_request:type_name -> quilibrium.node.clock.pb.ClockFramesRequest + 108, // 9: quilibrium.node.node.pb.SyncResponse.frames_response:type_name -> quilibrium.node.clock.pb.ClockFramesResponse 17, // 10: quilibrium.node.node.pb.PeerManifest.capabilities:type_name -> quilibrium.node.node.pb.Capability - 107, // 11: quilibrium.node.node.pb.AnnounceProverRequest.public_key_signatures_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 11: quilibrium.node.node.pb.AnnounceProverRequest.public_key_signatures_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature 53, // 12: quilibrium.node.node.pb.AnnounceProverRequest.initial_proof:type_name -> quilibrium.node.node.pb.MintCoinRequest - 107, // 13: quilibrium.node.node.pb.AnnounceProverJoin.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature - 107, // 14: quilibrium.node.node.pb.AnnounceProverLeave.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature - 107, // 15: quilibrium.node.node.pb.AnnounceProverPause.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature - 107, // 16: quilibrium.node.node.pb.AnnounceProverResume.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 13: quilibrium.node.node.pb.AnnounceProverJoin.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 14: quilibrium.node.node.pb.AnnounceProverLeave.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 15: quilibrium.node.node.pb.AnnounceProverPause.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 16: quilibrium.node.node.pb.AnnounceProverResume.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature 29, // 17: quilibrium.node.node.pb.AccountRef.originated_account:type_name -> quilibrium.node.node.pb.OriginatedAccountRef 30, // 18: quilibrium.node.node.pb.AccountRef.implicit_account:type_name -> quilibrium.node.node.pb.ImplicitAccount 31, // 19: quilibrium.node.node.pb.Coin.owner:type_name -> quilibrium.node.node.pb.AccountRef @@ -7885,9 +8020,9 @@ var file_node_proto_depIdxs = []int32{ 40, // 57: quilibrium.node.node.pb.MergeCoinRequest.coins:type_name -> quilibrium.node.node.pb.CoinRef 32, // 58: quilibrium.node.node.pb.MergeCoinRequest.account_allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef 33, // 59: quilibrium.node.node.pb.MergeCoinRequest.coin_allowances:type_name -> quilibrium.node.node.pb.CoinAllowanceRef - 107, // 60: quilibrium.node.node.pb.MergeCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 60: quilibrium.node.node.pb.MergeCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature 32, // 61: quilibrium.node.node.pb.MintCoinRequest.allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef - 107, // 62: quilibrium.node.node.pb.MintCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 62: quilibrium.node.node.pb.MintCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature 31, // 63: quilibrium.node.node.pb.MutualReceiveCoinRequest.to_account:type_name -> quilibrium.node.node.pb.AccountRef 32, // 64: quilibrium.node.node.pb.MutualReceiveCoinRequest.allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef 43, // 65: quilibrium.node.node.pb.MutualReceiveCoinRequest.signature:type_name -> quilibrium.node.node.pb.Signature @@ -7907,13 +8042,13 @@ var file_node_proto_depIdxs = []int32{ 40, // 79: quilibrium.node.node.pb.SplitCoinRequest.of_coin:type_name -> quilibrium.node.node.pb.CoinRef 32, // 80: quilibrium.node.node.pb.SplitCoinRequest.account_allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef 33, // 81: quilibrium.node.node.pb.SplitCoinRequest.coin_allowance:type_name -> quilibrium.node.node.pb.CoinAllowanceRef - 107, // 82: quilibrium.node.node.pb.SplitCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 82: quilibrium.node.node.pb.SplitCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature 31, // 83: quilibrium.node.node.pb.TransferCoinRequest.to_account:type_name -> quilibrium.node.node.pb.AccountRef 31, // 84: quilibrium.node.node.pb.TransferCoinRequest.refund_account:type_name -> quilibrium.node.node.pb.AccountRef 40, // 85: quilibrium.node.node.pb.TransferCoinRequest.of_coin:type_name -> quilibrium.node.node.pb.CoinRef 32, // 86: quilibrium.node.node.pb.TransferCoinRequest.account_allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef 33, // 87: quilibrium.node.node.pb.TransferCoinRequest.coin_allowance:type_name -> quilibrium.node.node.pb.CoinAllowanceRef - 107, // 88: quilibrium.node.node.pb.TransferCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 109, // 88: quilibrium.node.node.pb.TransferCoinRequest.signature:type_name -> quilibrium.node.keys.pb.Ed448Signature 41, // 89: quilibrium.node.node.pb.ApprovePendingTransactionRequest.pending_transaction:type_name -> quilibrium.node.node.pb.PendingTransactionRef 32, // 90: quilibrium.node.node.pb.ApprovePendingTransactionRequest.account_allowance:type_name -> quilibrium.node.node.pb.AccountAllowanceRef 43, // 91: quilibrium.node.node.pb.ApprovePendingTransactionRequest.signature:type_name -> quilibrium.node.node.pb.Signature @@ -7996,69 +8131,72 @@ var file_node_proto_depIdxs = []int32{ 65, // 168: quilibrium.node.node.pb.ApprovePendingTransactionResponse.deliveries:type_name -> quilibrium.node.node.pb.DeliveryData 65, // 169: quilibrium.node.node.pb.RejectPendingTransactionResponse.deliveries:type_name -> quilibrium.node.node.pb.DeliveryData 34, // 170: quilibrium.node.node.pb.TokensByAccountResponse.coins:type_name -> quilibrium.node.node.pb.Coin - 19, // 171: quilibrium.node.node.pb.ValidationService.PerformValidation:input_type -> quilibrium.node.node.pb.ValidationMessage - 20, // 172: quilibrium.node.node.pb.ValidationService.Sync:input_type -> quilibrium.node.node.pb.SyncRequest - 0, // 173: quilibrium.node.node.pb.NodeService.GetFrames:input_type -> quilibrium.node.node.pb.GetFramesRequest - 1, // 174: quilibrium.node.node.pb.NodeService.GetFrameInfo:input_type -> quilibrium.node.node.pb.GetFrameInfoRequest - 2, // 175: quilibrium.node.node.pb.NodeService.GetPeerInfo:input_type -> quilibrium.node.node.pb.GetPeerInfoRequest - 3, // 176: quilibrium.node.node.pb.NodeService.GetNodeInfo:input_type -> quilibrium.node.node.pb.GetNodeInfoRequest - 4, // 177: quilibrium.node.node.pb.NodeService.GetNetworkInfo:input_type -> quilibrium.node.node.pb.GetNetworkInfoRequest - 15, // 178: quilibrium.node.node.pb.NodeService.GetTokenInfo:input_type -> quilibrium.node.node.pb.GetTokenInfoRequest - 22, // 179: quilibrium.node.node.pb.NodeService.GetPeerManifests:input_type -> quilibrium.node.node.pb.GetPeerManifestsRequest - 35, // 180: quilibrium.node.node.pb.NodeService.SendMessage:input_type -> quilibrium.node.node.pb.TokenRequest - 102, // 181: quilibrium.node.node.pb.NodeService.GetTokensByAccount:input_type -> quilibrium.node.node.pb.GetTokensByAccountRequest - 67, // 182: quilibrium.node.node.pb.AccountService.Allow:input_type -> quilibrium.node.node.pb.DecryptableAllowAccountRequest - 68, // 183: quilibrium.node.node.pb.AccountService.GetBalance:input_type -> quilibrium.node.node.pb.DecryptableBalanceAccountRequest - 69, // 184: quilibrium.node.node.pb.AccountService.ListCoins:input_type -> quilibrium.node.node.pb.DecryptableCoinsAccountRequest - 71, // 185: quilibrium.node.node.pb.AccountService.ListPendingTransactions:input_type -> quilibrium.node.node.pb.DecryptablePendingTransactionsAccountRequest - 70, // 186: quilibrium.node.node.pb.AccountService.Revoke:input_type -> quilibrium.node.node.pb.DecryptableRevokeAccountRequest - 72, // 187: quilibrium.node.node.pb.CoinService.Allow:input_type -> quilibrium.node.node.pb.DecryptableAllowCoinRequest - 73, // 188: quilibrium.node.node.pb.CoinService.Intersect:input_type -> quilibrium.node.node.pb.DecryptableIntersectCoinRequest - 74, // 189: quilibrium.node.node.pb.CoinService.Merge:input_type -> quilibrium.node.node.pb.DecryptableMergeCoinRequest - 75, // 190: quilibrium.node.node.pb.CoinService.Mint:input_type -> quilibrium.node.node.pb.DecryptableMintCoinRequest - 76, // 191: quilibrium.node.node.pb.CoinService.MutualReceive:input_type -> quilibrium.node.node.pb.DecryptableMutualReceiveCoinRequest - 77, // 192: quilibrium.node.node.pb.CoinService.MutualTransfer:input_type -> quilibrium.node.node.pb.DecryptableMutualTransferCoinRequest - 78, // 193: quilibrium.node.node.pb.CoinService.Revoke:input_type -> quilibrium.node.node.pb.DecryptableRevokeCoinRequest - 79, // 194: quilibrium.node.node.pb.CoinService.Split:input_type -> quilibrium.node.node.pb.DecryptableSplitCoinRequest - 80, // 195: quilibrium.node.node.pb.CoinService.Transfer:input_type -> quilibrium.node.node.pb.DecryptableTransferCoinRequest - 81, // 196: quilibrium.node.node.pb.TransactionService.Approve:input_type -> quilibrium.node.node.pb.DecryptableApprovePendingTransactionRequest - 82, // 197: quilibrium.node.node.pb.TransactionService.Reject:input_type -> quilibrium.node.node.pb.DecryptableRejectPendingTransactionRequest - 12, // 198: quilibrium.node.node.pb.NodeStats.PutNodeInfo:input_type -> quilibrium.node.node.pb.PutNodeInfoRequest - 11, // 199: quilibrium.node.node.pb.NodeStats.PutPeerInfo:input_type -> quilibrium.node.node.pb.PutPeerInfoRequest - 19, // 200: quilibrium.node.node.pb.ValidationService.PerformValidation:output_type -> quilibrium.node.node.pb.ValidationMessage - 21, // 201: quilibrium.node.node.pb.ValidationService.Sync:output_type -> quilibrium.node.node.pb.SyncResponse - 5, // 202: quilibrium.node.node.pb.NodeService.GetFrames:output_type -> quilibrium.node.node.pb.FramesResponse - 6, // 203: quilibrium.node.node.pb.NodeService.GetFrameInfo:output_type -> quilibrium.node.node.pb.FrameInfoResponse - 8, // 204: quilibrium.node.node.pb.NodeService.GetPeerInfo:output_type -> quilibrium.node.node.pb.PeerInfoResponse - 10, // 205: quilibrium.node.node.pb.NodeService.GetNodeInfo:output_type -> quilibrium.node.node.pb.NodeInfoResponse - 14, // 206: quilibrium.node.node.pb.NodeService.GetNetworkInfo:output_type -> quilibrium.node.node.pb.NetworkInfoResponse - 16, // 207: quilibrium.node.node.pb.NodeService.GetTokenInfo:output_type -> quilibrium.node.node.pb.TokenInfoResponse - 44, // 208: quilibrium.node.node.pb.NodeService.GetPeerManifests:output_type -> quilibrium.node.node.pb.PeerManifestsResponse - 101, // 209: quilibrium.node.node.pb.NodeService.SendMessage:output_type -> quilibrium.node.node.pb.SendMessageResponse - 103, // 210: quilibrium.node.node.pb.NodeService.GetTokensByAccount:output_type -> quilibrium.node.node.pb.TokensByAccountResponse - 85, // 211: quilibrium.node.node.pb.AccountService.Allow:output_type -> quilibrium.node.node.pb.AllowAccountResponse - 86, // 212: quilibrium.node.node.pb.AccountService.GetBalance:output_type -> quilibrium.node.node.pb.BalanceAccountResponse - 87, // 213: quilibrium.node.node.pb.AccountService.ListCoins:output_type -> quilibrium.node.node.pb.CoinsAccountResponse - 88, // 214: quilibrium.node.node.pb.AccountService.ListPendingTransactions:output_type -> quilibrium.node.node.pb.PendingTransactionsAccountResponse - 89, // 215: quilibrium.node.node.pb.AccountService.Revoke:output_type -> quilibrium.node.node.pb.RevokeAccountResponse - 90, // 216: quilibrium.node.node.pb.CoinService.Allow:output_type -> quilibrium.node.node.pb.AllowCoinResponse - 91, // 217: quilibrium.node.node.pb.CoinService.Intersect:output_type -> quilibrium.node.node.pb.IntersectCoinResponse - 92, // 218: quilibrium.node.node.pb.CoinService.Merge:output_type -> quilibrium.node.node.pb.MergeCoinResponse - 93, // 219: quilibrium.node.node.pb.CoinService.Mint:output_type -> quilibrium.node.node.pb.MintCoinResponse - 94, // 220: quilibrium.node.node.pb.CoinService.MutualReceive:output_type -> quilibrium.node.node.pb.MutualReceiveCoinResponse - 95, // 221: quilibrium.node.node.pb.CoinService.MutualTransfer:output_type -> quilibrium.node.node.pb.MutualTransferCoinResponse - 96, // 222: quilibrium.node.node.pb.CoinService.Revoke:output_type -> quilibrium.node.node.pb.RevokeCoinResponse - 97, // 223: quilibrium.node.node.pb.CoinService.Split:output_type -> quilibrium.node.node.pb.SplitCoinResponse - 98, // 224: quilibrium.node.node.pb.CoinService.Transfer:output_type -> quilibrium.node.node.pb.TransferCoinResponse - 99, // 225: quilibrium.node.node.pb.TransactionService.Approve:output_type -> quilibrium.node.node.pb.ApprovePendingTransactionResponse - 100, // 226: quilibrium.node.node.pb.TransactionService.Reject:output_type -> quilibrium.node.node.pb.RejectPendingTransactionResponse - 13, // 227: quilibrium.node.node.pb.NodeStats.PutNodeInfo:output_type -> quilibrium.node.node.pb.PutResponse - 13, // 228: quilibrium.node.node.pb.NodeStats.PutPeerInfo:output_type -> quilibrium.node.node.pb.PutResponse - 200, // [200:229] is the sub-list for method output_type - 171, // [171:200] is the sub-list for method input_type - 171, // [171:171] is the sub-list for extension type_name - 171, // [171:171] is the sub-list for extension extendee - 0, // [0:171] is the sub-list for field type_name + 37, // 171: quilibrium.node.node.pb.PreCoinProofsByAccountResponse.proofs:type_name -> quilibrium.node.node.pb.PreCoinProof + 19, // 172: quilibrium.node.node.pb.ValidationService.PerformValidation:input_type -> quilibrium.node.node.pb.ValidationMessage + 20, // 173: quilibrium.node.node.pb.ValidationService.Sync:input_type -> quilibrium.node.node.pb.SyncRequest + 0, // 174: quilibrium.node.node.pb.NodeService.GetFrames:input_type -> quilibrium.node.node.pb.GetFramesRequest + 1, // 175: quilibrium.node.node.pb.NodeService.GetFrameInfo:input_type -> quilibrium.node.node.pb.GetFrameInfoRequest + 2, // 176: quilibrium.node.node.pb.NodeService.GetPeerInfo:input_type -> quilibrium.node.node.pb.GetPeerInfoRequest + 3, // 177: quilibrium.node.node.pb.NodeService.GetNodeInfo:input_type -> quilibrium.node.node.pb.GetNodeInfoRequest + 4, // 178: quilibrium.node.node.pb.NodeService.GetNetworkInfo:input_type -> quilibrium.node.node.pb.GetNetworkInfoRequest + 15, // 179: quilibrium.node.node.pb.NodeService.GetTokenInfo:input_type -> quilibrium.node.node.pb.GetTokenInfoRequest + 22, // 180: quilibrium.node.node.pb.NodeService.GetPeerManifests:input_type -> quilibrium.node.node.pb.GetPeerManifestsRequest + 35, // 181: quilibrium.node.node.pb.NodeService.SendMessage:input_type -> quilibrium.node.node.pb.TokenRequest + 102, // 182: quilibrium.node.node.pb.NodeService.GetTokensByAccount:input_type -> quilibrium.node.node.pb.GetTokensByAccountRequest + 104, // 183: quilibrium.node.node.pb.NodeService.GetPreCoinProofsByAccount:input_type -> quilibrium.node.node.pb.GetPreCoinProofsByAccountRequest + 67, // 184: quilibrium.node.node.pb.AccountService.Allow:input_type -> quilibrium.node.node.pb.DecryptableAllowAccountRequest + 68, // 185: quilibrium.node.node.pb.AccountService.GetBalance:input_type -> quilibrium.node.node.pb.DecryptableBalanceAccountRequest + 69, // 186: quilibrium.node.node.pb.AccountService.ListCoins:input_type -> quilibrium.node.node.pb.DecryptableCoinsAccountRequest + 71, // 187: quilibrium.node.node.pb.AccountService.ListPendingTransactions:input_type -> quilibrium.node.node.pb.DecryptablePendingTransactionsAccountRequest + 70, // 188: quilibrium.node.node.pb.AccountService.Revoke:input_type -> quilibrium.node.node.pb.DecryptableRevokeAccountRequest + 72, // 189: quilibrium.node.node.pb.CoinService.Allow:input_type -> quilibrium.node.node.pb.DecryptableAllowCoinRequest + 73, // 190: quilibrium.node.node.pb.CoinService.Intersect:input_type -> quilibrium.node.node.pb.DecryptableIntersectCoinRequest + 74, // 191: quilibrium.node.node.pb.CoinService.Merge:input_type -> quilibrium.node.node.pb.DecryptableMergeCoinRequest + 75, // 192: quilibrium.node.node.pb.CoinService.Mint:input_type -> quilibrium.node.node.pb.DecryptableMintCoinRequest + 76, // 193: quilibrium.node.node.pb.CoinService.MutualReceive:input_type -> quilibrium.node.node.pb.DecryptableMutualReceiveCoinRequest + 77, // 194: quilibrium.node.node.pb.CoinService.MutualTransfer:input_type -> quilibrium.node.node.pb.DecryptableMutualTransferCoinRequest + 78, // 195: quilibrium.node.node.pb.CoinService.Revoke:input_type -> quilibrium.node.node.pb.DecryptableRevokeCoinRequest + 79, // 196: quilibrium.node.node.pb.CoinService.Split:input_type -> quilibrium.node.node.pb.DecryptableSplitCoinRequest + 80, // 197: quilibrium.node.node.pb.CoinService.Transfer:input_type -> quilibrium.node.node.pb.DecryptableTransferCoinRequest + 81, // 198: quilibrium.node.node.pb.TransactionService.Approve:input_type -> quilibrium.node.node.pb.DecryptableApprovePendingTransactionRequest + 82, // 199: quilibrium.node.node.pb.TransactionService.Reject:input_type -> quilibrium.node.node.pb.DecryptableRejectPendingTransactionRequest + 12, // 200: quilibrium.node.node.pb.NodeStats.PutNodeInfo:input_type -> quilibrium.node.node.pb.PutNodeInfoRequest + 11, // 201: quilibrium.node.node.pb.NodeStats.PutPeerInfo:input_type -> quilibrium.node.node.pb.PutPeerInfoRequest + 19, // 202: quilibrium.node.node.pb.ValidationService.PerformValidation:output_type -> quilibrium.node.node.pb.ValidationMessage + 21, // 203: quilibrium.node.node.pb.ValidationService.Sync:output_type -> quilibrium.node.node.pb.SyncResponse + 5, // 204: quilibrium.node.node.pb.NodeService.GetFrames:output_type -> quilibrium.node.node.pb.FramesResponse + 6, // 205: quilibrium.node.node.pb.NodeService.GetFrameInfo:output_type -> quilibrium.node.node.pb.FrameInfoResponse + 8, // 206: quilibrium.node.node.pb.NodeService.GetPeerInfo:output_type -> quilibrium.node.node.pb.PeerInfoResponse + 10, // 207: quilibrium.node.node.pb.NodeService.GetNodeInfo:output_type -> quilibrium.node.node.pb.NodeInfoResponse + 14, // 208: quilibrium.node.node.pb.NodeService.GetNetworkInfo:output_type -> quilibrium.node.node.pb.NetworkInfoResponse + 16, // 209: quilibrium.node.node.pb.NodeService.GetTokenInfo:output_type -> quilibrium.node.node.pb.TokenInfoResponse + 44, // 210: quilibrium.node.node.pb.NodeService.GetPeerManifests:output_type -> quilibrium.node.node.pb.PeerManifestsResponse + 101, // 211: quilibrium.node.node.pb.NodeService.SendMessage:output_type -> quilibrium.node.node.pb.SendMessageResponse + 103, // 212: quilibrium.node.node.pb.NodeService.GetTokensByAccount:output_type -> quilibrium.node.node.pb.TokensByAccountResponse + 105, // 213: quilibrium.node.node.pb.NodeService.GetPreCoinProofsByAccount:output_type -> quilibrium.node.node.pb.PreCoinProofsByAccountResponse + 85, // 214: quilibrium.node.node.pb.AccountService.Allow:output_type -> quilibrium.node.node.pb.AllowAccountResponse + 86, // 215: quilibrium.node.node.pb.AccountService.GetBalance:output_type -> quilibrium.node.node.pb.BalanceAccountResponse + 87, // 216: quilibrium.node.node.pb.AccountService.ListCoins:output_type -> quilibrium.node.node.pb.CoinsAccountResponse + 88, // 217: quilibrium.node.node.pb.AccountService.ListPendingTransactions:output_type -> quilibrium.node.node.pb.PendingTransactionsAccountResponse + 89, // 218: quilibrium.node.node.pb.AccountService.Revoke:output_type -> quilibrium.node.node.pb.RevokeAccountResponse + 90, // 219: quilibrium.node.node.pb.CoinService.Allow:output_type -> quilibrium.node.node.pb.AllowCoinResponse + 91, // 220: quilibrium.node.node.pb.CoinService.Intersect:output_type -> quilibrium.node.node.pb.IntersectCoinResponse + 92, // 221: quilibrium.node.node.pb.CoinService.Merge:output_type -> quilibrium.node.node.pb.MergeCoinResponse + 93, // 222: quilibrium.node.node.pb.CoinService.Mint:output_type -> quilibrium.node.node.pb.MintCoinResponse + 94, // 223: quilibrium.node.node.pb.CoinService.MutualReceive:output_type -> quilibrium.node.node.pb.MutualReceiveCoinResponse + 95, // 224: quilibrium.node.node.pb.CoinService.MutualTransfer:output_type -> quilibrium.node.node.pb.MutualTransferCoinResponse + 96, // 225: quilibrium.node.node.pb.CoinService.Revoke:output_type -> quilibrium.node.node.pb.RevokeCoinResponse + 97, // 226: quilibrium.node.node.pb.CoinService.Split:output_type -> quilibrium.node.node.pb.SplitCoinResponse + 98, // 227: quilibrium.node.node.pb.CoinService.Transfer:output_type -> quilibrium.node.node.pb.TransferCoinResponse + 99, // 228: quilibrium.node.node.pb.TransactionService.Approve:output_type -> quilibrium.node.node.pb.ApprovePendingTransactionResponse + 100, // 229: quilibrium.node.node.pb.TransactionService.Reject:output_type -> quilibrium.node.node.pb.RejectPendingTransactionResponse + 13, // 230: quilibrium.node.node.pb.NodeStats.PutNodeInfo:output_type -> quilibrium.node.node.pb.PutResponse + 13, // 231: quilibrium.node.node.pb.NodeStats.PutPeerInfo:output_type -> quilibrium.node.node.pb.PutResponse + 202, // [202:232] is the sub-list for method output_type + 172, // [172:202] is the sub-list for method input_type + 172, // [172:172] is the sub-list for extension type_name + 172, // [172:172] is the sub-list for extension extendee + 0, // [0:172] is the sub-list for field type_name } func init() { file_node_proto_init() } @@ -9317,6 +9455,30 @@ func file_node_proto_init() { return nil } } + file_node_proto_msgTypes[104].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPreCoinProofsByAccountRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_node_proto_msgTypes[105].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PreCoinProofsByAccountResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_node_proto_msgTypes[31].OneofWrappers = []interface{}{ (*AccountRef_OriginatedAccount)(nil), @@ -9341,7 +9503,7 @@ func file_node_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_node_proto_rawDesc, NumEnums: 0, - NumMessages: 104, + NumMessages: 106, NumExtensions: 0, NumServices: 6, }, diff --git a/node/protobufs/node.pb.gw.go b/node/protobufs/node.pb.gw.go index 22c9afb..c92f81a 100644 --- a/node/protobufs/node.pb.gw.go +++ b/node/protobufs/node.pb.gw.go @@ -396,6 +396,40 @@ func local_request_NodeService_GetTokensByAccount_0(ctx context.Context, marshal } +func request_NodeService_GetPreCoinProofsByAccount_0(ctx context.Context, marshaler runtime.Marshaler, client NodeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetPreCoinProofsByAccountRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetPreCoinProofsByAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_NodeService_GetPreCoinProofsByAccount_0(ctx context.Context, marshaler runtime.Marshaler, server NodeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetPreCoinProofsByAccountRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetPreCoinProofsByAccount(ctx, &protoReq) + return msg, metadata, err + +} + func request_AccountService_Allow_0(ctx context.Context, marshaler runtime.Marshaler, client AccountServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq DecryptableAllowAccountRequest var metadata runtime.ServerMetadata @@ -1262,6 +1296,31 @@ func RegisterNodeServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_NodeService_GetPreCoinProofsByAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/quilibrium.node.node.pb.NodeService/GetPreCoinProofsByAccount", runtime.WithHTTPPathPattern("/quilibrium.node.node.pb.NodeService/GetPreCoinProofsByAccount")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_NodeService_GetPreCoinProofsByAccount_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_NodeService_GetPreCoinProofsByAccount_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -2048,6 +2107,28 @@ func RegisterNodeServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_NodeService_GetPreCoinProofsByAccount_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/quilibrium.node.node.pb.NodeService/GetPreCoinProofsByAccount", runtime.WithHTTPPathPattern("/quilibrium.node.node.pb.NodeService/GetPreCoinProofsByAccount")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_NodeService_GetPreCoinProofsByAccount_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_NodeService_GetPreCoinProofsByAccount_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -2069,6 +2150,8 @@ var ( pattern_NodeService_SendMessage_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.node.pb.NodeService", "SendMessage"}, "")) pattern_NodeService_GetTokensByAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.node.pb.NodeService", "GetTokensByAccount"}, "")) + + pattern_NodeService_GetPreCoinProofsByAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"quilibrium.node.node.pb.NodeService", "GetPreCoinProofsByAccount"}, "")) ) var ( @@ -2089,6 +2172,8 @@ var ( forward_NodeService_SendMessage_0 = runtime.ForwardResponseMessage forward_NodeService_GetTokensByAccount_0 = runtime.ForwardResponseMessage + + forward_NodeService_GetPreCoinProofsByAccount_0 = runtime.ForwardResponseMessage ) // RegisterAccountServiceHandlerFromEndpoint is same as RegisterAccountServiceHandler but diff --git a/node/protobufs/node.proto b/node/protobufs/node.proto index ebafda7..d4c7f7e 100644 --- a/node/protobufs/node.proto +++ b/node/protobufs/node.proto @@ -623,6 +623,16 @@ message GetTokensByAccountRequest { message TokensByAccountResponse { repeated Coin coins = 1; repeated uint64 frame_numbers = 2; + repeated bytes addresses = 3; +} + +message GetPreCoinProofsByAccountRequest { + bytes address = 1; +} + +message PreCoinProofsByAccountResponse { + repeated PreCoinProof proofs = 1; + repeated uint64 frame_numbers = 2; } service NodeService { @@ -635,6 +645,7 @@ service NodeService { rpc GetPeerManifests(GetPeerManifestsRequest) returns (PeerManifestsResponse); rpc SendMessage(TokenRequest) returns (SendMessageResponse); rpc GetTokensByAccount(GetTokensByAccountRequest) returns (TokensByAccountResponse); + rpc GetPreCoinProofsByAccount(GetPreCoinProofsByAccountRequest) returns (PreCoinProofsByAccountResponse); } service AccountService { diff --git a/node/protobufs/node_grpc.pb.go b/node/protobufs/node_grpc.pb.go index 64b7283..fc776bc 100644 --- a/node/protobufs/node_grpc.pb.go +++ b/node/protobufs/node_grpc.pb.go @@ -174,15 +174,16 @@ var ValidationService_ServiceDesc = grpc.ServiceDesc{ } const ( - NodeService_GetFrames_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetFrames" - NodeService_GetFrameInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetFrameInfo" - NodeService_GetPeerInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetPeerInfo" - NodeService_GetNodeInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetNodeInfo" - NodeService_GetNetworkInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetNetworkInfo" - NodeService_GetTokenInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetTokenInfo" - NodeService_GetPeerManifests_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetPeerManifests" - NodeService_SendMessage_FullMethodName = "/quilibrium.node.node.pb.NodeService/SendMessage" - NodeService_GetTokensByAccount_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetTokensByAccount" + NodeService_GetFrames_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetFrames" + NodeService_GetFrameInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetFrameInfo" + NodeService_GetPeerInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetPeerInfo" + NodeService_GetNodeInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetNodeInfo" + NodeService_GetNetworkInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetNetworkInfo" + NodeService_GetTokenInfo_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetTokenInfo" + NodeService_GetPeerManifests_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetPeerManifests" + NodeService_SendMessage_FullMethodName = "/quilibrium.node.node.pb.NodeService/SendMessage" + NodeService_GetTokensByAccount_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetTokensByAccount" + NodeService_GetPreCoinProofsByAccount_FullMethodName = "/quilibrium.node.node.pb.NodeService/GetPreCoinProofsByAccount" ) // NodeServiceClient is the client API for NodeService service. @@ -198,6 +199,7 @@ type NodeServiceClient interface { GetPeerManifests(ctx context.Context, in *GetPeerManifestsRequest, opts ...grpc.CallOption) (*PeerManifestsResponse, error) SendMessage(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*SendMessageResponse, error) GetTokensByAccount(ctx context.Context, in *GetTokensByAccountRequest, opts ...grpc.CallOption) (*TokensByAccountResponse, error) + GetPreCoinProofsByAccount(ctx context.Context, in *GetPreCoinProofsByAccountRequest, opts ...grpc.CallOption) (*PreCoinProofsByAccountResponse, error) } type nodeServiceClient struct { @@ -289,6 +291,15 @@ func (c *nodeServiceClient) GetTokensByAccount(ctx context.Context, in *GetToken return out, nil } +func (c *nodeServiceClient) GetPreCoinProofsByAccount(ctx context.Context, in *GetPreCoinProofsByAccountRequest, opts ...grpc.CallOption) (*PreCoinProofsByAccountResponse, error) { + out := new(PreCoinProofsByAccountResponse) + err := c.cc.Invoke(ctx, NodeService_GetPreCoinProofsByAccount_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // NodeServiceServer is the server API for NodeService service. // All implementations must embed UnimplementedNodeServiceServer // for forward compatibility @@ -302,6 +313,7 @@ type NodeServiceServer interface { GetPeerManifests(context.Context, *GetPeerManifestsRequest) (*PeerManifestsResponse, error) SendMessage(context.Context, *TokenRequest) (*SendMessageResponse, error) GetTokensByAccount(context.Context, *GetTokensByAccountRequest) (*TokensByAccountResponse, error) + GetPreCoinProofsByAccount(context.Context, *GetPreCoinProofsByAccountRequest) (*PreCoinProofsByAccountResponse, error) mustEmbedUnimplementedNodeServiceServer() } @@ -336,6 +348,9 @@ func (UnimplementedNodeServiceServer) SendMessage(context.Context, *TokenRequest func (UnimplementedNodeServiceServer) GetTokensByAccount(context.Context, *GetTokensByAccountRequest) (*TokensByAccountResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTokensByAccount not implemented") } +func (UnimplementedNodeServiceServer) GetPreCoinProofsByAccount(context.Context, *GetPreCoinProofsByAccountRequest) (*PreCoinProofsByAccountResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPreCoinProofsByAccount not implemented") +} func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {} // UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service. @@ -511,6 +526,24 @@ func _NodeService_GetTokensByAccount_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _NodeService_GetPreCoinProofsByAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPreCoinProofsByAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NodeServiceServer).GetPreCoinProofsByAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: NodeService_GetPreCoinProofsByAccount_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NodeServiceServer).GetPreCoinProofsByAccount(ctx, req.(*GetPreCoinProofsByAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + // NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -554,6 +587,10 @@ var NodeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetTokensByAccount", Handler: _NodeService_GetTokensByAccount_Handler, }, + { + MethodName: "GetPreCoinProofsByAccount", + Handler: _NodeService_GetPreCoinProofsByAccount_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "node.proto", diff --git a/node/protobufs/protobufs.go b/node/protobufs/protobufs.go index 10668b9..90638b6 100644 --- a/node/protobufs/protobufs.go +++ b/node/protobufs/protobufs.go @@ -22,6 +22,7 @@ const ( InclusionProofsMapType = DataPrefix + "InclusionProofsMap" InclusionSegmentsMapType = DataPrefix + "InclusionSegmentsMap" InclusionCommitmentsMapType = DataPrefix + "InclusionCommitmentsMap" + FrameRebroadcastType = DataPrefix + "FrameRebroadcast" ApplicationType = AppPrefix + "Application" ExecutionContextType = AppPrefix + "ExecutionContext" MessageType = AppPrefix + "Message" diff --git a/node/rpc/data_worker_ipc_server.go b/node/rpc/data_worker_ipc_server.go index f997f63..8a19a0c 100644 --- a/node/rpc/data_worker_ipc_server.go +++ b/node/rpc/data_worker_ipc_server.go @@ -64,12 +64,13 @@ func (r *DataWorkerIPCServer) CalculateChallengeProof( } inRange: - for _, out := range outputs.Outputs { + for i, out := range outputs.Outputs { switch e := out.Output.(type) { case *protobufs.TokenOutput_Coin: addr, err := token.GetAddressOfCoin( e.Coin, req.ClockFrame.FrameNumber, + uint64(i), ) if err != nil { return nil, err diff --git a/node/rpc/node_rpc_server.go b/node/rpc/node_rpc_server.go index e934a54..4b845dd 100644 --- a/node/rpc/node_rpc_server.go +++ b/node/rpc/node_rpc_server.go @@ -161,9 +161,14 @@ func (r *RPCServer) GetNodeInfo( } peerScore := r.pubSub.GetPeerScore(r.pubSub.GetPeerID()) + head := r.executionEngines[0].GetFrame() + frame := uint64(0) + if head != nil { + frame = head.FrameNumber + } return &protobufs.NodeInfoResponse{ PeerId: peerID.String(), - MaxFrame: r.masterClock.GetFrame().GetFrameNumber(), + MaxFrame: frame, PeerScore: uint64(peerScore), Version: append( append([]byte{}, config.GetVersion()...), config.GetPatchNumber(), @@ -246,7 +251,9 @@ func (r *RPCServer) GetTokensByAccount( ctx context.Context, req *protobufs.GetTokensByAccountRequest, ) (*protobufs.TokensByAccountResponse, error) { - frameNumbers, coins, err := r.coinStore.GetCoinsForOwner(req.Address) + frameNumbers, addresses, coins, err := r.coinStore.GetCoinsForOwner( + req.Address, + ) if err != nil { return nil, err } @@ -254,6 +261,7 @@ func (r *RPCServer) GetTokensByAccount( return &protobufs.TokensByAccountResponse{ Coins: coins, FrameNumbers: frameNumbers, + Addresses: addresses, }, nil } @@ -263,7 +271,7 @@ func (r *RPCServer) GetTokenInfo( ) (*protobufs.TokenInfoResponse, error) { // 1 QUIL = 0x1DCD65000 units if req.Address != nil { - _, coins, err := r.coinStore.GetCoinsForOwner(req.Address) + _, _, coins, err := r.coinStore.GetCoinsForOwner(req.Address) if err != nil { return nil, errors.New("no coins found for address") } @@ -298,12 +306,12 @@ func (r *RPCServer) GetTokenInfo( addrBytes := addr.FillBytes(make([]byte, 32)) peerAddrBytes := peerAddr.FillBytes(make([]byte, 32)) - _, coins, err := r.coinStore.GetCoinsForOwner(addrBytes) + _, _, coins, err := r.coinStore.GetCoinsForOwner(addrBytes) if err != nil { panic(err) } - _, otherCoins, err := r.coinStore.GetCoinsForOwner(peerAddrBytes) + _, _, otherCoins, err := r.coinStore.GetCoinsForOwner(peerAddrBytes) if err != nil { panic(err) } diff --git a/node/store/clock.go b/node/store/clock.go index 2c6653a..03c9d71 100644 --- a/node/store/clock.go +++ b/node/store/clock.go @@ -63,6 +63,10 @@ type ClockStore interface { parentSelector []byte, truncate bool, ) (*protobufs.ClockFrame, error) + GetStagedDataClockFramesForFrameNumber( + filter []byte, + frameNumber uint64, + ) ([]*protobufs.ClockFrame, error) SetLatestDataClockFrameNumber( filter []byte, frameNumber uint64, @@ -816,6 +820,45 @@ func (p *PebbleClockStore) GetStagedDataClockFrame( return parent, nil } +func (p *PebbleClockStore) GetStagedDataClockFramesForFrameNumber( + filter []byte, + frameNumber uint64, +) ([]*protobufs.ClockFrame, error) { + iter, err := p.db.NewIter( + clockDataParentIndexKey(filter, frameNumber, bytes.Repeat([]byte{0x00}, 32)), + clockDataParentIndexKey(filter, frameNumber, bytes.Repeat([]byte{0xff}, 32)), + ) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return nil, errors.Wrap(ErrNotFound, "get staged data clock frames") + } + return nil, errors.Wrap(err, "get staged data clock frames") + } + + frames := []*protobufs.ClockFrame{} + + for iter.First(); iter.Valid(); iter.Next() { + data := iter.Value() + frame := &protobufs.ClockFrame{} + if err := proto.Unmarshal(data, frame); err != nil { + return nil, errors.Wrap(err, "get staged data clock frames") + } + + if err := p.fillAggregateProofs(frame, false); err != nil { + return nil, errors.Wrap( + errors.Wrap(err, ErrInvalidData.Error()), + "get staged data clock frames", + ) + } + + frames = append(frames, frame) + } + + iter.Close() + + return frames, nil +} + // StageDataClockFrame implements ClockStore. func (p *PebbleClockStore) StageDataClockFrame( selector []byte, @@ -1027,24 +1070,6 @@ func (p *PebbleClockStore) Compact( } if !cleared { - // If this node has been around since the early days, this is going to free - // up a lot of cruft. - if err := p.db.DeleteRange( - clockDataCandidateFrameKey( - make([]byte, 32), - 0, - make([]byte, 32), - make([]byte, 32), - ), - clockDataCandidateFrameKey( - bytes.Repeat([]byte{0xff}, 32), - 1000000, - bytes.Repeat([]byte{0xff}, 32), - bytes.Repeat([]byte{0xff}, 32), - ), - ); err != nil { - return errors.Wrap(err, "compact") - } if err := p.db.Compact( clockDataCandidateFrameKey( make([]byte, 32), diff --git a/node/store/coin.go b/node/store/coin.go index 3642b3c..83d785f 100644 --- a/node/store/coin.go +++ b/node/store/coin.go @@ -3,6 +3,8 @@ package store import ( "bytes" "encoding/binary" + "encoding/hex" + "io" "github.com/cockroachdb/pebble" "github.com/pkg/errors" @@ -13,13 +15,13 @@ import ( type CoinStore interface { NewTransaction() (Transaction, error) - GetCoinsForOwner(owner []byte) ([]uint64, []*protobufs.Coin, error) + GetCoinsForOwner(owner []byte) ([]uint64, [][]byte, []*protobufs.Coin, error) GetPreCoinProofsForOwner(owner []byte) ( []uint64, []*protobufs.PreCoinProof, error, ) - GetCoinByAddress(address []byte) (*protobufs.Coin, error) + GetCoinByAddress(txn Transaction, address []byte) (*protobufs.Coin, error) GetPreCoinProofByAddress(address []byte) (*protobufs.PreCoinProof, error) PutCoin( txn Transaction, @@ -43,6 +45,10 @@ type CoinStore interface { address []byte, preCoinProof *protobufs.PreCoinProof, ) error + GetLatestFrameProcessed() (uint64, error) + SetLatestFrameProcessed(txn Transaction, frameNumber uint64) error + SetMigrationVersion(genesisSeedHex string) error + Migrate(filter []byte, genesisSeedHex string) error } var _ CoinStore = (*PebbleCoinStore)(nil) @@ -63,10 +69,13 @@ func NewPebbleCoinStore( } const ( - COIN = 0x05 - PROOF = 0x06 - COIN_BY_ADDRESS = 0x00 - COIN_BY_OWNER = 0x01 + COIN = 0x07 + PROOF = 0x08 + COIN_BY_ADDRESS = 0x00 + COIN_BY_OWNER = 0x01 + MIGRATION = 0x02 + GENESIS = 0xFE + LATEST_EXECUTION = 0xFF ) func coinKey(address []byte) []byte { @@ -88,6 +97,10 @@ func proofKey(address []byte) []byte { return key } +func latestExecutionKey() []byte { + return []byte{COIN, LATEST_EXECUTION} +} + func proofByOwnerKey(owner []byte, address []byte) []byte { key := []byte{PROOF, COIN_BY_OWNER} key = append(key, owner...) @@ -95,13 +108,21 @@ func proofByOwnerKey(owner []byte, address []byte) []byte { return key } +func migrationKey() []byte { + return []byte{COIN, MIGRATION} +} + +func genesisSeedKey() []byte { + return []byte{COIN, GENESIS} +} + func (p *PebbleCoinStore) NewTransaction() (Transaction, error) { return p.db.NewBatch(), nil } func (p *PebbleCoinStore) GetCoinsForOwner( owner []byte, -) ([]uint64, []*protobufs.Coin, error) { +) ([]uint64, [][]byte, []*protobufs.Coin, error) { iter, err := p.db.NewIter( coinByOwnerKey(owner, bytes.Repeat([]byte{0x00}, 32)), coinByOwnerKey(owner, bytes.Repeat([]byte{0xff}, 32)), @@ -109,14 +130,15 @@ func (p *PebbleCoinStore) GetCoinsForOwner( if err != nil { if errors.Is(err, pebble.ErrNotFound) { err = ErrNotFound - return nil, nil, err + return nil, nil, nil, err } err = errors.Wrap(err, "get coins for owner") - return nil, nil, err + return nil, nil, nil, err } defer iter.Close() frameNumbers := []uint64{} + addresses := [][]byte{} coins := []*protobufs.Coin{} for iter.First(); iter.Valid(); iter.Next() { coinBytes := iter.Value() @@ -124,13 +146,16 @@ func (p *PebbleCoinStore) GetCoinsForOwner( coin := &protobufs.Coin{} err := proto.Unmarshal(coinBytes[8:], coin) if err != nil { - return nil, nil, errors.Wrap(err, "get coins for owner") + return nil, nil, nil, errors.Wrap(err, "get coins for owner") } frameNumbers = append(frameNumbers, frameNumber) + addr := make([]byte, 32) + copy(addr[:], iter.Key()[34:]) + addresses = append(addresses, addr) coins = append(coins, coin) } - return frameNumbers, coins, nil + return frameNumbers, addresses, coins, nil } func (p *PebbleCoinStore) GetPreCoinProofsForOwner(owner []byte) ( @@ -169,11 +194,18 @@ func (p *PebbleCoinStore) GetPreCoinProofsForOwner(owner []byte) ( return frameNumbers, proofs, nil } -func (p *PebbleCoinStore) GetCoinByAddress(address []byte) ( +func (p *PebbleCoinStore) GetCoinByAddress(txn Transaction, address []byte) ( *protobufs.Coin, error, ) { - coinBytes, closer, err := p.db.Get(coinKey(address)) + var coinBytes []byte + var closer io.Closer + var err error + if txn == nil { + coinBytes, closer, err = p.db.Get(coinKey(address)) + } else { + coinBytes, closer, err = txn.Get(coinKey(address)) + } if err != nil { if errors.Is(err, pebble.ErrNotFound) { err = ErrNotFound @@ -186,7 +218,7 @@ func (p *PebbleCoinStore) GetCoinByAddress(address []byte) ( defer closer.Close() coin := &protobufs.Coin{} - err = proto.Unmarshal(coinBytes[:8], coin) + err = proto.Unmarshal(coinBytes[8:], coin) if err != nil { return nil, errors.Wrap(err, "get coin by address") } @@ -211,7 +243,7 @@ func (p *PebbleCoinStore) GetPreCoinProofByAddress(address []byte) ( defer closer.Close() proof := &protobufs.PreCoinProof{} - err = proto.Unmarshal(preCoinProofBytes[:8], proof) + err = proto.Unmarshal(preCoinProofBytes[8:], proof) if err != nil { return nil, errors.Wrap(err, "get pre coin proof by address") } @@ -242,7 +274,7 @@ func (p *PebbleCoinStore) PutCoin( } err = txn.Set( - coinKey(coin.Owner.GetImplicitAccount().Address), + coinKey(address), data, ) if err != nil { @@ -295,7 +327,7 @@ func (p *PebbleCoinStore) PutPreCoinProof( } err = txn.Set( - proofKey(preCoinProof.Owner.GetImplicitAccount().Address), + proofKey(address), data, ) if err != nil { @@ -312,6 +344,10 @@ func (p *PebbleCoinStore) DeletePreCoinProof( ) error { err := txn.Delete(proofKey(address)) if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return ErrNotFound + } + return errors.Wrap(err, "delete pre coin proof") } @@ -327,3 +363,184 @@ func (p *PebbleCoinStore) DeletePreCoinProof( return nil } + +func (p *PebbleCoinStore) GetLatestFrameProcessed() (uint64, error) { + v, closer, err := p.db.Get(latestExecutionKey()) + if err != nil { + if errors.Is(err, pebble.ErrNotFound) { + return 0, nil + } + + return 0, errors.Wrap(err, "get latest frame processed") + } + + frameNumber := binary.BigEndian.Uint64(v) + closer.Close() + + return frameNumber, nil +} + +func (p *PebbleCoinStore) SetLatestFrameProcessed( + txn Transaction, + frameNumber uint64, +) error { + if err := txn.Set( + latestExecutionKey(), + binary.BigEndian.AppendUint64([]byte{}, frameNumber), + ); err != nil { + return errors.Wrap(err, "set latest frame processed") + } + + return nil +} + +func (p *PebbleCoinStore) SetMigrationVersion( + genesisSeedHex string, +) error { + seed, err := hex.DecodeString(genesisSeedHex) + if err != nil { + return errors.Wrap(err, "migrate") + } + + txn, err := p.NewTransaction() + if err != nil { + return nil + } + + err = txn.Set(migrationKey(), []byte{0x02, 0x00, 0x01, 0x04}) + if err != nil { + panic(err) + } + + err = txn.Set(genesisSeedKey(), seed) + if err != nil { + panic(err) + } + + return txn.Commit() +} + +func (p *PebbleCoinStore) internalMigrate( + filter []byte, + genesisSeed []byte, +) error { + p.logger.Warn("incompatible state change detected, performing migration") + err := p.db.DeleteRange( + coinByOwnerKey( + bytes.Repeat([]byte{0x00}, 32), + bytes.Repeat([]byte{0x00}, 32), + ), + coinByOwnerKey( + bytes.Repeat([]byte{0xff}, 32), + bytes.Repeat([]byte{0xff}, 32), + ), + ) + if err != nil { + panic(err) + } + err = p.db.DeleteRange( + coinKey( + bytes.Repeat([]byte{0x00}, 32), + ), + coinKey( + bytes.Repeat([]byte{0xff}, 32), + ), + ) + if err != nil { + panic(err) + } + err = p.db.DeleteRange( + proofByOwnerKey( + bytes.Repeat([]byte{0x00}, 32), + bytes.Repeat([]byte{0x00}, 32), + ), + proofByOwnerKey( + bytes.Repeat([]byte{0xff}, 32), + bytes.Repeat([]byte{0xff}, 32), + ), + ) + if err != nil { + panic(err) + } + err = p.db.DeleteRange( + proofKey( + bytes.Repeat([]byte{0x00}, 32), + ), + proofKey( + bytes.Repeat([]byte{0xff}, 32), + ), + ) + if err != nil { + panic(err) + } + if err := p.db.Delete(clockDataEarliestIndex(filter)); err != nil { + panic(err) + } + if err := p.db.Delete(clockDataLatestIndex(filter)); err != nil { + panic(err) + } + + txn, err := p.NewTransaction() + if err != nil { + return nil + } + + err = txn.Set(migrationKey(), []byte{0x02, 0x00, 0x01, 0x04}) + if err != nil { + panic(err) + } + + err = txn.Set(genesisSeedKey(), genesisSeed) + if err != nil { + panic(err) + } + + return txn.Commit() +} + +func (p *PebbleCoinStore) Migrate(filter []byte, genesisSeedHex string) error { + seed, err := hex.DecodeString(genesisSeedHex) + if err != nil { + return errors.Wrap(err, "migrate") + } + + compare, closer, err := p.db.Get(genesisSeedKey()) + if err != nil { + if !errors.Is(err, pebble.ErrNotFound) { + return errors.Wrap(err, "migrate") + } + return p.internalMigrate(filter, seed) + } + + if !bytes.Equal(compare, seed) { + return p.internalMigrate(filter, seed) + } + + closer.Close() + + status, closer, err := p.db.Get(migrationKey()) + if err != nil { + if !errors.Is(err, pebble.ErrNotFound) { + return errors.Wrap(err, "migrate") + } + + txn, err := p.NewTransaction() + if err != nil { + return nil + } + + err = txn.Set(migrationKey(), []byte{0x02, 0x00, 0x01, 0x04}) + if err != nil { + panic(err) + } + return txn.Commit() + } else { + defer closer.Close() + if len(status) == 4 && bytes.Compare(status, []byte{0x02, 0x00, 0x01, 0x04}) > 0 { + panic("database has been migrated to a newer version, do not rollback") + } else if len(status) == 3 || bytes.Compare(status, []byte{0x02, 0x00, 0x01, 0x04}) < 0 { + return p.internalMigrate(filter, seed) + } + return nil + } +} diff --git a/node/store/pebble.go b/node/store/pebble.go index dd2260e..9e2cbb9 100644 --- a/node/store/pebble.go +++ b/node/store/pebble.go @@ -35,7 +35,7 @@ func (p *PebbleDB) Delete(key []byte) error { func (p *PebbleDB) NewBatch() Transaction { return &PebbleTransaction{ - b: p.db.NewBatch(), + b: p.db.NewIndexedBatch(), } }