From 78bfb14b96350d6ec9567e4953a23fc7bc94b6b1 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 13 Mar 2024 14:38:54 +0800 Subject: [PATCH 01/85] added keyexchange protocol --- cmd/main.go | 2 +- pkg/evmclient/evmclient.go | 2 +- pkg/evmclient/evmclient_test.go | 2 +- pkg/keyexchange/keyexchange.go | 291 ++++++++++++++++++ pkg/keyexchange/keyexchange_test.go | 106 +++++++ pkg/keyexchange/models.go | 52 ++++ pkg/keyexchange/util.go | 37 +++ pkg/keykeeper/aescrypto.go | 50 +++ pkg/keykeeper/keykeeper.go | 60 ++++ pkg/{ => keykeeper}/keysigner/keysigner.go | 0 .../keysigner/keystoresigner.go | 0 pkg/{ => keykeeper}/keysigner/mock/mock.go | 0 .../keysigner/privatekeysigner.go | 0 pkg/keykeeper/models.go | 29 ++ pkg/node/node.go | 32 +- .../libp2p/internal/handshake/handshake.go | 2 +- .../internal/handshake/handshake_test.go | 2 +- pkg/p2p/libp2p/libp2p.go | 2 +- pkg/p2p/libp2p/libp2p_test.go | 2 +- pkg/p2p/p2p.go | 8 + pkg/signer/preconfsigner/signer.go | 2 +- pkg/signer/preconfsigner/signer_test.go | 2 +- 22 files changed, 673 insertions(+), 10 deletions(-) create mode 100644 pkg/keyexchange/keyexchange.go create mode 100644 pkg/keyexchange/keyexchange_test.go create mode 100644 pkg/keyexchange/models.go create mode 100644 pkg/keyexchange/util.go create mode 100644 pkg/keykeeper/aescrypto.go create mode 100644 pkg/keykeeper/keykeeper.go rename pkg/{ => keykeeper}/keysigner/keysigner.go (100%) rename pkg/{ => keykeeper}/keysigner/keystoresigner.go (100%) rename pkg/{ => keykeeper}/keysigner/mock/mock.go (100%) rename pkg/{ => keykeeper}/keysigner/privatekeysigner.go (100%) create mode 100644 pkg/keykeeper/models.go diff --git a/cmd/main.go b/cmd/main.go index ac9e30c7..25a8e4dd 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,7 +12,7 @@ import ( contracts "github.com/primevprotocol/contracts-abi/config" mevcommit "github.com/primevprotocol/mev-commit" - ks "github.com/primevprotocol/mev-commit/pkg/keysigner" + ks "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" "github.com/primevprotocol/mev-commit/pkg/node" "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" diff --git a/pkg/evmclient/evmclient.go b/pkg/evmclient/evmclient.go index 6c341eb5..434634df 100644 --- a/pkg/evmclient/evmclient.go +++ b/pkg/evmclient/evmclient.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/primevprotocol/mev-commit/pkg/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" "github.com/prometheus/client_golang/prometheus" ) diff --git a/pkg/evmclient/evmclient_test.go b/pkg/evmclient/evmclient_test.go index 71b98917..7e3569ab 100644 --- a/pkg/evmclient/evmclient_test.go +++ b/pkg/evmclient/evmclient_test.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/primevprotocol/mev-commit/pkg/evmclient" "github.com/primevprotocol/mev-commit/pkg/evmclient/mockevm" - mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keysigner/mock" + mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/util" ) diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go new file mode 100644 index 00000000..f6a83ce7 --- /dev/null +++ b/pkg/keyexchange/keyexchange.go @@ -0,0 +1,291 @@ +package keyexchange + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/json" + "errors" + "fmt" + "log/slog" + "sync" + "time" + + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" + "github.com/primevprotocol/mev-commit/pkg/p2p" + "github.com/primevprotocol/mev-commit/pkg/p2p/msgpack" + "github.com/primevprotocol/mev-commit/pkg/signer" + "github.com/primevprotocol/mev-commit/pkg/topology" +) + +func New( + topo Topology, + streamer p2p.Streamer, + keyKeeper keykeeper.KeyKeeper, + logger *slog.Logger, + signer signer.Signer, +) *KeyExchange { + return &KeyExchange{ + topo: topo, + streamer: streamer, + keyKeeper: keyKeeper, + logger: logger, + signer: signer, + } +} + +func (ke *KeyExchange) Protocol() p2p.ProtocolSpec { + return p2p.ProtocolSpec{ + Name: ProtocolName, + Version: ProtocolVersion, + StreamSpecs: []p2p.StreamSpec{ + { + Name: ProtocolHandlerName, + Handler: ke.handleTimestampMessage, + }, + }, + } +} + +func (ke *KeyExchange) SendTimestampMessage() error { + providers, err := ke.getProviders() + if err != nil { + ke.logger.Error("getting providers", "error", err) + return ErrNoProvidersAvailable + } + + encryptedKeys, timestampMessage, err := ke.prepareMessages(providers) + if err != nil { + return err + } + + if err := ke.distributeMessages(providers, encryptedKeys, timestampMessage); err != nil { + return err + } + + return nil +} + +func (ke *KeyExchange) getProviders() ([]p2p.Peer, error) { + providers := ke.topo.GetPeers(topology.Query{Type: p2p.PeerTypeProvider}) + if len(providers) == 0 { + return nil, ErrNoProvidersAvailable + } + return providers, nil +} + +func (ke *KeyExchange) prepareMessages(providers []p2p.Peer) ([][]byte, []byte, error) { + bidderKK, ok := ke.keyKeeper.(*keykeeper.BidderKeyKeeper) + if !ok { + return nil, nil, fmt.Errorf("keyKeeper is not of type BidderKeyKeeper") + } + + var encryptedKeys [][]byte + for _, provider := range providers { + encryptedKey, err := ecies.Encrypt(rand.Reader, provider.Keys.PKEPublicKey, bidderKK.AESKey, nil, nil) + if err != nil { + return nil, nil, fmt.Errorf("error encrypting key for provider %s: %w", provider.EthAddress, err) + } + encryptedKeys = append(encryptedKeys, encryptedKey) + } + + timestampMessage := fmt.Sprintf("mev-commit bidder %s setup %d", bidderKK.KeySigner.GetAddress(), time.Now().Unix()) + encryptedTimestampMessage, err := keykeeper.EncryptWithAESGCM(bidderKK.AESKey, []byte(timestampMessage)) + if err != nil { + return nil, nil, fmt.Errorf("error encrypting timestamp message: %w", err) + } + + return encryptedKeys, encryptedTimestampMessage, nil +} + +func (ke *KeyExchange) distributeMessages(providers []p2p.Peer, encryptedKeys [][]byte, timestampMessage []byte) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + ekmWithSignature, err := ke.createSignedMessage(encryptedKeys, timestampMessage) + if err != nil { + return fmt.Errorf("error creating signed message: %w", err) + } + + var wg sync.WaitGroup + errorsChan := make(chan error, len(providers)) + + for _, provider := range providers { + wg.Add(1) + go func(provider p2p.Peer) { + defer wg.Done() + if err := ke.sendMessageToProvider(ctx, provider, ekmWithSignature); err != nil { + errorsChan <- err + ke.logger.Error("error sending message to provider", "provider", provider.EthAddress, "error", err) + } + }(provider) + } + + wg.Wait() + close(errorsChan) + + if len(errorsChan) > 0 { + return fmt.Errorf("errors occurred while distributing messages") + } + + return nil +} + +func (ke *KeyExchange) createSignedMessage(encryptedKeys [][]byte, timestampMessage []byte) (*EKMWithSignature, error) { + message := EncryptedKeysMessage{ + EncryptedKeys: encryptedKeys, + TimestampMessage: timestampMessage, + } + + messageBytes, err := json.Marshal(message) + if err != nil { + return nil, fmt.Errorf("failed to marshal message: %w", err) + } + + hashedMessage := hashData(messageBytes) + + bidderKK := ke.keyKeeper.(*keykeeper.BidderKeyKeeper) + + signature, err := bidderKK.KeySigner.SignHash(hashedMessage.Bytes()) + if err != nil { + return nil, fmt.Errorf("failed to sign message: %w", err) + } + + ekmWithSignature := &EKMWithSignature{ + Message: messageBytes, + Signature: signature, + } + + return ekmWithSignature, nil +} + +func (ke *KeyExchange) sendMessageToProvider(ctx context.Context, provider p2p.Peer, ekmWithSignature *EKMWithSignature) error { + stream, err := ke.streamer.NewStream( + ctx, + provider, + ProtocolName, + ProtocolVersion, + ProtocolHandlerName, + ) + + if err != nil { + return fmt.Errorf("failed to create new stream to provider %s: %w", provider.EthAddress, err) + } + defer stream.Close() + + _, w := msgpack.NewReaderWriter[EKMWithSignature, EKMWithSignature](stream) + err = w.WriteMsg(ctx, ekmWithSignature) + if err != nil { + _ = stream.Reset() + return fmt.Errorf("failed to send message to provider %s: %w", provider.EthAddress, err) + } + + return nil +} + +func (ke *KeyExchange) handleTimestampMessage(ctx context.Context, peer p2p.Peer, stream p2p.Stream) error { + ekmWithSignature, err := ke.readAndVerifyMessage(ctx, peer, stream) + if err != nil { + return fmt.Errorf("read and verify message failed: %w", err) + } + + message, aesKey, err := ke.decryptMessage(ekmWithSignature) + if err != nil { + return fmt.Errorf("decrypt message failed: %w", err) + } + + if err := ke.validateAndProcessTimestamp(message); err != nil { + return fmt.Errorf("validate and process timestamp failed: %w", err) + } + + ke.keyKeeper.(*keykeeper.ProviderKeyKeeper).BiddersAESKeys[peer.EthAddress] = aesKey + + return nil +} + +func (ke *KeyExchange) readAndVerifyMessage(ctx context.Context, peer p2p.Peer, stream p2p.Stream) (*EKMWithSignature, error) { + if peer.Type != p2p.PeerTypeBidder { + return nil, ErrInvalidBidderTypeForMessage + } + + r, _ := msgpack.NewReaderWriter[EKMWithSignature, EKMWithSignature](stream) + + ekmWithSignature, err := r.ReadMsg(ctx) + if err != nil { + return nil, err + } + + err = ke.verifySignature(peer, ekmWithSignature) + if err != nil { + return nil, fmt.Errorf("verification failed: %w", err) + } + + return ekmWithSignature, nil +} + +func (ke *KeyExchange) verifySignature(peer p2p.Peer, ekm *EKMWithSignature) error { + verified, ethAddress, err := ke.signer.Verify(ekm.Signature, ekm.Message) + if err != nil { + return errors.Join(err, ErrSignatureVerificationFailed) + } + + if !verified { + return ErrSignatureVerificationFailed + } + + if !bytes.Equal(peer.EthAddress.Bytes(), ethAddress.Bytes()) { + return ErrObservedAddressMismatch + } + + return nil +} + +func (ke *KeyExchange) decryptMessage(ekmWithSignature *EKMWithSignature) ([]byte, []byte, error) { + var ( + aesKey []byte + decrypted bool + err error + message EncryptedKeysMessage + ) + + err = json.Unmarshal(ekmWithSignature.Message, &message) + if err != nil { + return nil, nil, fmt.Errorf("failed to unmarshal message: %w", err) + } + + providerKK := ke.keyKeeper.(*keykeeper.ProviderKeyKeeper) + + for i := 0; i < len(message.EncryptedKeys); i++ { + aesKey, err = providerKK.DecryptWithECIES(message.EncryptedKeys[i]) + if err == nil { + decrypted = true + break // Successfully decrypted AES key, stop trying further keys + } + } + + if !decrypted { + return nil, nil, fmt.Errorf("none of the AES keys could be decrypted") + } + + encryptedMessage := message.TimestampMessage + decryptedMessage, err := keykeeper.DecryptWithAESGCM(aesKey, encryptedMessage) + if err != nil { + return nil, nil, fmt.Errorf("failed to decrypt message: %w", err) + } + + return decryptedMessage, aesKey, nil +} + +func (ke *KeyExchange) validateAndProcessTimestamp(message []byte) error { + _, timestamp, err := parseTimestampMessage(string(message)) + if err != nil { + return fmt.Errorf("failed to parse message: %w", err) + } + + if !isTimestampRecent(timestamp) { + return fmt.Errorf("the timestamp is more than 1 minute old") + } + + return nil +} diff --git a/pkg/keyexchange/keyexchange_test.go b/pkg/keyexchange/keyexchange_test.go new file mode 100644 index 00000000..b386c28c --- /dev/null +++ b/pkg/keyexchange/keyexchange_test.go @@ -0,0 +1,106 @@ +package keyexchange_test + +import ( + "bytes" + "io" + "os" + "testing" + "time" + + "log/slog" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/primevprotocol/mev-commit/pkg/keyexchange" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" + mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" + "github.com/primevprotocol/mev-commit/pkg/p2p" + p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" + "github.com/primevprotocol/mev-commit/pkg/signer" + "github.com/primevprotocol/mev-commit/pkg/topology" +) + +type testTopology struct { + peers []p2p.Peer +} + +func (tt *testTopology) GetPeers(q topology.Query) []p2p.Peer { + return tt.peers +} + +func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { + t.Helper() + + testLogger := slog.NewTextHandler(w, &slog.HandlerOptions{ + Level: slog.LevelDebug, + }) + return slog.New(testLogger) +} + +func TestKeyExchange_SendAndHandleTimestampMessage(t *testing.T) { + t.Parallel() + + privKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + ks := mockkeysigner.NewMockKeySigner(privKey, address) + bidderKK, err := keykeeper.NewBidderKeyKeeper(ks) + if err != nil { + t.Fatalf("Failed to create BidderKeyKeeper: %v", err) + } + + providerKK, err := keykeeper.NewProviderKeyKeeper(ks) + if err != nil { + t.Fatalf("Failed to create ProviderKeyKeeper: %v", err) + } + + bidderPeer := p2p.Peer{ + EthAddress: bidderKK.KeySigner.GetAddress(), + Type: p2p.PeerTypeBidder, + } + + providerPeer := p2p.Peer{ + EthAddress: providerKK.KeySigner.GetAddress(), + Type: p2p.PeerTypeProvider, + Keys: &p2p.Keys{PKEPublicKey: providerKK.GetECIESPublicKey(), NIKEPublicKey: providerKK.GetNIKEPublicKey()}, + } + topo1 := &testTopology{peers: []p2p.Peer{providerPeer}} + topo2 := &testTopology{peers: []p2p.Peer{bidderPeer}} + + logger := newTestLogger(t, os.Stdout) + + signer := signer.New() + svc1 := p2ptest.New( + &bidderPeer, + ) + + svc2 := p2ptest.New( + &providerPeer, + ) + + ke1 := keyexchange.New(topo1, svc1, bidderKK, logger, signer) + ke2 := keyexchange.New(topo2, svc2, providerKK, logger, signer) + + svc1.SetPeerHandler(bidderPeer, ke2.Protocol()) + + err = ke1.SendTimestampMessage() + if err != nil { + t.Fatalf("SendTimestampMessage failed: %v", err) + } + + start := time.Now() + for { + if time.Since(start) > 5*time.Second { + t.Fatal("timed out") + } + if _, exists := providerKK.BiddersAESKeys[bidderPeer.EthAddress]; exists { + aesKey := providerKK.BiddersAESKeys[bidderPeer.EthAddress] + if !bytes.Equal(bidderKK.AESKey, aesKey) { + t.Fatal("AES keys are not equal") + } + break + } + time.Sleep(100 * time.Millisecond) + } +} diff --git a/pkg/keyexchange/models.go b/pkg/keyexchange/models.go new file mode 100644 index 00000000..12fdfa7c --- /dev/null +++ b/pkg/keyexchange/models.go @@ -0,0 +1,52 @@ +package keyexchange + +import ( + "errors" + "log/slog" + + "github.com/primevprotocol/mev-commit/pkg/keykeeper" + "github.com/primevprotocol/mev-commit/pkg/p2p" + "github.com/primevprotocol/mev-commit/pkg/signer" + "github.com/primevprotocol/mev-commit/pkg/topology" +) + +// Protocol constants. +const ( + ProtocolName = "keyexchange" + ProtocolHandlerName = "timestampMessage" + ProtocolVersion = "1.0.0" +) + +// Error declarations. +var ( + ErrSignatureVerificationFailed = errors.New("signature verification failed") + ErrObservedAddressMismatch = errors.New("observed address mismatch") + ErrInvalidBidderTypeForMessage = errors.New("invalid bidder type for message") + ErrNoProvidersAvailable = errors.New("no providers available") +) + +// KeyExchange manages the key exchange process. +type KeyExchange struct { + keyKeeper keykeeper.KeyKeeper + topo Topology + streamer p2p.Streamer + signer signer.Signer + logger *slog.Logger +} + +// EncryptedKeysMessage represents a message containing encrypted keys. +type EncryptedKeysMessage struct { + EncryptedKeys [][]byte `json:"encryptedKeys"` + TimestampMessage []byte `json:"timestampMessage"` +} + +// EKMWithSignature wraps a message and its signature. +type EKMWithSignature struct { + Message []byte `json:"message"` + Signature []byte `json:"signature"` +} + +// Topology interface to get peers. +type Topology interface { + GetPeers(topology.Query) []p2p.Peer +} diff --git a/pkg/keyexchange/util.go b/pkg/keyexchange/util.go new file mode 100644 index 00000000..2631061f --- /dev/null +++ b/pkg/keyexchange/util.go @@ -0,0 +1,37 @@ +package keyexchange + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func hashData(data []byte) common.Hash { + hash := crypto.Keccak256Hash(data) + return hash +} + +func parseTimestampMessage(msg string) (string, int64, error) { + parts := strings.Fields(msg) + if len(parts) != 5 || parts[0] != "mev-commit" || parts[1] != "bidder" || parts[3] != "setup" { + return "", 0, fmt.Errorf("message format is incorrect") + } + address := parts[2] + timestamp, err := strconv.ParseInt(parts[4], 10, 64) + if err != nil { + return "", 0, fmt.Errorf("invalid timestamp") + } + + return address, timestamp, nil +} + +func isTimestampRecent(timestamp int64) bool { + currentTime := time.Now().Unix() + difference := currentTime - timestamp + + return difference <= 60 +} diff --git a/pkg/keykeeper/aescrypto.go b/pkg/keykeeper/aescrypto.go new file mode 100644 index 00000000..337ad28e --- /dev/null +++ b/pkg/keykeeper/aescrypto.go @@ -0,0 +1,50 @@ +package keykeeper + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" +) + +func generateAESKey() ([]byte, error) { + aesKey := make([]byte, 32) // AES-256 + _, err := rand.Read(aesKey) + if err != nil { + return nil, err + } + return aesKey, nil +} + +func EncryptWithAESGCM(aesKey, plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher(aesKey) + if err != nil { + return nil, err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + nonce := make([]byte, aesgcm.NonceSize()) + if _, err := rand.Read(nonce); err != nil { + return nil, err + } + ciphertext := aesgcm.Seal(nonce, nonce, plaintext, nil) + return ciphertext, nil +} + +func DecryptWithAESGCM(aesKey, ciphertext []byte) ([]byte, error) { + block, err := aes.NewCipher(aesKey) + if err != nil { + return nil, err + } + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + nonce := ciphertext[:aesgcm.NonceSize()] + plaintext, err := aesgcm.Open(nil, nonce, ciphertext[aesgcm.NonceSize():], nil) + if err != nil { + return nil, err + } + return plaintext, nil +} diff --git a/pkg/keykeeper/keykeeper.go b/pkg/keykeeper/keykeeper.go new file mode 100644 index 00000000..b06e4bbf --- /dev/null +++ b/pkg/keykeeper/keykeeper.go @@ -0,0 +1,60 @@ +package keykeeper + +import ( + "crypto/ecdh" + "crypto/elliptic" + "crypto/rand" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" +) + +func NewBidderKeyKeeper(keysigner keysigner.KeySigner) (*BidderKeyKeeper, error) { + aesKey, err := generateAESKey() + if err != nil { + return nil, err + } + + return &BidderKeyKeeper{ + KeySigner: keysigner, + AESKey: aesKey, + }, nil +} + +func NewProviderKeyKeeper(keysigner keysigner.KeySigner) (*ProviderKeyKeeper, error) { + biddersAESKeys := make(map[common.Address][]byte) + + encryptionPrivateKey, err := ecies.GenerateKey(rand.Reader, elliptic.P256(), nil) + if err != nil { + return nil, err + } + + nikePrivateKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return nil, err + } + + return &ProviderKeyKeeper{ + KeySigner: keysigner, + BiddersAESKeys: biddersAESKeys, + keys: ProviderKeys{ + EncryptionPrivateKey: encryptionPrivateKey, + EncryptionPublicKey: &encryptionPrivateKey.PublicKey, + NIKEPrivateKey: nikePrivateKey, + NIKEPublicKey: nikePrivateKey.PublicKey(), + }, + }, nil +} + +func (pkk *ProviderKeyKeeper) GetNIKEPublicKey() *ecdh.PublicKey { + return pkk.keys.NIKEPublicKey +} + +func (pkk *ProviderKeyKeeper) GetECIESPublicKey() *ecies.PublicKey { + return pkk.keys.EncryptionPublicKey +} + +func (pkk *ProviderKeyKeeper) DecryptWithECIES(message []byte) ([]byte, error) { + return pkk.keys.EncryptionPrivateKey.Decrypt(message, nil, nil) +} diff --git a/pkg/keysigner/keysigner.go b/pkg/keykeeper/keysigner/keysigner.go similarity index 100% rename from pkg/keysigner/keysigner.go rename to pkg/keykeeper/keysigner/keysigner.go diff --git a/pkg/keysigner/keystoresigner.go b/pkg/keykeeper/keysigner/keystoresigner.go similarity index 100% rename from pkg/keysigner/keystoresigner.go rename to pkg/keykeeper/keysigner/keystoresigner.go diff --git a/pkg/keysigner/mock/mock.go b/pkg/keykeeper/keysigner/mock/mock.go similarity index 100% rename from pkg/keysigner/mock/mock.go rename to pkg/keykeeper/keysigner/mock/mock.go diff --git a/pkg/keysigner/privatekeysigner.go b/pkg/keykeeper/keysigner/privatekeysigner.go similarity index 100% rename from pkg/keysigner/privatekeysigner.go rename to pkg/keykeeper/keysigner/privatekeysigner.go diff --git a/pkg/keykeeper/models.go b/pkg/keykeeper/models.go new file mode 100644 index 00000000..e67a03ab --- /dev/null +++ b/pkg/keykeeper/models.go @@ -0,0 +1,29 @@ +package keykeeper + +import ( + "crypto/ecdh" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" +) + +type KeyKeeper interface{} + +type ProviderKeys struct { + EncryptionPrivateKey *ecies.PrivateKey + EncryptionPublicKey *ecies.PublicKey + NIKEPrivateKey *ecdh.PrivateKey + NIKEPublicKey *ecdh.PublicKey +} + +type ProviderKeyKeeper struct { + keys ProviderKeys + KeySigner keysigner.KeySigner + BiddersAESKeys map[common.Address][]byte +} + +type BidderKeyKeeper struct { + AESKey []byte + KeySigner keysigner.KeySigner +} diff --git a/pkg/node/node.go b/pkg/node/node.go index f5bb174b..7801e02b 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -25,12 +25,15 @@ import ( "github.com/primevprotocol/mev-commit/pkg/debugapi" "github.com/primevprotocol/mev-commit/pkg/discovery" "github.com/primevprotocol/mev-commit/pkg/evmclient" - "github.com/primevprotocol/mev-commit/pkg/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keyexchange" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/libp2p" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" providerapi "github.com/primevprotocol/mev-commit/pkg/rpc/provider" + "github.com/primevprotocol/mev-commit/pkg/signer" "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" "github.com/primevprotocol/mev-commit/pkg/topology" "google.golang.org/grpc" @@ -201,6 +204,19 @@ func NewNode(opts *Options) (*Node, error) { ) // Only register handler for provider p2pSvc.AddProtocol(preconfProto.Protocol()) + + providerKK, err := keykeeper.NewProviderKeyKeeper(opts.KeySigner) + if err != nil { + return nil, errors.Join(err, nd.Close()) + } + keyexchange := keyexchange.New( + topo, + p2pSvc, + providerKK, + opts.Logger.With("component", "keyexchange_protocol"), + signer.New(), + ) + p2pSvc.AddProtocol(keyexchange.Protocol()) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) case p2p.PeerTypeBidder.String(): @@ -223,6 +239,20 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "bidderapi"), ) bidderapiv1.RegisterBidderServer(grpcServer, bidderAPI) + + bidderKK, err := keykeeper.NewBidderKeyKeeper(opts.KeySigner) + if err != nil { + return nil, errors.Join(err, nd.Close()) + } + keyexchange := keyexchange.New( + topo, + p2pSvc, + bidderKK, + opts.Logger.With("component", "keyexchange_protocol"), + signer.New(), + ) + keyexchange.SendTimestampMessage() + srv.RegisterMetricsCollectors(bidderAPI.Metrics()...) } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index 2f1b9ab9..df199590 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/protocol" - "github.com/primevprotocol/mev-commit/pkg/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/msgpack" "github.com/primevprotocol/mev-commit/pkg/signer" diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index f3768096..35cb881b 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/libp2p/go-libp2p/core" - mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keysigner/mock" + mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/libp2p/internal/handshake" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index d3fdcdf9..0d076703 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -11,7 +11,7 @@ import ( ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" - "github.com/primevprotocol/mev-commit/pkg/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" "github.com/primevprotocol/mev-commit/pkg/util" "github.com/ethereum/go-ethereum/common" diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index f0c7ca04..d6832922 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core/peer" - mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keysigner/mock" + mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/libp2p" ) diff --git a/pkg/p2p/p2p.go b/pkg/p2p/p2p.go index 4843657c..21100371 100644 --- a/pkg/p2p/p2p.go +++ b/pkg/p2p/p2p.go @@ -2,10 +2,12 @@ package p2p import ( "context" + "crypto/ecdh" "errors" "io" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/ecies" ) // PeerType is the type of a peer @@ -51,9 +53,15 @@ var ( ErrNoAddresses = errors.New("no addresses") ) +type Keys struct { + PKEPublicKey *ecies.PublicKey + NIKEPublicKey *ecdh.PublicKey +} + type Peer struct { EthAddress common.Address Type PeerType + Keys *Keys } type PeerInfo struct { diff --git a/pkg/signer/preconfsigner/signer.go b/pkg/signer/preconfsigner/signer.go index bb5e8f41..865c1469 100644 --- a/pkg/signer/preconfsigner/signer.go +++ b/pkg/signer/preconfsigner/signer.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/primevprotocol/mev-commit/pkg/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" ) var ( diff --git a/pkg/signer/preconfsigner/signer_test.go b/pkg/signer/preconfsigner/signer_test.go index 1df3e44f..6a56db9d 100644 --- a/pkg/signer/preconfsigner/signer_test.go +++ b/pkg/signer/preconfsigner/signer_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/crypto" - mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keysigner/mock" + mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" "github.com/stretchr/testify/assert" ) From 1887eb82134cc2cf7895c0cfc8a92edfe7bbaf27 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 13 Mar 2024 21:13:59 +0800 Subject: [PATCH 02/85] added pub keys to handshake and keykeeper init in node --- pkg/keykeeper/{aescrypto.go => aes.go} | 0 pkg/keykeeper/ecies.go | 25 +++++++++ pkg/keykeeper/keykeeper.go | 55 +++++++++++++++++++ pkg/keykeeper/models.go | 12 +++- pkg/node/node.go | 29 ++++++---- .../libp2p/internal/handshake/handshake.go | 48 +++++++++++++--- .../internal/handshake/handshake_test.go | 23 ++++++-- pkg/p2p/libp2p/libp2p.go | 10 ++-- pkg/p2p/libp2p/libp2p_test.go | 15 +++-- 9 files changed, 184 insertions(+), 33 deletions(-) rename pkg/keykeeper/{aescrypto.go => aes.go} (100%) create mode 100644 pkg/keykeeper/ecies.go diff --git a/pkg/keykeeper/aescrypto.go b/pkg/keykeeper/aes.go similarity index 100% rename from pkg/keykeeper/aescrypto.go rename to pkg/keykeeper/aes.go diff --git a/pkg/keykeeper/ecies.go b/pkg/keykeeper/ecies.go new file mode 100644 index 00000000..74b67dba --- /dev/null +++ b/pkg/keykeeper/ecies.go @@ -0,0 +1,25 @@ +package keykeeper + +import ( + "crypto/elliptic" + "errors" + + "github.com/ethereum/go-ethereum/crypto/ecies" +) + +func SerializePublicKey(pub *ecies.PublicKey) []byte { + return elliptic.MarshalCompressed(elliptic.P256(), pub.X, pub.Y) +} + +func DeserializePublicKey(data []byte) (*ecies.PublicKey, error) { + x, y := elliptic.UnmarshalCompressed(elliptic.P256(), data) + if x == nil { + return nil, errors.New("invalid public key") + } + return &ecies.PublicKey{ + X: x, + Y: y, + Curve: elliptic.P256(), + Params: ecies.ECIES_AES128_SHA256, + }, nil +} diff --git a/pkg/keykeeper/keykeeper.go b/pkg/keykeeper/keykeeper.go index b06e4bbf..30ed0b4c 100644 --- a/pkg/keykeeper/keykeeper.go +++ b/pkg/keykeeper/keykeeper.go @@ -2,6 +2,7 @@ package keykeeper import ( "crypto/ecdh" + "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -22,6 +23,22 @@ func NewBidderKeyKeeper(keysigner keysigner.KeySigner) (*BidderKeyKeeper, error) }, nil } +func (bkk *BidderKeyKeeper) SignHash(data []byte) ([]byte, error) { + return bkk.KeySigner.SignHash(data) +} + +func (bkk *BidderKeyKeeper) GetAddress() common.Address { + return bkk.KeySigner.GetAddress() +} + +func (bkk *BidderKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { + return bkk.KeySigner.GetPrivateKey() +} + +func (bkk *BidderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { + bkk.KeySigner.ZeroPrivateKey(key) +} + func NewProviderKeyKeeper(keysigner keysigner.KeySigner) (*ProviderKeyKeeper, error) { biddersAESKeys := make(map[common.Address][]byte) @@ -58,3 +75,41 @@ func (pkk *ProviderKeyKeeper) GetECIESPublicKey() *ecies.PublicKey { func (pkk *ProviderKeyKeeper) DecryptWithECIES(message []byte) ([]byte, error) { return pkk.keys.EncryptionPrivateKey.Decrypt(message, nil, nil) } + +func (pkk *ProviderKeyKeeper) SignHash(data []byte) ([]byte, error) { + return pkk.KeySigner.SignHash(data) +} + +func (pkk *ProviderKeyKeeper) GetAddress() common.Address { + return pkk.KeySigner.GetAddress() +} + +func (pkk *ProviderKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { + return pkk.KeySigner.GetPrivateKey() +} + +func (pkk *ProviderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { + pkk.KeySigner.ZeroPrivateKey(key) +} + +func NewBootnodeKeyKeeper(keysigner keysigner.KeySigner) *BootnodeKeyKeeper { + return &BootnodeKeyKeeper{ + KeySigner: keysigner, + } +} + +func (btkk *BootnodeKeyKeeper) SignHash(data []byte) ([]byte, error) { + return btkk.KeySigner.SignHash(data) +} + +func (btkk *BootnodeKeyKeeper) GetAddress() common.Address { + return btkk.KeySigner.GetAddress() +} + +func (btkk *BootnodeKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { + return btkk.KeySigner.GetPrivateKey() +} + +func (btkk *BootnodeKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { + btkk.KeySigner.ZeroPrivateKey(key) +} diff --git a/pkg/keykeeper/models.go b/pkg/keykeeper/models.go index e67a03ab..4e9ab151 100644 --- a/pkg/keykeeper/models.go +++ b/pkg/keykeeper/models.go @@ -2,13 +2,19 @@ package keykeeper import ( "crypto/ecdh" + "crypto/ecdsa" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" ) -type KeyKeeper interface{} +type KeyKeeper interface { + SignHash(data []byte) ([]byte, error) + GetAddress() common.Address + GetPrivateKey() (*ecdsa.PrivateKey, error) + ZeroPrivateKey(key *ecdsa.PrivateKey) +} type ProviderKeys struct { EncryptionPrivateKey *ecies.PrivateKey @@ -27,3 +33,7 @@ type BidderKeyKeeper struct { AESKey []byte KeySigner keysigner.KeySigner } + +type BootnodeKeyKeeper struct { + KeySigner keysigner.KeySigner +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 7801e02b..8ab41a8a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -110,8 +110,23 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "providerregistry"), ) + var keyKeeper keykeeper.KeyKeeper + switch opts.PeerType { + case p2p.PeerTypeProvider.String(): + keyKeeper, err = keykeeper.NewBidderKeyKeeper(opts.KeySigner) + if err != nil { + return nil, errors.Join(err, nd.Close()) + } + case p2p.PeerTypeBidder.String(): + keyKeeper, err = keykeeper.NewProviderKeyKeeper(opts.KeySigner) + if err != nil { + return nil, errors.Join(err, nd.Close()) + } + default: + keyKeeper = keykeeper.NewBootnodeKeyKeeper(opts.KeySigner) + } p2pSvc, err := libp2p.New(&libp2p.Options{ - KeySigner: opts.KeySigner, + KeyKeeper: keyKeeper, Secret: opts.Secret, PeerType: peerType, Register: providerRegistry, @@ -205,14 +220,10 @@ func NewNode(opts *Options) (*Node, error) { // Only register handler for provider p2pSvc.AddProtocol(preconfProto.Protocol()) - providerKK, err := keykeeper.NewProviderKeyKeeper(opts.KeySigner) - if err != nil { - return nil, errors.Join(err, nd.Close()) - } keyexchange := keyexchange.New( topo, p2pSvc, - providerKK, + keyKeeper, opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) @@ -240,14 +251,10 @@ func NewNode(opts *Options) (*Node, error) { ) bidderapiv1.RegisterBidderServer(grpcServer, bidderAPI) - bidderKK, err := keykeeper.NewBidderKeyKeeper(opts.KeySigner) - if err != nil { - return nil, errors.Join(err, nd.Close()) - } keyexchange := keyexchange.New( topo, p2pSvc, - bidderKK, + keyKeeper, opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index df199590..b8ac23d1 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -3,13 +3,14 @@ package handshake import ( "bytes" "context" + "crypto/ecdh" "errors" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/protocol" - "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/msgpack" "github.com/primevprotocol/mev-commit/pkg/signer" @@ -33,7 +34,7 @@ type ProviderRegistry interface { // Handshake is the handshake protocol type Service struct { - ks keysigner.KeySigner + kk keykeeper.KeyKeeper peerType p2p.PeerType passcode string signer signer.Signer @@ -43,7 +44,7 @@ type Service struct { } func New( - ks keysigner.KeySigner, + kk keykeeper.KeyKeeper, peerType p2p.PeerType, passcode string, signer signer.Signer, @@ -51,7 +52,7 @@ func New( getEthAddress func(core.PeerID) (common.Address, error), ) (*Service, error) { s := &Service{ - ks: ks, + kk: kk, peerType: peerType, passcode: passcode, signer: signer, @@ -75,10 +76,15 @@ func ProtocolID() protocol.ID { )) } +type SerializedKeys struct { + PKEPublicKey, NIKEPublicKey []byte +} + type HandshakeReq struct { PeerType string Token string Sig []byte + Keys *SerializedKeys } type HandshakeResp struct { @@ -122,7 +128,7 @@ func (h *Service) verifyReq( func (h *Service) createSignature() ([]byte, error) { unsignedData := []byte(h.peerType.String() + h.passcode) hash := crypto.Keccak256Hash(unsignedData) - sig, err := h.ks.SignHash(hash.Bytes()) + sig, err := h.kk.SignHash(hash.Bytes()) if err != nil { return nil, err } @@ -142,12 +148,22 @@ func (h *Service) setHandshakeReq() error { Sig: sig, } + if h.peerType == p2p.PeerTypeProvider { + providerKK := h.kk.(*keykeeper.ProviderKeyKeeper) + ppk := keykeeper.SerializePublicKey(providerKK.GetECIESPublicKey()) + npk := providerKK.GetNIKEPublicKey().Bytes() + req.Keys = &SerializedKeys{ + PKEPublicKey: ppk, + NIKEPublicKey: npk, + } + } + h.handshakeReq = req return nil } func (h *Service) verifyResp(resp *HandshakeResp) error { - if !bytes.Equal(resp.ObservedAddress.Bytes(), h.ks.GetAddress().Bytes()) { + if !bytes.Equal(resp.ObservedAddress.Bytes(), h.kk.GetAddress().Bytes()) { return errors.New("observed address mismatch") } @@ -200,10 +216,26 @@ func (h *Service) Handle( return p2p.Peer{}, err } - return p2p.Peer{ + p := p2p.Peer{ EthAddress: ethAddress, Type: p2p.FromString(req.PeerType), - }, nil + } + + if req.PeerType == p2p.PeerTypeProvider.String() { + ppk, err := keykeeper.DeserializePublicKey(req.Keys.PKEPublicKey) + if err != nil { + return p2p.Peer{}, err + } + npk, err := ecdh.P256().NewPublicKey(req.Keys.NIKEPublicKey) + if err != nil { + return p2p.Peer{}, err + } + p.Keys = &p2p.Keys{ + PKEPublicKey: ppk, + NIKEPublicKey: npk, + } + } + return p, nil } func (h *Service) Handshake( diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 35cb881b..3047f5b6 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/libp2p/go-libp2p/core" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/libp2p/internal/handshake" @@ -46,7 +47,10 @@ func TestHandshake(t *testing.T) { } address1 := common.HexToAddress("0x1") ks1 := mockkeysigner.NewMockKeySigner(privKey1, address1) - + kk1, err := keykeeper.NewProviderKeyKeeper(ks1) + if err != nil { + t.Fatal(err) + } privKey2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) @@ -54,9 +58,12 @@ func TestHandshake(t *testing.T) { address2 := common.HexToAddress("0x2") ks2 := mockkeysigner.NewMockKeySigner(privKey2, address2) - + kk2, err := keykeeper.NewProviderKeyKeeper(ks2) + if err != nil { + t.Fatal(err) + } hs1, err := handshake.New( - ks1, + kk1, p2p.PeerTypeProvider, "test", &testSigner{address: address2}, @@ -70,7 +77,7 @@ func TestHandshake(t *testing.T) { } hs2, err := handshake.New( - ks2, + kk2, p2p.PeerTypeProvider, "test", &testSigner{address: address1}, @@ -105,6 +112,14 @@ func TestHandshake(t *testing.T) { t.Errorf("expected peer type %s, got %s", p2p.PeerTypeProvider, p.Type) return } + if !p.Keys.NIKEPublicKey.Equal(kk2.GetNIKEPublicKey()) { + t.Errorf("expected nike pk %s, got %s", p.Keys.NIKEPublicKey.Bytes(), kk2.GetNIKEPublicKey().Bytes()) + return + } + if !p.Keys.PKEPublicKey.ExportECDSA().Equal(kk2.GetECIESPublicKey().ExportECDSA()) { + t.Error("expected pke pk is not equal to present") + return + } }() p, err := hs2.Handshake(context.Background(), core.PeerID("test1"), out) diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 0d076703..9203725e 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -11,7 +11,7 @@ import ( ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" - "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" "github.com/primevprotocol/mev-commit/pkg/util" "github.com/ethereum/go-ethereum/common" @@ -55,7 +55,7 @@ type ProviderRegistry interface { } type Options struct { - KeySigner keysigner.KeySigner + KeyKeeper keykeeper.KeyKeeper Secret string PeerType p2p.PeerType Register handshake.ProviderRegistry @@ -68,11 +68,11 @@ type Options struct { } func New(opts *Options) (*Service, error) { - privKey, err := opts.KeySigner.GetPrivateKey() + privKey, err := opts.KeyKeeper.GetPrivateKey() if err != nil { return nil, fmt.Errorf("failed to get priv key: %w", err) } - defer opts.KeySigner.ZeroPrivateKey(privKey) + defer opts.KeyKeeper.ZeroPrivateKey(privKey) padded32BytePrivKey := util.PadKeyTo32Bytes(privKey.D) libp2pKey, err := libp2pcrypto.UnmarshalSecp256k1PrivateKey(padded32BytePrivKey) @@ -160,7 +160,7 @@ func New(opts *Options) (*Service, error) { } hsSvc, err := handshake.New( - opts.KeySigner, + opts.KeyKeeper, opts.PeerType, opts.Secret, signer.New(), diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index d6832922..2fe9ac17 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core/peer" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/libp2p" @@ -45,8 +46,12 @@ func newTestService(t *testing.T) *libp2p.Service { } address := crypto.PubkeyToAddress(privKey.PublicKey) ks := mockkeysigner.NewMockKeySigner(privKey, address) + pkk, err := keykeeper.NewProviderKeyKeeper(ks) + if err != nil { + t.Fatal(err) + } svc, err := libp2p.New(&libp2p.Options{ - KeySigner: ks, + KeyKeeper: pkk, Secret: "test", ListenPort: 0, ListenAddr: "0.0.0.0", @@ -247,7 +252,7 @@ func TestBootstrap(t *testing.T) { ks := mockkeysigner.NewMockKeySigner(privKey, address) bnOpts := testDefaultOptions - bnOpts.KeySigner = ks + bnOpts.KeyKeeper = keykeeper.NewBootnodeKeyKeeper(ks) bnOpts.PeerType = p2p.PeerTypeBootnode bootnode, err := libp2p.New(&bnOpts) @@ -268,8 +273,10 @@ func TestBootstrap(t *testing.T) { n1Opts := testDefaultOptions n1Opts.BootstrapAddrs = []string{bootnode.AddrString()} - n1Opts.KeySigner = ks - + n1Opts.KeyKeeper, err = keykeeper.NewProviderKeyKeeper(ks) + if err != nil { + t.Fatal(err) + } p1, err := libp2p.New(&n1Opts) if err != nil { t.Fatal(err) From 6671e34ec14f748691385ee2111ab1c0931e5c4b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 14 Mar 2024 13:30:56 +0800 Subject: [PATCH 03/85] signer -> encryptor --- pkg/node/node.go | 10 +++--- pkg/preconfirmation/preconfirmation.go | 26 +++++++-------- pkg/preconfirmation/preconfirmation_test.go | 20 ++++++------ pkg/rpc/bidder/service.go | 4 +-- pkg/rpc/bidder/service_test.go | 10 +++--- pkg/rpc/provider/service.go | 4 +-- pkg/rpc/provider/service_test.go | 16 +++++----- .../encryptor.go} | 32 +++++++++---------- .../encryptor_test.go} | 28 ++++++++-------- .../export_test.go | 8 ++--- 10 files changed, 79 insertions(+), 79 deletions(-) rename pkg/signer/{preconfsigner/signer.go => preconfencryptor/encryptor.go} (92%) rename pkg/signer/{preconfsigner/signer_test.go => preconfencryptor/encryptor_test.go} (82%) rename pkg/signer/{preconfsigner => preconfencryptor}/export_test.go (82%) diff --git a/pkg/node/node.go b/pkg/node/node.go index 8ab41a8a..a79fbac6 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -34,7 +34,7 @@ import ( bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" providerapi "github.com/primevprotocol/mev-commit/pkg/rpc/provider" "github.com/primevprotocol/mev-commit/pkg/signer" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -176,7 +176,7 @@ func NewNode(opts *Options) (*Node, error) { } grpcServer := grpc.NewServer(grpc.Creds(tlsCredentials)) - preconfSigner := preconfsigner.NewSigner(opts.KeySigner) + preconfEncryptor := preconfencryptor.NewEncryptor(opts.KeySigner) validator, err := protovalidate.New() if err != nil { return nil, errors.Join(err, nd.Close()) @@ -211,7 +211,7 @@ func NewNode(opts *Options) (*Node, error) { preconfProto := preconfirmation.New( topo, p2pSvc, - preconfSigner, + preconfEncryptor, bidderRegistry, bidProcessor, commitmentDA, @@ -234,7 +234,7 @@ func NewNode(opts *Options) (*Node, error) { preconfProto := preconfirmation.New( topo, p2pSvc, - preconfSigner, + preconfEncryptor, bidderRegistry, bidProcessor, commitmentDA, @@ -393,7 +393,7 @@ type noOpBidProcessor struct{} // ProcessBid auto accepts all bids sent. func (noOpBidProcessor) ProcessBid( _ context.Context, - _ *preconfsigner.Bid, + _ *preconfencryptor.Bid, ) (chan providerapiv1.BidResponse_Status, error) { statusC := make(chan providerapiv1.BidResponse_Status, 5) statusC <- providerapiv1.BidResponse_STATUS_ACCEPTED diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index eabe4d5a..5b7df9c9 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -13,7 +13,7 @@ import ( preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/p2p/msgpack" - signer "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" ) @@ -23,7 +23,7 @@ const ( ) type Preconfirmation struct { - signer signer.Signer + encryptor encryptor.Encryptor topo Topology streamer p2p.Streamer us BidderStore @@ -42,13 +42,13 @@ type BidderStore interface { } type BidProcessor interface { - ProcessBid(context.Context, *signer.Bid) (chan providerapiv1.BidResponse_Status, error) + ProcessBid(context.Context, *encryptor.Bid) (chan providerapiv1.BidResponse_Status, error) } func New( topo Topology, streamer p2p.Streamer, - signer signer.Signer, + encryptor encryptor.Encryptor, us BidderStore, processor BidProcessor, commitmentDA preconfcontract.Interface, @@ -57,7 +57,7 @@ func New( return &Preconfirmation{ topo: topo, streamer: streamer, - signer: signer, + encryptor: encryptor, us: us, processer: processor, commitmentDA: commitmentDA, @@ -88,8 +88,8 @@ func (p *Preconfirmation) SendBid( txHash string, bidAmt *big.Int, blockNumber *big.Int, -) (chan *signer.PreConfirmation, error) { - signedBid, err := p.signer.ConstructSignedBid(txHash, bidAmt, blockNumber) +) (chan *encryptor.PreConfirmation, error) { + signedBid, err := p.encryptor.ConstructSignedBid(txHash, bidAmt, blockNumber) if err != nil { p.logger.Error("constructing signed bid", "error", err, "txHash", txHash) return nil, err @@ -103,7 +103,7 @@ func (p *Preconfirmation) SendBid( } // Create a new channel to receive preConfirmations - preConfirmations := make(chan *signer.PreConfirmation, len(providers)) + preConfirmations := make(chan *encryptor.PreConfirmation, len(providers)) wg := sync.WaitGroup{} for idx := range providers { @@ -127,7 +127,7 @@ func (p *Preconfirmation) SendBid( logger.Info("sending signed bid", "signedBid", signedBid) - r, w := msgpack.NewReaderWriter[signer.PreConfirmation, signer.Bid](providerStream) + r, w := msgpack.NewReaderWriter[encryptor.PreConfirmation, encryptor.Bid](providerStream) err = w.WriteMsg(ctx, signedBid) if err != nil { _ = providerStream.Reset() @@ -146,7 +146,7 @@ func (p *Preconfirmation) SendBid( _ = providerStream.Close() // Process preConfirmation as a bidder - providerAddress, err := p.signer.VerifyPreConfirmation(preConfirmation) + providerAddress, err := p.encryptor.VerifyPreConfirmation(preConfirmation) if err != nil { logger.Error("verifying provider signature", "error", err) return @@ -185,7 +185,7 @@ func (p *Preconfirmation) handleBid( return ErrInvalidBidderTypeForBid } - r, w := msgpack.NewReaderWriter[signer.Bid, signer.PreConfirmation](stream) + r, w := msgpack.NewReaderWriter[encryptor.Bid, encryptor.PreConfirmation](stream) bid, err := r.ReadMsg(ctx) if err != nil { return err @@ -193,7 +193,7 @@ func (p *Preconfirmation) handleBid( p.logger.Info("received bid", "bid", bid) - ethAddress, err := p.signer.VerifyBid(bid) + ethAddress, err := p.encryptor.VerifyBid(bid) if err != nil { return err } @@ -215,7 +215,7 @@ func (p *Preconfirmation) handleBid( case providerapiv1.BidResponse_STATUS_REJECTED: return errors.New("bid rejected") case providerapiv1.BidResponse_STATUS_ACCEPTED: - preConfirmation, err := p.signer.ConstructPreConfirmation(bid) + preConfirmation, err := p.encryptor.ConstructPreConfirmation(bid) if err != nil { return err } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 19e11158..d7caa9f7 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -13,7 +13,7 @@ import ( "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" ) @@ -32,25 +32,25 @@ func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Addre } type testSigner struct { - bid *preconfsigner.Bid - preConfirmation *preconfsigner.PreConfirmation + bid *preconfencryptor.Bid + preConfirmation *preconfencryptor.PreConfirmation bidSigner common.Address preConfirmationSigner common.Address } -func (t *testSigner) ConstructSignedBid(_ string, _ *big.Int, _ *big.Int) (*preconfsigner.Bid, error) { +func (t *testSigner) ConstructSignedBid(_ string, _ *big.Int, _ *big.Int) (*preconfencryptor.Bid, error) { return t.bid, nil } -func (t *testSigner) ConstructPreConfirmation(_ *preconfsigner.Bid) (*preconfsigner.PreConfirmation, error) { +func (t *testSigner) ConstructPreConfirmation(_ *preconfencryptor.Bid) (*preconfencryptor.PreConfirmation, error) { return t.preConfirmation, nil } -func (t *testSigner) VerifyBid(_ *preconfsigner.Bid) (*common.Address, error) { +func (t *testSigner) VerifyBid(_ *preconfencryptor.Bid) (*common.Address, error) { return &t.bidSigner, nil } -func (t *testSigner) VerifyPreConfirmation(_ *preconfsigner.PreConfirmation) (*common.Address, error) { +func (t *testSigner) VerifyPreConfirmation(_ *preconfencryptor.PreConfirmation) (*common.Address, error) { return &t.preConfirmationSigner, nil } @@ -60,7 +60,7 @@ type testProcessor struct { func (t *testProcessor) ProcessBid( _ context.Context, - _ *preconfsigner.Bid) (chan providerapiv1.BidResponse_Status, error) { + _ *preconfencryptor.Bid) (chan providerapiv1.BidResponse_Status, error) { statusC := make(chan providerapiv1.BidResponse_Status, 1) statusC <- t.status return statusC, nil @@ -105,7 +105,7 @@ func TestPreconfBidSubmission(t *testing.T) { Type: p2p.PeerTypeProvider, } - bid := &preconfsigner.Bid{ + bid := &preconfencryptor.Bid{ TxHash: "test", BidAmt: big.NewInt(10), BlockNumber: big.NewInt(10), @@ -113,7 +113,7 @@ func TestPreconfBidSubmission(t *testing.T) { Signature: []byte("test"), } - preConfirmation := &preconfsigner.PreConfirmation{ + preConfirmation := &preconfencryptor.PreConfirmation{ Bid: *bid, Digest: []byte("test"), Signature: []byte("test"), diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 525b7994..b009e859 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/rpc/bidderapi/v1" registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/bidder_registry" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -45,7 +45,7 @@ func NewService( } type PreconfSender interface { - SendBid(context.Context, string, *big.Int, *big.Int) (chan *preconfsigner.PreConfirmation, error) + SendBid(context.Context, string, *big.Int, *big.Int) (chan *preconfencryptor.PreConfirmation, error) } func (s *Service) SendBid( diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 083dc8c8..5f82442c 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/rpc/bidderapi/v1" bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/util" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -42,17 +42,17 @@ func (s *testSender) SendBid( txHex string, amount *big.Int, blockNum *big.Int, -) (chan *preconfsigner.PreConfirmation, error) { +) (chan *preconfencryptor.PreConfirmation, error) { s.bids = append(s.bids, bid{ txHex: txHex, amount: amount, blockNum: blockNum, }) - preconfs := make(chan *preconfsigner.PreConfirmation, s.noOfPreconfs) + preconfs := make(chan *preconfencryptor.PreConfirmation, s.noOfPreconfs) for i := 0; i < s.noOfPreconfs; i++ { - preconfs <- &preconfsigner.PreConfirmation{ - Bid: preconfsigner.Bid{ + preconfs <- &preconfencryptor.PreConfirmation{ + Bid: preconfencryptor.Bid{ TxHash: txHex, BidAmt: amount, BlockNumber: blockNum, diff --git a/pkg/rpc/provider/service.go b/pkg/rpc/provider/service.go index abb994cd..51a0f957 100644 --- a/pkg/rpc/provider/service.go +++ b/pkg/rpc/provider/service.go @@ -15,7 +15,7 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/rpc/providerapi/v1" registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/provider_registry" "github.com/primevprotocol/mev-commit/pkg/evmclient" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -66,7 +66,7 @@ func toString(bid *providerapiv1.Bid) string { func (s *Service) ProcessBid( ctx context.Context, - bid *preconfsigner.Bid, + bid *preconfencryptor.Bid, ) (chan providerapiv1.BidResponse_Status, error) { bidMsg := &providerapiv1.Bid{ TxHashes: strings.Split(bid.TxHash, ","), diff --git a/pkg/rpc/provider/service_test.go b/pkg/rpc/provider/service_test.go index 0796bdc4..43d76d94 100644 --- a/pkg/rpc/provider/service_test.go +++ b/pkg/rpc/provider/service_test.go @@ -14,7 +14,7 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/rpc/providerapi/v1" "github.com/primevprotocol/mev-commit/pkg/evmclient" providerapi "github.com/primevprotocol/mev-commit/pkg/rpc/provider" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/util" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -181,7 +181,7 @@ func TestBidHandling(t *testing.T) { type testCase struct { name string - bid *preconfsigner.Bid + bid *preconfencryptor.Bid status providerapiv1.BidResponse_Status noStatus bool processErr string @@ -190,7 +190,7 @@ func TestBidHandling(t *testing.T) { for _, tc := range []testCase{ { name: "accepted bid", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: strings.Join( []string{ common.HexToHash("0x00001").Hex()[2:], // remove 0x @@ -206,7 +206,7 @@ func TestBidHandling(t *testing.T) { }, { name: "rejected bid", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: common.HexToHash("0x00003").Hex()[2:], // remove 0x BidAmt: big.NewInt(1000000000000000000), BlockNumber: big.NewInt(1), @@ -217,7 +217,7 @@ func TestBidHandling(t *testing.T) { }, { name: "invalid bid status", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: common.HexToHash("0x00003").Hex()[2:], // remove 0x BidAmt: big.NewInt(1000000000000000000), BlockNumber: big.NewInt(1), @@ -229,7 +229,7 @@ func TestBidHandling(t *testing.T) { }, { name: "invalid bid txHash", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: "asdf", BidAmt: big.NewInt(1000000000000000000), BlockNumber: big.NewInt(1), @@ -240,7 +240,7 @@ func TestBidHandling(t *testing.T) { }, { name: "invalid bid amount", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: common.HexToHash("0x00004").Hex()[2:], // remove 0x BidAmt: big.NewInt(0000000000000000000), BlockNumber: big.NewInt(1), @@ -251,7 +251,7 @@ func TestBidHandling(t *testing.T) { }, { name: "invalid bid block number", - bid: &preconfsigner.Bid{ + bid: &preconfencryptor.Bid{ TxHash: common.HexToHash("0x00004").Hex()[2:], // remove 0x BidAmt: big.NewInt(1000000000000000000), BlockNumber: big.NewInt(0), diff --git a/pkg/signer/preconfsigner/signer.go b/pkg/signer/preconfencryptor/encryptor.go similarity index 92% rename from pkg/signer/preconfsigner/signer.go rename to pkg/signer/preconfencryptor/encryptor.go index 865c1469..8840a2d4 100644 --- a/pkg/signer/preconfsigner/signer.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -1,4 +1,4 @@ -package preconfsigner +package preconfencryptor import ( "bytes" @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/signer/core/apitypes" - "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" ) var ( @@ -57,24 +57,24 @@ func (p PreConfirmation) String() string { ) } -type Signer interface { +type Encryptor interface { ConstructSignedBid(string, *big.Int, *big.Int) (*Bid, error) ConstructPreConfirmation(*Bid) (*PreConfirmation, error) VerifyBid(*Bid) (*common.Address, error) VerifyPreConfirmation(*PreConfirmation) (*common.Address, error) } -type privateKeySigner struct { - keySigner keysigner.KeySigner +type encryptor struct { + keyKeeper keykeeper.KeyKeeper } -func NewSigner(keySigner keysigner.KeySigner) *privateKeySigner { - return &privateKeySigner{ - keySigner: keySigner, +func NewEncryptor(keyKeeper keykeeper.KeyKeeper) *encryptor { + return &encryptor{ + keyKeeper: keyKeeper, } } -func (p *privateKeySigner) ConstructSignedBid( +func (e *encryptor) ConstructSignedBid( txHash string, bidAmt *big.Int, blockNumber *big.Int, @@ -94,7 +94,7 @@ func (p *privateKeySigner) ConstructSignedBid( return nil, err } - sig, err := p.keySigner.SignHash(bidHash) + sig, err := e.keyKeeper.SignHash(bidHash) if err != nil { return nil, err } @@ -109,8 +109,8 @@ func (p *privateKeySigner) ConstructSignedBid( return bid, nil } -func (p *privateKeySigner) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, error) { - _, err := p.VerifyBid(bid) +func (e *encryptor) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, error) { + _, err := e.VerifyBid(bid) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func (p *privateKeySigner) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, return nil, err } - sig, err := p.keySigner.SignHash(preConfirmationHash) + sig, err := e.keyKeeper.SignHash(preConfirmationHash) if err != nil { return nil, err } @@ -139,7 +139,7 @@ func (p *privateKeySigner) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, return preConfirmation, nil } -func (p *privateKeySigner) VerifyBid(bid *Bid) (*common.Address, error) { +func (e *encryptor) VerifyBid(bid *Bid) (*common.Address, error) { if bid.Digest == nil || bid.Signature == nil { return nil, ErrMissingHashSignature } @@ -158,12 +158,12 @@ func (p *privateKeySigner) VerifyBid(bid *Bid) (*common.Address, error) { // VerifyPreConfirmation verifies the preconfirmation message, and returns the address of the provider // that signed the preconfirmation. -func (p *privateKeySigner) VerifyPreConfirmation(c *PreConfirmation) (*common.Address, error) { +func (e *encryptor) VerifyPreConfirmation(c *PreConfirmation) (*common.Address, error) { if c.Digest == nil || c.Signature == nil { return nil, ErrMissingHashSignature } - _, err := p.VerifyBid(&c.Bid) + _, err := e.VerifyBid(&c.Bid) if err != nil { return nil, err } diff --git a/pkg/signer/preconfsigner/signer_test.go b/pkg/signer/preconfencryptor/encryptor_test.go similarity index 82% rename from pkg/signer/preconfsigner/signer_test.go rename to pkg/signer/preconfencryptor/encryptor_test.go index 6a56db9d..91235463 100644 --- a/pkg/signer/preconfsigner/signer_test.go +++ b/pkg/signer/preconfencryptor/encryptor_test.go @@ -1,4 +1,4 @@ -package preconfsigner_test +package preconfencryptor_test import ( "encoding/hex" @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" - "github.com/primevprotocol/mev-commit/pkg/signer/preconfsigner" + "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/stretchr/testify/assert" ) @@ -21,21 +21,21 @@ func TestBids(t *testing.T) { } keySigner := mockkeysigner.NewMockKeySigner(key, crypto.PubkeyToAddress(key.PublicKey)) - signer := preconfsigner.NewSigner(keySigner) + encryptor := preconfencryptor.NewEncryptor(keySigner) - bid, err := signer.ConstructSignedBid("0xkartik", big.NewInt(10), big.NewInt(2)) + bid, err := encryptor.ConstructSignedBid("0xkartik", big.NewInt(10), big.NewInt(2)) if err != nil { t.Fatal(err) } - address, err := signer.VerifyBid(bid) + address, err := encryptor.VerifyBid(bid) if err != nil { t.Fatal(err) } expectedAddress := crypto.PubkeyToAddress(key.PublicKey) - originatorAddress, pubkey, err := signer.BidOriginator(bid) + originatorAddress, pubkey, err := encryptor.BidOriginator(bid) if err != nil { t.Fatal(err) } @@ -51,14 +51,14 @@ func TestBids(t *testing.T) { keySigner := mockkeysigner.NewMockKeySigner(bidderKey, crypto.PubkeyToAddress(bidderKey.PublicKey)) - bidderSigner := preconfsigner.NewSigner(keySigner) + bidderSigner := preconfencryptor.NewEncryptor(keySigner) providerKey, err := crypto.GenerateKey() if err != nil { t.Fatal(err) } keySigner = mockkeysigner.NewMockKeySigner(providerKey, crypto.PubkeyToAddress(providerKey.PublicKey)) - providerSigner := preconfsigner.NewSigner(keySigner) + providerSigner := preconfencryptor.NewEncryptor(keySigner) bid, err := bidderSigner.ConstructSignedBid("0xkartik", big.NewInt(10), big.NewInt(2)) if err != nil { @@ -83,13 +83,13 @@ func TestHashing(t *testing.T) { t.Parallel() t.Run("bid", func(t *testing.T) { - bid := &preconfsigner.Bid{ + bid := &preconfencryptor.Bid{ TxHash: "0xkartik", BidAmt: big.NewInt(2), BlockNumber: big.NewInt(2), } - hash, err := preconfsigner.GetBidHash(bid) + hash, err := preconfencryptor.GetBidHash(bid) if err != nil { t.Fatal(err) } @@ -114,7 +114,7 @@ func TestHashing(t *testing.T) { t.Fatal(err) } - bid := &preconfsigner.Bid{ + bid := &preconfencryptor.Bid{ TxHash: "0xkartik", BidAmt: big.NewInt(2), BlockNumber: big.NewInt(2), @@ -122,11 +122,11 @@ func TestHashing(t *testing.T) { Signature: bidSigBytes, } - preConfirmation := &preconfsigner.PreConfirmation{ + preConfirmation := &preconfencryptor.PreConfirmation{ Bid: *bid, } - hash, err := preconfsigner.GetPreConfirmationHash(preConfirmation) + hash, err := preconfencryptor.GetPreConfirmationHash(preConfirmation) if err != nil { t.Fatal(err) } @@ -160,7 +160,7 @@ func TestVerify(t *testing.T) { bidSigBytes[64] -= 27 } - owner, err := preconfsigner.EIPVerify(bidHashBytes, bidHashBytes, bidSigBytes) + owner, err := preconfencryptor.EIPVerify(bidHashBytes, bidHashBytes, bidSigBytes) if err != nil { t.Fatal(err) } diff --git a/pkg/signer/preconfsigner/export_test.go b/pkg/signer/preconfencryptor/export_test.go similarity index 82% rename from pkg/signer/preconfsigner/export_test.go rename to pkg/signer/preconfencryptor/export_test.go index fd334a1a..26681125 100644 --- a/pkg/signer/preconfsigner/export_test.go +++ b/pkg/signer/preconfencryptor/export_test.go @@ -1,4 +1,4 @@ -package preconfsigner +package preconfencryptor import ( "crypto/ecdsa" @@ -9,8 +9,8 @@ import ( var EIPVerify = eipVerify -func (p *privateKeySigner) BidOriginator(bid *Bid) (*common.Address, *ecdsa.PublicKey, error) { - _, err := p.VerifyBid(bid) +func (e *encryptor) BidOriginator(bid *Bid) (*common.Address, *ecdsa.PublicKey, error) { + _, err := e.VerifyBid(bid) if err != nil { return nil, nil, err } @@ -31,7 +31,7 @@ func (p *privateKeySigner) BidOriginator(bid *Bid) (*common.Address, *ecdsa.Publ return &address, pubkey, nil } -func (p *privateKeySigner) PreConfirmationOriginator( +func (p *encryptor) PreConfirmationOriginator( c *PreConfirmation, ) (*common.Address, *ecdsa.PublicKey, error) { _, err := p.VerifyPreConfirmation(c) From d14ced1d6b2f6873bcdea4380b9e18b2922284ba Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 18 Mar 2024 10:58:06 +0100 Subject: [PATCH 04/85] implemented bid/commitment encryption --- pkg/keykeeper/keykeeper.go | 22 ++- pkg/keykeeper/models.go | 5 +- pkg/preconfirmation/preconfirmation.go | 56 +++++--- pkg/preconfirmation/preconfirmation_test.go | 65 +++++++-- pkg/signer/preconfencryptor/encryptor.go | 132 ++++++++++++++---- pkg/signer/preconfencryptor/encryptor_test.go | 58 ++++++-- pkg/signer/preconfencryptor/export_test.go | 46 +++--- 7 files changed, 282 insertions(+), 102 deletions(-) diff --git a/pkg/keykeeper/keykeeper.go b/pkg/keykeeper/keykeeper.go index 30ed0b4c..6c45335b 100644 --- a/pkg/keykeeper/keykeeper.go +++ b/pkg/keykeeper/keykeeper.go @@ -5,6 +5,7 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" + "encoding/hex" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" @@ -17,9 +18,12 @@ func NewBidderKeyKeeper(keysigner keysigner.KeySigner) (*BidderKeyKeeper, error) return nil, err } + bidHashesToNIKE := make(map[string]*ecdh.PrivateKey) + return &BidderKeyKeeper{ - KeySigner: keysigner, - AESKey: aesKey, + KeySigner: keysigner, + AESKey: aesKey, + BidHashesToNIKE: bidHashesToNIKE, }, nil } @@ -39,6 +43,16 @@ func (bkk *BidderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { bkk.KeySigner.ZeroPrivateKey(key) } +func (bkk *BidderKeyKeeper) GenerateNIKEKeys(bidHash []byte) (*ecdh.PublicKey, error) { + nikePrivateKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return nil, err + } + nikePublicKey := nikePrivateKey.PublicKey() + bkk.BidHashesToNIKE[hex.EncodeToString(bidHash)] = nikePrivateKey + return nikePublicKey, nil +} + func NewProviderKeyKeeper(keysigner keysigner.KeySigner) (*ProviderKeyKeeper, error) { biddersAESKeys := make(map[common.Address][]byte) @@ -92,6 +106,10 @@ func (pkk *ProviderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { pkk.KeySigner.ZeroPrivateKey(key) } +func (pkk *ProviderKeyKeeper) GetNIKEPrivateKey() *ecdh.PrivateKey { + return pkk.keys.NIKEPrivateKey +} + func NewBootnodeKeyKeeper(keysigner keysigner.KeySigner) *BootnodeKeyKeeper { return &BootnodeKeyKeeper{ KeySigner: keysigner, diff --git a/pkg/keykeeper/models.go b/pkg/keykeeper/models.go index 4e9ab151..3bdfc372 100644 --- a/pkg/keykeeper/models.go +++ b/pkg/keykeeper/models.go @@ -30,8 +30,9 @@ type ProviderKeyKeeper struct { } type BidderKeyKeeper struct { - AESKey []byte - KeySigner keysigner.KeySigner + AESKey []byte + KeySigner keysigner.KeySigner + BidHashesToNIKE map[string]*ecdh.PrivateKey } type BootnodeKeyKeeper struct { diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 5b7df9c9..d98ed2be 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -89,7 +89,7 @@ func (p *Preconfirmation) SendBid( bidAmt *big.Int, blockNumber *big.Int, ) (chan *encryptor.PreConfirmation, error) { - signedBid, err := p.encryptor.ConstructSignedBid(txHash, bidAmt, blockNumber) + bid, signedBid, err := p.encryptor.ConstructEncryptedBid(txHash, bidAmt, blockNumber) if err != nil { p.logger.Error("constructing signed bid", "error", err, "txHash", txHash) return nil, err @@ -127,7 +127,7 @@ func (p *Preconfirmation) SendBid( logger.Info("sending signed bid", "signedBid", signedBid) - r, w := msgpack.NewReaderWriter[encryptor.PreConfirmation, encryptor.Bid](providerStream) + r, w := msgpack.NewReaderWriter[encryptor.EncryptedPreConfirmation, encryptor.EncryptedBid](providerStream) err = w.WriteMsg(ctx, signedBid) if err != nil { _ = providerStream.Reset() @@ -136,7 +136,7 @@ func (p *Preconfirmation) SendBid( } p.metrics.SentBidsCount.Inc() - preConfirmation, err := r.ReadMsg(ctx) + encryptedPreConfirmation, err := r.ReadMsg(ctx) if err != nil { _ = providerStream.Reset() logger.Error("reading message", "error", err) @@ -146,12 +146,19 @@ func (p *Preconfirmation) SendBid( _ = providerStream.Close() // Process preConfirmation as a bidder - providerAddress, err := p.encryptor.VerifyPreConfirmation(preConfirmation) + providerAddress, err := p.encryptor.VerifyEncryptedPreConfirmation(provider.Keys.NIKEPublicKey, bid.Digest, encryptedPreConfirmation) if err != nil { logger.Error("verifying provider signature", "error", err) return } - preConfirmation.ProviderAddress = *providerAddress + + preConfirmation := &encryptor.PreConfirmation{ + Bid: *bid, + Digest: encryptedPreConfirmation.Commitment, + Signature: encryptedPreConfirmation.Signature, + ProviderAddress: *providerAddress, + } + logger.Info("received preconfirmation", "preConfirmation", preConfirmation) p.metrics.ReceivedPreconfsCount.Inc() @@ -185,19 +192,23 @@ func (p *Preconfirmation) handleBid( return ErrInvalidBidderTypeForBid } - r, w := msgpack.NewReaderWriter[encryptor.Bid, encryptor.PreConfirmation](stream) - bid, err := r.ReadMsg(ctx) + r, w := msgpack.NewReaderWriter[encryptor.EncryptedBid, encryptor.EncryptedPreConfirmation](stream) + encryptedBid, err := r.ReadMsg(ctx) if err != nil { return err } - p.logger.Info("received bid", "bid", bid) - + p.logger.Info("received bid", "encryptedBid", encryptedBid) + bid, err := p.encryptor.DecryptBidData(peer.EthAddress, encryptedBid) + if err != nil { + return err + } ethAddress, err := p.encryptor.VerifyBid(bid) if err != nil { return err } + // todo: change to take care of double spend if p.us.CheckBidderAllowance(ctx, *ethAddress) { // try to enqueue for 5 seconds ctx, cancel := context.WithTimeout(ctx, 5*time.Second) @@ -215,23 +226,24 @@ func (p *Preconfirmation) handleBid( case providerapiv1.BidResponse_STATUS_REJECTED: return errors.New("bid rejected") case providerapiv1.BidResponse_STATUS_ACCEPTED: - preConfirmation, err := p.encryptor.ConstructPreConfirmation(bid) + preConfirmation, err := p.encryptor.ConstructEncryptedPreConfirmation(bid) if err != nil { return err } p.logger.Info("sending preconfirmation", "preConfirmation", preConfirmation) - err = p.commitmentDA.StoreCommitment( - ctx, - preConfirmation.Bid.BidAmt, - uint64(preConfirmation.Bid.BlockNumber.Int64()), - preConfirmation.Bid.TxHash, - preConfirmation.Bid.Signature, - preConfirmation.Signature, - ) - if err != nil { - p.logger.Error("storing commitment", "error", err) - return err - } + // todo: update SC + // err = p.commitmentDA.StoreCommitment( + // ctx, + // preConfirmation.Bid.BidAmt, + // uint64(preConfirmation.Bid.BlockNumber.Int64()), + // preConfirmation.Bid.TxHash, + // preConfirmation.Bid.Signature, + // preConfirmation.Signature, + // ) + // if err != nil { + // p.logger.Error("storing commitment", "error", err) + // return err + // } return w.WriteMsg(ctx, preConfirmation) } } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index d7caa9f7..cf0bc94b 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -2,6 +2,9 @@ package preconfirmation_test import ( "context" + "crypto/ecdh" + "crypto/elliptic" + "crypto/rand" "io" "log/slog" "math/big" @@ -9,6 +12,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/ecies" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/rpc/providerapi/v1" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" @@ -31,26 +35,36 @@ func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Addre return true } -type testSigner struct { +type testEncryptor struct { + bidHash []byte + encryptedBid *preconfencryptor.EncryptedBid bid *preconfencryptor.Bid - preConfirmation *preconfencryptor.PreConfirmation + preConfirmation *preconfencryptor.EncryptedPreConfirmation bidSigner common.Address preConfirmationSigner common.Address } -func (t *testSigner) ConstructSignedBid(_ string, _ *big.Int, _ *big.Int) (*preconfencryptor.Bid, error) { - return t.bid, nil +func (t *testEncryptor) ConstructEncryptedBid(_ string, _ *big.Int, _ *big.Int) (*preconfencryptor.Bid, *preconfencryptor.EncryptedBid, error) { + return t.bid, t.encryptedBid, nil } -func (t *testSigner) ConstructPreConfirmation(_ *preconfencryptor.Bid) (*preconfencryptor.PreConfirmation, error) { +func (t *testEncryptor) ConstructEncryptedPreConfirmation(_ *preconfencryptor.Bid) (*preconfencryptor.EncryptedPreConfirmation, error) { return t.preConfirmation, nil } -func (t *testSigner) VerifyBid(_ *preconfencryptor.Bid) (*common.Address, error) { +func (t *testEncryptor) VerifyBid(_ *preconfencryptor.Bid) (*common.Address, error) { return &t.bidSigner, nil } -func (t *testSigner) VerifyPreConfirmation(_ *preconfencryptor.PreConfirmation) (*common.Address, error) { +func (t *testEncryptor) DecryptBidData(_ common.Address, _ *preconfencryptor.EncryptedBid) (*preconfencryptor.Bid, error) { + return t.bid, nil +} + +func (t *testEncryptor) VerifyPreConfirmation(_ *preconfencryptor.PreConfirmation) (*common.Address, error) { + return &t.preConfirmationSigner, nil +} + +func (t *testEncryptor) VerifyEncryptedPreConfirmation(*ecdh.PublicKey, []byte, *preconfencryptor.EncryptedPreConfirmation) (*common.Address, error) { return &t.preConfirmationSigner, nil } @@ -100,9 +114,24 @@ func TestPreconfBidSubmission(t *testing.T) { EthAddress: common.HexToAddress("0x1"), Type: p2p.PeerTypeBidder, } + + encryptionPrivateKey, err := ecies.GenerateKey(rand.Reader, elliptic.P256(), nil) + if err != nil { + t.Fatal(err) + } + + nikePrivateKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + server := p2p.Peer{ EthAddress: common.HexToAddress("0x2"), Type: p2p.PeerTypeProvider, + Keys: &p2p.Keys{ + PKEPublicKey: &encryptionPrivateKey.PublicKey, + NIKEPublicKey: nikePrivateKey.PublicKey(), + }, } bid := &preconfencryptor.Bid{ @@ -113,12 +142,20 @@ func TestPreconfBidSubmission(t *testing.T) { Signature: []byte("test"), } - preConfirmation := &preconfencryptor.PreConfirmation{ - Bid: *bid, - Digest: []byte("test"), - Signature: []byte("test"), + encryptedBid := &preconfencryptor.EncryptedBid{ + Ciphertext: []byte("test"), } + // preConfirmation := &preconfencryptor.PreConfirmation{ + // Bid: *bid, + // Digest: []byte("test"), + // Signature: []byte("test"), + // } + + encryptedPreConfirmation := &preconfencryptor.EncryptedPreConfirmation{ + Commitment: []byte("test"), + Signature: []byte("test"), + } svc := p2ptest.New( &client, ) @@ -128,9 +165,11 @@ func TestPreconfBidSubmission(t *testing.T) { proc := &testProcessor{ status: providerapiv1.BidResponse_STATUS_ACCEPTED, } - signer := &testSigner{ + signer := &testEncryptor{ + bidHash: bid.Digest, + encryptedBid: encryptedBid, bid: bid, - preConfirmation: preConfirmation, + preConfirmation: encryptedPreConfirmation, bidSigner: common.HexToAddress("0x1"), preConfirmationSigner: common.HexToAddress("0x2"), } diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index 8840a2d4..c90e1954 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -2,7 +2,9 @@ package preconfencryptor import ( "bytes" + "crypto/ecdh" "encoding/hex" + "encoding/json" "errors" "fmt" "math/big" @@ -20,6 +22,7 @@ var ( ErrInvalidSignature = errors.New("signature is not valid") ErrInvalidHash = errors.New("bidhash doesn't match bid payload") ErrAlreadySignedPreConfirmation = errors.New("preConfirmation is already hashed or signed") + ErrInvalidCommitment = errors.New("commitment is incorrect") ) // PreConfBid represents the bid data. @@ -30,8 +33,13 @@ type Bid struct { BidAmt *big.Int `json:"bid_amt"` BlockNumber *big.Int `json:"block_number"` - Digest []byte `json:"bid_digest"` // TODO(@ckaritk): name better - Signature []byte `json:"bid_signature"` + NikePublicKey []byte `json:"nike_public_key"` + Digest []byte `json:"bid_digest"` // TODO(@ckaritk): name better + Signature []byte `json:"bid_signature"` +} + +type EncryptedBid struct { + Ciphertext []byte `json:"ciphertext"` } func (b Bid) String() string { @@ -44,12 +52,18 @@ func (b Bid) String() string { type PreConfirmation struct { Bid Bid `json:"bid"` - Digest []byte `json:"digest"` // TODO(@ckaritk): name better - Signature []byte `json:"signature"` + Digest []byte `json:"digest"` // TODO(@ckaritk): name better + Signature []byte `json:"signature"` + SharedSecret []byte `json:"shared_secret"` ProviderAddress common.Address `json:"provider_address"` } +type EncryptedPreConfirmation struct { + Commitment []byte `json:"commitment"` + Signature []byte `json:"signature"` +} + func (p PreConfirmation) String() string { return fmt.Sprintf( "Bid: %s, Digest: %s, Signature: %s", @@ -58,29 +72,33 @@ func (p PreConfirmation) String() string { } type Encryptor interface { - ConstructSignedBid(string, *big.Int, *big.Int) (*Bid, error) - ConstructPreConfirmation(*Bid) (*PreConfirmation, error) + ConstructEncryptedBid(string, *big.Int, *big.Int) (*Bid, *EncryptedBid, error) + ConstructEncryptedPreConfirmation(*Bid) (*EncryptedPreConfirmation, error) VerifyBid(*Bid) (*common.Address, error) - VerifyPreConfirmation(*PreConfirmation) (*common.Address, error) + VerifyEncryptedPreConfirmation(*ecdh.PublicKey, []byte, *EncryptedPreConfirmation) (*common.Address, error) + DecryptBidData(common.Address, *EncryptedBid) (*Bid, error) } type encryptor struct { - keyKeeper keykeeper.KeyKeeper + keyKeeper keykeeper.KeyKeeper + bidHashesToBid map[string]*Bid } func NewEncryptor(keyKeeper keykeeper.KeyKeeper) *encryptor { + bidHashesToBid := make(map[string]*Bid) return &encryptor{ - keyKeeper: keyKeeper, + keyKeeper: keyKeeper, + bidHashesToBid: bidHashesToBid, } } -func (e *encryptor) ConstructSignedBid( +func (e *encryptor) ConstructEncryptedBid( txHash string, bidAmt *big.Int, blockNumber *big.Int, -) (*Bid, error) { +) (*Bid, *EncryptedBid, error) { if txHash == "" || bidAmt == nil || blockNumber == nil { - return nil, errors.New("missing required fields") + return nil, nil, errors.New("missing required fields") } bid := &Bid{ @@ -91,34 +109,67 @@ func (e *encryptor) ConstructSignedBid( bidHash, err := GetBidHash(bid) if err != nil { - return nil, err + return nil, nil, err } + // todo: probably sign all data including nike public key sig, err := e.keyKeeper.SignHash(bidHash) if err != nil { - return nil, err + return nil, nil, err } if sig[64] == 0 || sig[64] == 1 { sig[64] += 27 // Transform V from 0/1 to 27/28 } + bidderKK := e.keyKeeper.(*keykeeper.BidderKeyKeeper) + nikePublicKey, err := bidderKK.GenerateNIKEKeys(bidHash) + if err != nil { + return nil, nil, err + } + + bid.NikePublicKey = nikePublicKey.Bytes() bid.Digest = bidHash bid.Signature = sig - return bid, nil + bidDataBytes, err := json.Marshal(bid) + if err != nil { + return nil, nil, err + } + + e.bidHashesToBid[hex.EncodeToString(bidHash)] = bid + + encryptedBidData, err := keykeeper.EncryptWithAESGCM(bidderKK.AESKey, bidDataBytes) + if err != nil { + return nil, nil, err + } + + return bid, &EncryptedBid{Ciphertext: encryptedBidData}, nil } -func (e *encryptor) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, error) { +func (e *encryptor) ConstructEncryptedPreConfirmation(bid *Bid) (*EncryptedPreConfirmation, error) { _, err := e.VerifyBid(bid) if err != nil { return nil, err } + bidDataPublicKey, err := ecdh.Curve.NewPublicKey(ecdh.P256(), bid.NikePublicKey) + if err != nil { + return nil, err + } + + providerKK := e.keyKeeper.(*keykeeper.ProviderKeyKeeper) + sharedSecredProviderSk, err := providerKK.GetNIKEPrivateKey().ECDH(bidDataPublicKey) + if err != nil { + return nil, err + } + preConfirmation := &PreConfirmation{ - Bid: *bid, + Bid: *bid, + SharedSecret: sharedSecredProviderSk, } + // todo: update to take preconf hash into hash calculation preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) if err != nil { return nil, err @@ -133,10 +184,10 @@ func (e *encryptor) ConstructPreConfirmation(bid *Bid) (*PreConfirmation, error) sig[64] += 27 // Transform V from 0/1 to 27/28 } - preConfirmation.Digest = preConfirmationHash - preConfirmation.Signature = sig - - return preConfirmation, nil + return &EncryptedPreConfirmation{ + Commitment: preConfirmationHash, + Signature: sig, + }, nil } func (e *encryptor) VerifyBid(bid *Bid) (*common.Address, error) { @@ -156,24 +207,49 @@ func (e *encryptor) VerifyBid(bid *Bid) (*common.Address, error) { ) } +func (e *encryptor) DecryptBidData(bidderAddress common.Address, bid *EncryptedBid) (*Bid, error) { + pkk := e.keyKeeper.(*keykeeper.ProviderKeyKeeper) + aesKey := pkk.BiddersAESKeys[bidderAddress] + decryptedBytes, err := keykeeper.DecryptWithAESGCM(aesKey, bid.Ciphertext) + if err != nil { + return nil, err + } + + var bidData Bid + if err := json.Unmarshal(decryptedBytes, &bidData); err != nil { + return nil, err + } + + return &bidData, nil +} + // VerifyPreConfirmation verifies the preconfirmation message, and returns the address of the provider // that signed the preconfirmation. -func (e *encryptor) VerifyPreConfirmation(c *PreConfirmation) (*common.Address, error) { - if c.Digest == nil || c.Signature == nil { +func (e *encryptor) VerifyEncryptedPreConfirmation(providerNikePK *ecdh.PublicKey, bidHash []byte, c *EncryptedPreConfirmation) (*common.Address, error) { + if c.Signature == nil { return nil, ErrMissingHashSignature } - _, err := e.VerifyBid(&c.Bid) + bidHashStr := hex.EncodeToString(bidHash) + bid := e.bidHashesToBid[bidHashStr] + + bidderKK := e.keyKeeper.(*keykeeper.BidderKeyKeeper) + sharedSecredBidderSk, err := bidderKK.BidHashesToNIKE[bidHashStr].ECDH(providerNikePK) if err != nil { return nil, err } - preConfirmationHash, err := GetPreConfirmationHash(c) + preConfirmation := &PreConfirmation{ + Bid: *bid, + SharedSecret: sharedSecredBidderSk, + } + + preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) if err != nil { return nil, err } - return eipVerify(preConfirmationHash, c.Digest, c.Signature) + return eipVerify(preConfirmationHash, c.Commitment, c.Signature) } func eipVerify( @@ -260,13 +336,14 @@ func GetPreConfirmationHash(c *PreConfirmation) ([]byte, error) { // EIP712_MESSAGE_TYPEHASH eip712MessageTypeHash := crypto.Keccak256Hash( - []byte("PreConfCommitment(string txnHash,uint64 bid,uint64 blockNumber,string bidHash,string signature)"), + []byte("PreConfCommitment(string txnHash,uint64 bid,uint64 blockNumber,string bidHash,string signature,string sharedSecret)"), ) // Convert the txnHash to a byte array and hash it txnHashHash := crypto.Keccak256Hash([]byte(c.Bid.TxHash)) bidDigestHash := crypto.Keccak256Hash([]byte(hex.EncodeToString(c.Bid.Digest))) bidSigHash := crypto.Keccak256Hash([]byte(hex.EncodeToString(c.Bid.Signature))) + sharedSecretHash := crypto.Keccak256Hash([]byte(hex.EncodeToString(c.SharedSecret))) // Encode values similar to Solidity's abi.encode data := append(eip712MessageTypeHash.Bytes(), txnHashHash.Bytes()...) @@ -274,6 +351,7 @@ func GetPreConfirmationHash(c *PreConfirmation) ([]byte, error) { data = append(data, math.U256Bytes(c.Bid.BlockNumber)...) data = append(data, bidDigestHash.Bytes()...) data = append(data, bidSigHash.Bytes()...) + data = append(data, sharedSecretHash.Bytes()...) dataHash := crypto.Keccak256Hash(data) rawData := append([]byte("\x19\x01"), append(domainSeparatorBid.Bytes(), dataHash.Bytes()...)...) diff --git a/pkg/signer/preconfencryptor/encryptor_test.go b/pkg/signer/preconfencryptor/encryptor_test.go index 91235463..ba422333 100644 --- a/pkg/signer/preconfencryptor/encryptor_test.go +++ b/pkg/signer/preconfencryptor/encryptor_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/crypto" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner/mock" "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/stretchr/testify/assert" @@ -20,27 +21,41 @@ func TestBids(t *testing.T) { t.Fatal(err) } - keySigner := mockkeysigner.NewMockKeySigner(key, crypto.PubkeyToAddress(key.PublicKey)) - encryptor := preconfencryptor.NewEncryptor(keySigner) + address := crypto.PubkeyToAddress(key.PublicKey) + keySigner := mockkeysigner.NewMockKeySigner(key, address) + keyKeeper, err := keykeeper.NewBidderKeyKeeper(keySigner) + if err != nil { + t.Fatal(err) + } + encryptor := preconfencryptor.NewEncryptor(keyKeeper) - bid, err := encryptor.ConstructSignedBid("0xkartik", big.NewInt(10), big.NewInt(2)) + _, encryptedBid, err := encryptor.ConstructEncryptedBid("0xkartik", big.NewInt(10), big.NewInt(2)) if err != nil { t.Fatal(err) } - address, err := encryptor.VerifyBid(bid) + providerKeyKeeper, err := keykeeper.NewProviderKeyKeeper(keySigner) + if err != nil { + t.Fatal(err) + } + providerKeyKeeper.BiddersAESKeys[address] = keyKeeper.AESKey + encryptorProvider := preconfencryptor.NewEncryptor(providerKeyKeeper) + bid, err := encryptorProvider.DecryptBidData(address, encryptedBid) if err != nil { t.Fatal(err) } - expectedAddress := crypto.PubkeyToAddress(key.PublicKey) + bidAddress, err := encryptor.VerifyBid(bid) + if err != nil { + t.Fatal(err) + } originatorAddress, pubkey, err := encryptor.BidOriginator(bid) if err != nil { t.Fatal(err) } - assert.Equal(t, expectedAddress, *originatorAddress) - assert.Equal(t, expectedAddress, *address) + assert.Equal(t, address, *originatorAddress) + assert.Equal(t, address, *bidAddress) assert.Equal(t, key.PublicKey, *pubkey) }) t.Run("preConfirmation", func(t *testing.T) { @@ -50,27 +65,42 @@ func TestBids(t *testing.T) { } keySigner := mockkeysigner.NewMockKeySigner(bidderKey, crypto.PubkeyToAddress(bidderKey.PublicKey)) - - bidderSigner := preconfencryptor.NewEncryptor(keySigner) + bidderKeyKeeper, err := keykeeper.NewBidderKeyKeeper(keySigner) + if err != nil { + t.Fatal(err) + } + bidderEncryptor := preconfencryptor.NewEncryptor(bidderKeyKeeper) providerKey, err := crypto.GenerateKey() if err != nil { t.Fatal(err) } + bidderAddress := crypto.PubkeyToAddress(bidderKey.PublicKey) keySigner = mockkeysigner.NewMockKeySigner(providerKey, crypto.PubkeyToAddress(providerKey.PublicKey)) - providerSigner := preconfencryptor.NewEncryptor(keySigner) + providerKeyKeeper, err := keykeeper.NewProviderKeyKeeper(keySigner) + if err != nil { + t.Fatal(err) + } - bid, err := bidderSigner.ConstructSignedBid("0xkartik", big.NewInt(10), big.NewInt(2)) + providerKeyKeeper.BiddersAESKeys[bidderAddress] = bidderKeyKeeper.AESKey + + providerEncryptor := preconfencryptor.NewEncryptor(providerKeyKeeper) + + bid, encryptedBid, err := bidderEncryptor.ConstructEncryptedBid("0xkartik", big.NewInt(10), big.NewInt(2)) if err != nil { t.Fatal(err) } - preConfirmation, err := providerSigner.ConstructPreConfirmation(bid) + decryptedBid, err := providerEncryptor.DecryptBidData(bidderAddress, encryptedBid) + if err != nil { + t.Fatal(err) + } + encryptedPreConfirmation, err := providerEncryptor.ConstructEncryptedPreConfirmation(decryptedBid) if err != nil { t.Fail() } - address, err := bidderSigner.VerifyPreConfirmation(preConfirmation) + address, err := bidderEncryptor.VerifyEncryptedPreConfirmation(providerKeyKeeper.GetNIKEPublicKey(), bid.Digest, encryptedPreConfirmation) if err != nil { t.Fail() } @@ -132,7 +162,7 @@ func TestHashing(t *testing.T) { } hashStr := hex.EncodeToString(hash) - expHash := "31dca6c6fd15593559dabb9e25285f727fd33f07e17ec2e8da266706020034dc" + expHash := "33a9d7e3fb407f57ecb3b5e1503e71180289cc8c2e05df682d6a16f34fa00291" if hashStr != expHash { t.Fatalf("hash mismatch: %s != %s", hashStr, expHash) } diff --git a/pkg/signer/preconfencryptor/export_test.go b/pkg/signer/preconfencryptor/export_test.go index 26681125..66087e40 100644 --- a/pkg/signer/preconfencryptor/export_test.go +++ b/pkg/signer/preconfencryptor/export_test.go @@ -31,25 +31,27 @@ func (e *encryptor) BidOriginator(bid *Bid) (*common.Address, *ecdsa.PublicKey, return &address, pubkey, nil } -func (p *encryptor) PreConfirmationOriginator( - c *PreConfirmation, -) (*common.Address, *ecdsa.PublicKey, error) { - _, err := p.VerifyPreConfirmation(c) - if err != nil { - return nil, nil, err - } - - sig := make([]byte, len(c.Signature)) - copy(sig, c.Signature) - if sig[64] >= 27 && sig[64] <= 28 { - sig[64] -= 27 - } - pubkey, err := crypto.SigToPub(c.Digest, sig) - if err != nil { - return nil, nil, err - } - - address := crypto.PubkeyToAddress(*pubkey) - - return &address, pubkey, nil -} +// todo: come up with better test with passing all the data +// currently this is not used +// func (p *encryptor) PreConfirmationOriginator( +// c *PreConfirmation, +// ) (*common.Address, *ecdsa.PublicKey, error) { +// _, err := p.VerifyEncryptedPreConfirmation(c) +// if err != nil { +// return nil, nil, err +// } + +// sig := make([]byte, len(c.Signature)) +// copy(sig, c.Signature) +// if sig[64] >= 27 && sig[64] <= 28 { +// sig[64] -= 27 +// } +// pubkey, err := crypto.SigToPub(c.Digest, sig) +// if err != nil { +// return nil, nil, err +// } + +// address := crypto.PubkeyToAddress(*pubkey) + +// return &address, pubkey, nil +// } From 61f37c46eebab255d4181b4c36b30925ad46f8e8 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 18 Mar 2024 14:32:25 +0100 Subject: [PATCH 05/85] get rid of repeated code --- pkg/keykeeper/keykeeper.go | 79 ++++++++++------------------------- pkg/keykeeper/models.go | 12 +++--- pkg/node/node.go | 2 +- pkg/p2p/libp2p/libp2p_test.go | 2 +- 4 files changed, 31 insertions(+), 64 deletions(-) diff --git a/pkg/keykeeper/keykeeper.go b/pkg/keykeeper/keykeeper.go index 6c45335b..a0723594 100644 --- a/pkg/keykeeper/keykeeper.go +++ b/pkg/keykeeper/keykeeper.go @@ -12,37 +12,42 @@ import ( "github.com/primevprotocol/mev-commit/pkg/keykeeper/keysigner" ) -func NewBidderKeyKeeper(keysigner keysigner.KeySigner) (*BidderKeyKeeper, error) { - aesKey, err := generateAESKey() - if err != nil { - return nil, err - } - - bidHashesToNIKE := make(map[string]*ecdh.PrivateKey) - - return &BidderKeyKeeper{ - KeySigner: keysigner, - AESKey: aesKey, - BidHashesToNIKE: bidHashesToNIKE, - }, nil +// NewBaseKeyKeeper creates a new BaseKeyKeeper. +func NewBaseKeyKeeper(keysigner keysigner.KeySigner) *BaseKeyKeeper { + return &BaseKeyKeeper{KeySigner: keysigner} } -func (bkk *BidderKeyKeeper) SignHash(data []byte) ([]byte, error) { +func (bkk *BaseKeyKeeper) SignHash(data []byte) ([]byte, error) { return bkk.KeySigner.SignHash(data) } -func (bkk *BidderKeyKeeper) GetAddress() common.Address { +func (bkk *BaseKeyKeeper) GetAddress() common.Address { return bkk.KeySigner.GetAddress() } -func (bkk *BidderKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { +func (bkk *BaseKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { return bkk.KeySigner.GetPrivateKey() } -func (bkk *BidderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { +func (bkk *BaseKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { bkk.KeySigner.ZeroPrivateKey(key) } +func NewBidderKeyKeeper(keysigner keysigner.KeySigner) (*BidderKeyKeeper, error) { + aesKey, err := generateAESKey() + if err != nil { + return nil, err + } + + bidHashesToNIKE := make(map[string]*ecdh.PrivateKey) + + return &BidderKeyKeeper{ + BaseKeyKeeper: NewBaseKeyKeeper(keysigner), + AESKey: aesKey, + BidHashesToNIKE: bidHashesToNIKE, + }, nil +} + func (bkk *BidderKeyKeeper) GenerateNIKEKeys(bidHash []byte) (*ecdh.PublicKey, error) { nikePrivateKey, err := ecdh.P256().GenerateKey(rand.Reader) if err != nil { @@ -67,7 +72,7 @@ func NewProviderKeyKeeper(keysigner keysigner.KeySigner) (*ProviderKeyKeeper, er } return &ProviderKeyKeeper{ - KeySigner: keysigner, + BaseKeyKeeper: NewBaseKeyKeeper(keysigner), BiddersAESKeys: biddersAESKeys, keys: ProviderKeys{ EncryptionPrivateKey: encryptionPrivateKey, @@ -90,44 +95,6 @@ func (pkk *ProviderKeyKeeper) DecryptWithECIES(message []byte) ([]byte, error) { return pkk.keys.EncryptionPrivateKey.Decrypt(message, nil, nil) } -func (pkk *ProviderKeyKeeper) SignHash(data []byte) ([]byte, error) { - return pkk.KeySigner.SignHash(data) -} - -func (pkk *ProviderKeyKeeper) GetAddress() common.Address { - return pkk.KeySigner.GetAddress() -} - -func (pkk *ProviderKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { - return pkk.KeySigner.GetPrivateKey() -} - -func (pkk *ProviderKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { - pkk.KeySigner.ZeroPrivateKey(key) -} - func (pkk *ProviderKeyKeeper) GetNIKEPrivateKey() *ecdh.PrivateKey { return pkk.keys.NIKEPrivateKey } - -func NewBootnodeKeyKeeper(keysigner keysigner.KeySigner) *BootnodeKeyKeeper { - return &BootnodeKeyKeeper{ - KeySigner: keysigner, - } -} - -func (btkk *BootnodeKeyKeeper) SignHash(data []byte) ([]byte, error) { - return btkk.KeySigner.SignHash(data) -} - -func (btkk *BootnodeKeyKeeper) GetAddress() common.Address { - return btkk.KeySigner.GetAddress() -} - -func (btkk *BootnodeKeyKeeper) GetPrivateKey() (*ecdsa.PrivateKey, error) { - return btkk.KeySigner.GetPrivateKey() -} - -func (btkk *BootnodeKeyKeeper) ZeroPrivateKey(key *ecdsa.PrivateKey) { - btkk.KeySigner.ZeroPrivateKey(key) -} diff --git a/pkg/keykeeper/models.go b/pkg/keykeeper/models.go index 3bdfc372..c337bc67 100644 --- a/pkg/keykeeper/models.go +++ b/pkg/keykeeper/models.go @@ -16,6 +16,10 @@ type KeyKeeper interface { ZeroPrivateKey(key *ecdsa.PrivateKey) } +type BaseKeyKeeper struct { + KeySigner keysigner.KeySigner +} + type ProviderKeys struct { EncryptionPrivateKey *ecies.PrivateKey EncryptionPublicKey *ecies.PublicKey @@ -24,17 +28,13 @@ type ProviderKeys struct { } type ProviderKeyKeeper struct { + *BaseKeyKeeper keys ProviderKeys - KeySigner keysigner.KeySigner BiddersAESKeys map[common.Address][]byte } type BidderKeyKeeper struct { + *BaseKeyKeeper AESKey []byte - KeySigner keysigner.KeySigner BidHashesToNIKE map[string]*ecdh.PrivateKey } - -type BootnodeKeyKeeper struct { - KeySigner keysigner.KeySigner -} diff --git a/pkg/node/node.go b/pkg/node/node.go index a79fbac6..2d5ff266 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -123,7 +123,7 @@ func NewNode(opts *Options) (*Node, error) { return nil, errors.Join(err, nd.Close()) } default: - keyKeeper = keykeeper.NewBootnodeKeyKeeper(opts.KeySigner) + keyKeeper = keykeeper.NewBaseKeyKeeper(opts.KeySigner) } p2pSvc, err := libp2p.New(&libp2p.Options{ KeyKeeper: keyKeeper, diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index 2fe9ac17..7cddca58 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -252,7 +252,7 @@ func TestBootstrap(t *testing.T) { ks := mockkeysigner.NewMockKeySigner(privKey, address) bnOpts := testDefaultOptions - bnOpts.KeyKeeper = keykeeper.NewBootnodeKeyKeeper(ks) + bnOpts.KeyKeeper = keykeeper.NewBaseKeyKeeper(ks) bnOpts.PeerType = p2p.PeerTypeBootnode bootnode, err := libp2p.New(&bnOpts) From d6548b3448dc813d596b2d0ee1151f2a7b2b835b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 20 Mar 2024 15:14:03 +0100 Subject: [PATCH 06/85] updated according to SC changes --- go.mod | 2 +- go.sum | 2 ++ pkg/contracts/preconf/preconf.go | 28 +++++++-------------- pkg/contracts/preconf/preconf_test.go | 26 ++++++------------- pkg/node/node.go | 6 +---- pkg/preconfirmation/preconfirmation.go | 21 +++++++--------- pkg/preconfirmation/preconfirmation_test.go | 5 +--- 7 files changed, 31 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 0e2a9f31..d0642f35 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.1 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.0 + github.com/primevprotocol/contracts-abi v0.2.4-0.20240319201845-0e7b67b8e539 github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index 4d9fe9a0..93b47190 100644 --- a/go.sum +++ b/go.sum @@ -334,6 +334,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/primevprotocol/contracts-abi v0.2.0 h1:fzADMI4pVpLVOagZ6K1dOeibYDc89TNyuwymSKzU9ls= github.com/primevprotocol/contracts-abi v0.2.0/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240319201845-0e7b67b8e539 h1:gEge1UMJF88weugg6nUvUVbMu8byxASqHbpSKUs8ElE= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240319201845-0e7b67b8e539/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index e0d17b81..632f8b80 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -3,13 +3,12 @@ package preconfcontract import ( "context" "log/slog" - "math/big" "strings" "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/primevprotocol/contracts-abi/clients/PreConfCommitmentStore" + preconfcommitmentstore "github.com/primevprotocol/contracts-abi/clients/PreConfCommitmentStore" "github.com/primevprotocol/mev-commit/pkg/evmclient" ) @@ -24,12 +23,9 @@ var preconfABI = func() abi.ABI { var defaultWaitTimeout = 10 * time.Second type Interface interface { - StoreCommitment( + StoreEncryptedCommitment( ctx context.Context, - bid *big.Int, - blockNumber uint64, - txHash string, - bidSignature []byte, + commitmentDigest []byte, commitmentSignature []byte, ) error } @@ -54,25 +50,19 @@ func New( } } -func (p *preconfContract) StoreCommitment( +func (p *preconfContract) StoreEncryptedCommitment( ctx context.Context, - bid *big.Int, - blockNumber uint64, - txHash string, - bidSignature []byte, + commitmentDigest []byte, commitmentSignature []byte, ) error { callData, err := p.preconfABI.Pack( - "storeCommitment", - uint64(bid.Int64()), - blockNumber, - txHash, - bidSignature, + "storeEncryptedCommitment", + [32]byte(commitmentDigest), commitmentSignature, ) if err != nil { - p.logger.Error("preconf contract storeCommitment pack error", "err", err) + p.logger.Error("preconf contract storeEncryptedCommitment pack error", "err", err) return err } @@ -84,7 +74,7 @@ func (p *preconfContract) StoreCommitment( return err } - p.logger.Info("preconf contract storeCommitment successful", "txnHash", txnHash) + p.logger.Info("preconf contract storeEncryptedCommitment successful", "txnHash", txnHash) return nil } diff --git a/pkg/contracts/preconf/preconf_test.go b/pkg/contracts/preconf/preconf_test.go index 3ec472c3..c62b7323 100644 --- a/pkg/contracts/preconf/preconf_test.go +++ b/pkg/contracts/preconf/preconf_test.go @@ -3,7 +3,6 @@ package preconfcontract_test import ( "bytes" "context" - "math/big" "os" "testing" @@ -18,22 +17,16 @@ import ( func TestPreconfContract(t *testing.T) { t.Parallel() - t.Run("StoreCommitment", func(t *testing.T) { + t.Run("StoreEncryptedCommitment", func(t *testing.T) { preConfContract := common.HexToAddress("abcd") txHash := common.HexToHash("abcdef") - bid := big.NewInt(1000000000000000000) - blockNum := uint64(100) - bidHash := "abcdef" - bidSig := []byte("abcdef") - commitment := []byte("abcdef") + commitment := [32]byte([]byte("abcdefabcdefabcdefabcdefabcdefaa")) + commitmentSignature := []byte("abcdef") expCallData, err := preconfcontract.PreConfABI().Pack( - "storeCommitment", - uint64(bid.Int64()), - blockNum, - bidHash, - bidSig, + "storeEncryptedCommitment", commitment, + commitmentSignature, ) if err != nil { @@ -73,13 +66,10 @@ func TestPreconfContract(t *testing.T) { util.NewTestLogger(os.Stdout), ) - err = preConfContractClient.StoreCommitment( + err = preConfContractClient.StoreEncryptedCommitment( context.Background(), - bid, - blockNum, - bidHash, - bidSig, - commitment, + commitment[:], + commitmentSignature, ) if err != nil { t.Fatal(err) diff --git a/pkg/node/node.go b/pkg/node/node.go index 2d5ff266..29068135 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "log/slog" - "math/big" "net" "net/http" "time" @@ -404,11 +403,8 @@ func (noOpBidProcessor) ProcessBid( type noOpCommitmentDA struct{} -func (noOpCommitmentDA) StoreCommitment( +func (noOpCommitmentDA) StoreEncryptedCommitment( _ context.Context, - _ *big.Int, - _ uint64, - _ string, _ []byte, _ []byte, ) error { diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index d98ed2be..20f2ee48 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -232,18 +232,15 @@ func (p *Preconfirmation) handleBid( } p.logger.Info("sending preconfirmation", "preConfirmation", preConfirmation) // todo: update SC - // err = p.commitmentDA.StoreCommitment( - // ctx, - // preConfirmation.Bid.BidAmt, - // uint64(preConfirmation.Bid.BlockNumber.Int64()), - // preConfirmation.Bid.TxHash, - // preConfirmation.Bid.Signature, - // preConfirmation.Signature, - // ) - // if err != nil { - // p.logger.Error("storing commitment", "error", err) - // return err - // } + err = p.commitmentDA.StoreEncryptedCommitment( + ctx, + preConfirmation.Commitment, + preConfirmation.Signature, + ) + if err != nil { + p.logger.Error("storing commitment", "error", err) + return err + } return w.WriteMsg(ctx, preConfirmation) } } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index cf0bc94b..0f8b2081 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -82,11 +82,8 @@ func (t *testProcessor) ProcessBid( type testCommitmentDA struct{} -func (t *testCommitmentDA) StoreCommitment( +func (t *testCommitmentDA) StoreEncryptedCommitment( _ context.Context, - _ *big.Int, - _ uint64, - _ string, _ []byte, _ []byte, ) error { From 16557f8172060876c9962b73eb1296d45d9cdb00 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 1 Apr 2024 00:15:44 +0200 Subject: [PATCH 07/85] applied smart contract update --- gen/go/bidderapi/v1/bidderapi.pb.go | 513 ++++++++++-------- gen/go/bidderapi/v1/bidderapi.pb.gw.go | 22 +- gen/go/bidderapi/v1/bidderapi_grpc.pb.go | 12 +- .../bidderapi/v1/bidderapi.swagger.yaml | 7 + pkg/contracts/block_tracker/block_tracker.go | 269 +++++++++ pkg/node/node.go | 14 + pkg/preconfirmation/preconfirmation.go | 16 +- pkg/preconfirmation/preconfirmation_test.go | 49 +- pkg/rpc/bidder/service.go | 51 +- pkg/rpc/bidder/service_test.go | 54 +- rpc/bidderapi/v1/bidderapi.proto | 18 +- 11 files changed, 777 insertions(+), 248 deletions(-) create mode 100644 pkg/contracts/block_tracker/block_tracker.go diff --git a/gen/go/bidderapi/v1/bidderapi.pb.go b/gen/go/bidderapi/v1/bidderapi.pb.go index b4cc9573..2c8a63c4 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.go @@ -12,6 +12,7 @@ import ( _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" ) @@ -155,6 +156,53 @@ func (*EmptyMessage) Descriptor() ([]byte, []int) { return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{2} } +type GetAllowanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,1,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` +} + +func (x *GetAllowanceRequest) Reset() { + *x = GetAllowanceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAllowanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAllowanceRequest) ProtoMessage() {} + +func (x *GetAllowanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] + 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 GetAllowanceRequest.ProtoReflect.Descriptor instead. +func (*GetAllowanceRequest) Descriptor() ([]byte, []int) { + return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{3} +} + +func (x *GetAllowanceRequest) GetWindowNumber() *wrapperspb.UInt64Value { + if x != nil { + return x.WindowNumber + } + return nil +} + type Bid struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -170,7 +218,7 @@ type Bid struct { func (x *Bid) Reset() { *x = Bid{} if protoimpl.UnsafeEnabled { - mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -183,7 +231,7 @@ func (x *Bid) String() string { func (*Bid) ProtoMessage() {} func (x *Bid) ProtoReflect() protoreflect.Message { - mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -196,7 +244,7 @@ func (x *Bid) ProtoReflect() protoreflect.Message { // Deprecated: Use Bid.ProtoReflect.Descriptor instead. func (*Bid) Descriptor() ([]byte, []int) { - return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{3} + return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{4} } func (x *Bid) GetTxHashes() []string { @@ -254,7 +302,7 @@ type Commitment struct { func (x *Commitment) Reset() { *x = Commitment{} if protoimpl.UnsafeEnabled { - mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[4] + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -267,7 +315,7 @@ func (x *Commitment) String() string { func (*Commitment) ProtoMessage() {} func (x *Commitment) ProtoReflect() protoreflect.Message { - mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[4] + mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -280,7 +328,7 @@ func (x *Commitment) ProtoReflect() protoreflect.Message { // Deprecated: Use Commitment.ProtoReflect.Descriptor instead. func (*Commitment) Descriptor() ([]byte, []int) { - return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{4} + return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{5} } func (x *Commitment) GetTxHashes() []string { @@ -365,7 +413,9 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xa5, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8c, 0x01, 0x92, 0x41, 0x2e, 0x32, 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, @@ -395,193 +445,213 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x0e, - 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa2, - 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, - 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, - 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, - 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, - 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, - 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, - 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, - 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, - 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, - 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, - 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, - 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, - 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb6, + 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xdb, 0x01, 0x92, 0x41, + 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x70, 0xba, 0x01, 0x6d, 0x0a, 0x0c, 0x77, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x2e, 0x1a, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x3d, + 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, + 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, + 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, + 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, - 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, - 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, - 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, - 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, - 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, - 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, - 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, - 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, - 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, - 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, - 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, - 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, - 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, - 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, - 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, - 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, - 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, - 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, - 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, - 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, - 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, - 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, - 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, - 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, - 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, - 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, - 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, - 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, - 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, - 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, - 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, - 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, - 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, - 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, - 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, - 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, - 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, - 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, - 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, - 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, - 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, - 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, - 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, - 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, - 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, - 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, - 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, - 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, - 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, - 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, - 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xae, 0x03, - 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, - 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, - 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, - 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, - 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, - 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, - 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, - 0x6a, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, - 0x1a, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, + 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, + 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, + 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, + 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, + 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, + 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, + 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, + 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, + 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, + 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, + 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, + 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, + 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, + 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, + 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, + 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, + 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, + 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, + 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, + 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, + 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, + 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, + 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, + 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, + 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, + 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, + 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, + 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, + 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, + 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, + 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, + 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, + 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, + 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, + 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, + 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, + 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, + 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, + 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, + 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, + 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, + 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, + 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, @@ -627,28 +697,31 @@ func file_bidderapi_v1_bidderapi_proto_rawDescGZIP() []byte { return file_bidderapi_v1_bidderapi_proto_rawDescData } -var file_bidderapi_v1_bidderapi_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_bidderapi_v1_bidderapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_bidderapi_v1_bidderapi_proto_goTypes = []interface{}{ - (*PrepayRequest)(nil), // 0: bidderapi.v1.PrepayRequest - (*PrepayResponse)(nil), // 1: bidderapi.v1.PrepayResponse - (*EmptyMessage)(nil), // 2: bidderapi.v1.EmptyMessage - (*Bid)(nil), // 3: bidderapi.v1.Bid - (*Commitment)(nil), // 4: bidderapi.v1.Commitment + (*PrepayRequest)(nil), // 0: bidderapi.v1.PrepayRequest + (*PrepayResponse)(nil), // 1: bidderapi.v1.PrepayResponse + (*EmptyMessage)(nil), // 2: bidderapi.v1.EmptyMessage + (*GetAllowanceRequest)(nil), // 3: bidderapi.v1.GetAllowanceRequest + (*Bid)(nil), // 4: bidderapi.v1.Bid + (*Commitment)(nil), // 5: bidderapi.v1.Commitment + (*wrapperspb.UInt64Value)(nil), // 6: google.protobuf.UInt64Value } var file_bidderapi_v1_bidderapi_proto_depIdxs = []int32{ - 3, // 0: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid - 0, // 1: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest - 2, // 2: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.EmptyMessage - 2, // 3: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage - 4, // 4: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment - 1, // 5: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 6: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 7: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse - 4, // [4:8] is the sub-list for method output_type - 0, // [0:4] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 6, // 0: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 4, // 1: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid + 0, // 2: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest + 3, // 3: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest + 2, // 4: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage + 5, // 5: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment + 1, // 6: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 7: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 8: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse + 5, // [5:9] is the sub-list for method output_type + 1, // [1:5] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_bidderapi_v1_bidderapi_proto_init() } @@ -694,7 +767,7 @@ func file_bidderapi_v1_bidderapi_proto_init() { } } file_bidderapi_v1_bidderapi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Bid); i { + switch v := v.(*GetAllowanceRequest); i { case 0: return &v.state case 1: @@ -706,6 +779,18 @@ func file_bidderapi_v1_bidderapi_proto_init() { } } file_bidderapi_v1_bidderapi_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bid); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bidderapi_v1_bidderapi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Commitment); i { case 0: return &v.state @@ -724,7 +809,7 @@ func file_bidderapi_v1_bidderapi_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_bidderapi_v1_bidderapi_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/go/bidderapi/v1/bidderapi.pb.gw.go b/gen/go/bidderapi/v1/bidderapi.pb.gw.go index 910b8362..dda15497 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.gw.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.gw.go @@ -104,19 +104,37 @@ func local_request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runti } +var ( + filter_Bidder_GetAllowance_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Bidder_GetAllowance_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq EmptyMessage + var protoReq GetAllowanceRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetAllowance_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.GetAllowance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_Bidder_GetAllowance_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq EmptyMessage + var protoReq GetAllowanceRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetAllowance_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.GetAllowance(ctx, &protoReq) return msg, metadata, err diff --git a/gen/go/bidderapi/v1/bidderapi_grpc.pb.go b/gen/go/bidderapi/v1/bidderapi_grpc.pb.go index fed53db5..62b5586b 100644 --- a/gen/go/bidderapi/v1/bidderapi_grpc.pb.go +++ b/gen/go/bidderapi/v1/bidderapi_grpc.pb.go @@ -40,7 +40,7 @@ type BidderClient interface { // GetAllowance // // GetAllowance is called by the bidder to get its allowance in the bidder registry. - GetAllowance(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PrepayResponse, error) + GetAllowance(ctx context.Context, in *GetAllowanceRequest, opts ...grpc.CallOption) (*PrepayResponse, error) // GetMinAllowance // // GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. @@ -96,7 +96,7 @@ func (c *bidderClient) PrepayAllowance(ctx context.Context, in *PrepayRequest, o return out, nil } -func (c *bidderClient) GetAllowance(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PrepayResponse, error) { +func (c *bidderClient) GetAllowance(ctx context.Context, in *GetAllowanceRequest, opts ...grpc.CallOption) (*PrepayResponse, error) { out := new(PrepayResponse) err := c.cc.Invoke(ctx, Bidder_GetAllowance_FullMethodName, in, out, opts...) if err != nil { @@ -129,7 +129,7 @@ type BidderServer interface { // GetAllowance // // GetAllowance is called by the bidder to get its allowance in the bidder registry. - GetAllowance(context.Context, *EmptyMessage) (*PrepayResponse, error) + GetAllowance(context.Context, *GetAllowanceRequest) (*PrepayResponse, error) // GetMinAllowance // // GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. @@ -147,7 +147,7 @@ func (UnimplementedBidderServer) SendBid(*Bid, Bidder_SendBidServer) error { func (UnimplementedBidderServer) PrepayAllowance(context.Context, *PrepayRequest) (*PrepayResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PrepayAllowance not implemented") } -func (UnimplementedBidderServer) GetAllowance(context.Context, *EmptyMessage) (*PrepayResponse, error) { +func (UnimplementedBidderServer) GetAllowance(context.Context, *GetAllowanceRequest) (*PrepayResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAllowance not implemented") } func (UnimplementedBidderServer) GetMinAllowance(context.Context, *EmptyMessage) (*PrepayResponse, error) { @@ -206,7 +206,7 @@ func _Bidder_PrepayAllowance_Handler(srv interface{}, ctx context.Context, dec f } func _Bidder_GetAllowance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(EmptyMessage) + in := new(GetAllowanceRequest) if err := dec(in); err != nil { return nil, err } @@ -218,7 +218,7 @@ func _Bidder_GetAllowance_Handler(srv interface{}, ctx context.Context, dec func FullMethod: Bidder_GetAllowance_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BidderServer).GetAllowance(ctx, req.(*EmptyMessage)) + return srv.(BidderServer).GetAllowance(ctx, req.(*GetAllowanceRequest)) } return interceptor(ctx, in, info, handler) } diff --git a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml index 5ad93c7f..f3cbaa9f 100644 --- a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml +++ b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml @@ -51,6 +51,13 @@ paths: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' + parameters: + - name: windowNumber + description: Optional window number for querying allowances. If not specified, the current block number is used. + in: query + required: false + type: string + format: uint64 /v1/bidder/get_min_allowance: get: summary: GetMinAllowance diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go new file mode 100644 index 00000000..98f0b325 --- /dev/null +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -0,0 +1,269 @@ +package blocktrackercontract + +import ( + "context" + "fmt" + "log/slog" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" // Update this import path + "github.com/primevprotocol/mev-commit/pkg/evmclient" // Update this import path accordingly +) + +var blockTrackerABI = func() abi.ABI { + abi, err := abi.JSON(strings.NewReader(blocktracker.BlocktrackerMetaData.ABI)) + if err != nil { + panic(err) + } + return abi +}() + +type Interface interface { + // RecordL1Block records a new L1 block and its winner. + RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error + // GetLastL1BlockNumber returns the number of the last L1 block recorded. + GetLastL1BlockNumber(ctx context.Context) (uint64, error) + // GetLastL1BlockWinner returns the winner of the last L1 block recorded. + GetLastL1BlockWinner(ctx context.Context) (common.Address, error) + // GetBlocksPerWindow returns the number of blocks per window. + GetBlocksPerWindow(ctx context.Context) (uint64, error) + // SetBlocksPerWindow sets the number of blocks per window. + SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error + // GetCurrentWindow returns the current window number. + GetCurrentWindow(ctx context.Context) (uint64, error) + // GetBlockWinner returns the winner of a specific block. + GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) +} + +type blockTrackerContract struct { + blockTrackerABI abi.ABI + blockTrackerContractAddr common.Address + client evmclient.Interface + logger *slog.Logger +} + +func New( + blockTrackerContractAddr common.Address, + client evmclient.Interface, + logger *slog.Logger, +) Interface { + return &blockTrackerContract{ + blockTrackerABI: blockTrackerABI, + blockTrackerContractAddr: blockTrackerContractAddr, + client: client, + logger: logger, + } +} + +// RecordL1Block records a new L1 block and its winner. +func (btc *blockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { + callData, err := btc.blockTrackerABI.Pack("recordL1Block", new(big.Int).SetUint64(blockNumber), winner) + if err != nil { + btc.logger.Error("error packing call data for recordL1Block", "error", err) + return err + } + + txnHash, err := btc.client.Send(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return err + } + + receipt, err := btc.client.WaitForReceipt(ctx, txnHash) + if err != nil { + return err + } + + if receipt.Status != types.ReceiptStatusSuccessful { + btc.logger.Error("recordL1Block transaction failed", "txnHash", txnHash, "receipt", receipt) + return err + } + + btc.logger.Info("recordL1Block transaction successful", "txnHash", txnHash) + return nil +} + +// GetLastL1BlockNumber returns the number of the last L1 block recorded. +func (btc *blockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { + callData, err := btc.blockTrackerABI.Pack("getLastL1BlockNumber") + if err != nil { + btc.logger.Error("error packing call data for getLastL1BlockNumber", "error", err) + return 0, err + } + + result, err := btc.client.Call(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return 0, err + } + + results, err := btc.blockTrackerABI.Unpack("getLastL1BlockNumber", result) + if err != nil { + btc.logger.Error("error unpacking result for getLastL1BlockNumber", "error", err) + return 0, err + } + + lastBlockNumber, ok := results[0].(*big.Int) + if !ok { + return 0, fmt.Errorf("invalid result type") + } + + return lastBlockNumber.Uint64(), nil +} + +// GetLastL1BlockWinner returns the winner of the last L1 block recorded. +func (btc *blockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { + callData, err := btc.blockTrackerABI.Pack("getLastL1BlockWinner") + if err != nil { + btc.logger.Error("error packing call data for getLastL1BlockWinner", "error", err) + return common.Address{}, err + } + + result, err := btc.client.Call(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return common.Address{}, err + } + + results, err := btc.blockTrackerABI.Unpack("getLastL1BlockWinner", result) + if err != nil { + btc.logger.Error("error unpacking result for getLastL1BlockWinner", "error", err) + return common.Address{}, err + } + + winnerAddress, ok := results[0].(common.Address) + if !ok { + return common.Address{}, fmt.Errorf("invalid result type") + } + + return winnerAddress, nil +} + +// GetBlocksPerWindow returns the number of blocks per window. +func (btc *blockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { + callData, err := btc.blockTrackerABI.Pack("getBlocksPerWindow") + if err != nil { + btc.logger.Error("error packing call data for getBlocksPerWindow", "error", err) + return 0, err + } + + result, err := btc.client.Call(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return 0, err + } + + results, err := btc.blockTrackerABI.Unpack("getBlocksPerWindow", result) + if err != nil { + btc.logger.Error("error unpacking result for getBlocksPerWindow", "error", err) + return 0, err + } + + blocksPerWindow, ok := results[0].(*big.Int) + if !ok { + return 0, fmt.Errorf("invalid result type") + } + + return blocksPerWindow.Uint64(), nil +} + +// SetBlocksPerWindow sets the number of blocks per window. +func (btc *blockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { + callData, err := btc.blockTrackerABI.Pack("setBlocksPerWindow", new(big.Int).SetUint64(blocksPerWindow)) + if err != nil { + btc.logger.Error("error packing call data for setBlocksPerWindow", "error", err) + return err + } + + txnHash, err := btc.client.Send(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return err + } + + receipt, err := btc.client.WaitForReceipt(ctx, txnHash) + if err != nil { + return err + } + + if receipt.Status != types.ReceiptStatusSuccessful { + btc.logger.Error("setBlocksPerWindow transaction failed", "txnHash", txnHash, "receipt", receipt) + return fmt.Errorf("transaction failed with hash: %s", txnHash.Hex()) + } + + return nil +} + +// GetCurrentWindow returns the current window number. +func (btc *blockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { + callData, err := btc.blockTrackerABI.Pack("getCurrentWindow") + if err != nil { + btc.logger.Error("error packing call data for getCurrentWindow", "error", err) + return 0, err + } + + result, err := btc.client.Call(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return 0, err + } + + results, err := btc.blockTrackerABI.Unpack("getCurrentWindow", result) + if err != nil { + btc.logger.Error("error unpacking result for getCurrentWindow", "error", err) + return 0, err + } + + currentWindow, ok := results[0].(*big.Int) + if !ok { + return 0, fmt.Errorf("invalid result type") + } + + return currentWindow.Uint64(), nil +} + +// GetBlockWinner returns the winner of a specific block. +func (btc *blockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { + callData, err := btc.blockTrackerABI.Pack("getBlockWinner", new(big.Int).SetUint64(blockNumber)) + if err != nil { + btc.logger.Error("error packing call data for getBlockWinner", "error", err) + return common.Address{}, err + } + + result, err := btc.client.Call(ctx, &evmclient.TxRequest{ + To: &btc.blockTrackerContractAddr, + CallData: callData, + }) + if err != nil { + return common.Address{}, err + } + + results, err := btc.blockTrackerABI.Unpack("getBlockWinner", result) + if err != nil { + btc.logger.Error("error unpacking result for getBlockWinner", "error", err) + return common.Address{}, err + } + + winnerAddress, ok := results[0].(common.Address) + if !ok { + return common.Address{}, fmt.Errorf("invalid result type") + } + + return winnerAddress, nil +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 25b5006f..2d5ab2d4 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -20,6 +20,7 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" "github.com/primevprotocol/mev-commit/pkg/apiserver" bidder_registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/bidder_registry" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" provider_registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/provider_registry" "github.com/primevprotocol/mev-commit/pkg/debugapi" @@ -58,6 +59,7 @@ type Options struct { RPCAddr string Bootnodes []string PreconfContract string + BlockTrackerContract string ProviderRegistryContract string BidderRegistryContract string RPCEndpoint string @@ -187,6 +189,15 @@ func NewNode(opts *Options) (*Node, error) { commitmentDA preconfcontract.Interface = noOpCommitmentDA{} ) + blockTrackerAddr := common.HexToAddress(opts.PreconfContract) + + blockTracker := blocktrackercontract.New( + blockTrackerAddr, + evmClient, + opts.Logger.With("component", "blocktrackercontract"), + ) + + switch opts.PeerType { case p2p.PeerTypeProvider.String(): providerAPI := providerapi.NewService( @@ -215,6 +226,7 @@ func NewNode(opts *Options) (*Node, error) { bidderRegistry, bidProcessor, commitmentDA, + blockTracker, opts.Logger.With("component", "preconfirmation_protocol"), ) // Only register handler for provider @@ -238,6 +250,7 @@ func NewNode(opts *Options) (*Node, error) { bidderRegistry, bidProcessor, commitmentDA, + blockTracker, opts.Logger.With("component", "preconfirmation_protocol"), ) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) @@ -246,6 +259,7 @@ func NewNode(opts *Options) (*Node, error) { preconfProto, opts.KeySigner.GetAddress(), bidderRegistry, + blockTracker, validator, opts.Logger.With("component", "bidderapi"), ) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index a32ec80f..d09d31b9 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -4,12 +4,14 @@ import ( "context" "errors" "log/slog" + "math/big" "sync" "time" "github.com/ethereum/go-ethereum/common" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" "github.com/primevprotocol/mev-commit/pkg/p2p" encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" @@ -30,6 +32,7 @@ type Preconfirmation struct { us BidderStore processer BidProcessor commitmentDA preconfcontract.Interface + blockTracker blocktrackercontract.Interface logger *slog.Logger metrics *metrics } @@ -39,7 +42,7 @@ type Topology interface { } type BidderStore interface { - CheckBidderAllowance(context.Context, common.Address) bool + CheckBidderAllowance(context.Context, common.Address, *big.Int) bool } type BidProcessor interface { @@ -53,6 +56,7 @@ func New( us BidderStore, processor BidProcessor, commitmentDA preconfcontract.Interface, + blockTracker blocktrackercontract.Interface, logger *slog.Logger, ) *Preconfirmation { return &Preconfirmation{ @@ -62,6 +66,7 @@ func New( us: us, processer: processor, commitmentDA: commitmentDA, + blockTracker: blockTracker, logger: logger, metrics: newMetrics(), } @@ -210,9 +215,14 @@ func (p *Preconfirmation) handleBid( if err != nil { return err } + + window, err := p.blockTracker.GetCurrentWindow(ctx) + if err != nil { + p.logger.Error("getting window", "error", err) + return status.Errorf(codes.Internal, "failed to get window: %v", err) + } - // todo: change to take care of double spend - if !p.us.CheckBidderAllowance(ctx, *ethAddress) { + if !p.us.CheckBidderAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window)) { p.logger.Error("bidder does not have enough allowance", "ethAddress", ethAddress) return status.Errorf(codes.FailedPrecondition, "bidder not allowed") } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 191af125..e0f6eadd 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -7,13 +7,14 @@ import ( "crypto/rand" "io" "log/slog" + "math/big" "os" "testing" "time" "github.com/ethereum/go-ethereum/common" - preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" "github.com/ethereum/go-ethereum/crypto/ecies" + preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" @@ -31,7 +32,7 @@ func (t *testTopo) GetPeers(q topology.Query) []p2p.Peer { type testBidderStore struct{} -func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Address) bool { +func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Address, _ *big.Int) bool { return true } @@ -94,6 +95,49 @@ func (t *testCommitmentDA) Close() error { return nil } +type testBlockTrackerContract struct { + blockNumberToWinner map[uint64]common.Address + lastBlockNumber uint64 + lastBlockWinner common.Address + blocksPerWindow uint64 +} + +// RecordBlock records a new block and its winner. +func (btc *testBlockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { + btc.lastBlockNumber = blockNumber + btc.lastBlockWinner = winner + btc.blockNumberToWinner[blockNumber] = winner + return nil +} + +func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { + return btc.blockNumberToWinner[blockNumber], nil +} + +// GetCurrentWindow returns the current window number. +func (btc *testBlockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { + return btc.lastBlockNumber / btc.blocksPerWindow, nil +} + +func (btc *testBlockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { + return btc.lastBlockWinner, nil +} + +func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { + return btc.lastBlockNumber, nil +} + +// SetBlocksPerWindow sets the number of blocks per window. +func (btc *testBlockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { + btc.blocksPerWindow = blocksPerWindow + return nil +} + +// GetBlocksPerWindow returns the number of blocks per window. +func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { + return btc.blocksPerWindow, nil +} + func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { t.Helper() @@ -180,6 +224,7 @@ func TestPreconfBidSubmission(t *testing.T) { us, proc, &testCommitmentDA{}, + &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, newTestLogger(t, os.Stdout), ) diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 9642d88d..c93cb831 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -13,34 +13,38 @@ import ( bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfirmationv1 "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/bidder_registry" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type Service struct { bidderapiv1.UnimplementedBidderServer - sender PreconfSender - owner common.Address - registryContract registrycontract.Interface - logger *slog.Logger - metrics *metrics - validator *protovalidate.Validator + sender PreconfSender + owner common.Address + registryContract registrycontract.Interface + blockTrackerContract blocktrackercontract.Interface + logger *slog.Logger + metrics *metrics + validator *protovalidate.Validator } func NewService( sender PreconfSender, owner common.Address, registryContract registrycontract.Interface, + blockTrackerContract blocktrackercontract.Interface, validator *protovalidate.Validator, logger *slog.Logger, ) *Service { return &Service{ - sender: sender, - owner: owner, - registryContract: registryContract, - logger: logger, - metrics: newMetrics(), - validator: validator, + sender: sender, + owner: owner, + registryContract: registryContract, + blockTrackerContract: blockTrackerContract, + logger: logger, + metrics: newMetrics(), + validator: validator, } } @@ -122,7 +126,12 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "prepaying allowance: %v", err) } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner) + currentWindow, err := s.blockTrackerContract.GetCurrentWindow(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting current window: %v", err) + } + + stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, new(big.Int).SetUint64(currentWindow+1)) if err != nil { return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } @@ -132,9 +141,21 @@ func (s *Service) PrepayAllowance( func (s *Service) GetAllowance( ctx context.Context, - _ *bidderapiv1.EmptyMessage, + r *bidderapiv1.GetAllowanceRequest, ) (*bidderapiv1.PrepayResponse, error) { - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner) + var ( + window uint64 + err error + ) + if r.WindowNumber == nil { + window, err = s.blockTrackerContract.GetCurrentWindow(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting current window: %v", err) + } + } else { + window = r.WindowNumber.Value + } + stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, new(big.Int).SetUint64(window)) if err != nil { return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 9fed9da1..238601a0 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -16,6 +16,7 @@ import ( bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" + "google.golang.org/protobuf/types/known/wrapperspb" "github.com/primevprotocol/mev-commit/pkg/util" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -84,7 +85,7 @@ func (t *testRegistryContract) PrepayAllowance(ctx context.Context, amount *big. return nil } -func (t *testRegistryContract) GetAllowance(ctx context.Context, address common.Address) (*big.Int, error) { +func (t *testRegistryContract) GetAllowance(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) { return t.allowance, nil } @@ -92,10 +93,54 @@ func (t *testRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, e return t.minAllowance, nil } -func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address common.Address) bool { +func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int) bool { return t.allowance.Cmp(t.minAllowance) > 0 } +type testBlockTrackerContract struct { + blockNumberToWinner map[uint64]common.Address + lastBlockNumber uint64 + lastBlockWinner common.Address + blocksPerWindow uint64 +} + +// RecordBlock records a new block and its winner. +func (btc *testBlockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { + btc.lastBlockNumber = blockNumber + btc.lastBlockWinner = winner + btc.blockNumberToWinner[blockNumber] = winner + return nil +} + +func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { + return btc.blockNumberToWinner[blockNumber], nil +} + +// GetCurrentWindow returns the current window number. +func (btc *testBlockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { + return btc.lastBlockNumber / btc.blocksPerWindow, nil +} + +func (btc *testBlockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { + return btc.lastBlockWinner, nil +} + +func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { + return btc.lastBlockNumber, nil +} + +// SetBlocksPerWindow sets the number of blocks per window. +func (btc *testBlockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { + btc.blocksPerWindow = blocksPerWindow + return nil +} + +// GetBlocksPerWindow returns the number of blocks per window. +func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { + return btc.blocksPerWindow, nil +} + + func startServer(t *testing.T) bidderapiv1.BidderClient { lis := bufconn.Listen(bufferSize) @@ -108,11 +153,12 @@ func startServer(t *testing.T) bidderapiv1.BidderClient { owner := common.HexToAddress("0x00001") registryContract := &testRegistryContract{minAllowance: big.NewInt(100000000000000000)} sender := &testSender{noOfPreconfs: 2} - + blockTrackerContract := &testBlockTrackerContract{blocksPerWindow: 64, blockNumberToWinner: make(map[uint64]common.Address)} srvImpl := bidderapi.NewService( sender, owner, registryContract, + blockTrackerContract, validator, logger, ) @@ -192,7 +238,7 @@ func TestAllowanceHandling(t *testing.T) { }) t.Run("get allowance", func(t *testing.T) { - allowance, err := client.GetAllowance(context.Background(), &bidderapiv1.EmptyMessage{}) + allowance, err := client.GetAllowance(context.Background(), &bidderapiv1.GetAllowanceRequest{WindowNumber: wrapperspb.UInt64(1)}) if err != nil { t.Fatalf("error getting allowance: %v", err) } diff --git a/rpc/bidderapi/v1/bidderapi.proto b/rpc/bidderapi/v1/bidderapi.proto index 09a7cd3c..8fdb10b3 100644 --- a/rpc/bidderapi/v1/bidderapi.proto +++ b/rpc/bidderapi/v1/bidderapi.proto @@ -5,6 +5,7 @@ package bidderapi.v1; import "protoc-gen-openapiv2/options/annotations.proto"; import "google/api/annotations.proto"; import "buf/validate/validate.proto"; +import "google/protobuf/wrappers.proto"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { @@ -36,8 +37,10 @@ service Bidder { // GetAllowance // // GetAllowance is called by the bidder to get its allowance in the bidder registry. - rpc GetAllowance(EmptyMessage) returns (PrepayResponse) { - option (google.api.http) = {get: "/v1/bidder/get_allowance"}; + rpc GetAllowance(GetAllowanceRequest) returns (PrepayResponse) { + option (google.api.http) = { + get: "/v1/bidder/get_allowance" + }; } // GetMinAllowance // @@ -79,6 +82,17 @@ message PrepayResponse { message EmptyMessage {}; +message GetAllowanceRequest { + google.protobuf.UInt64Value windowNumber = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Optional window number for querying allowances. If not specified, the current block number is used." + }, (buf.validate.field).cel = { + id: "windowNumber", + message: "windowNumber must be a positive integer if specified.", + expression: "this.value == null || (this.value > 0)" + }]; +} + message Bid { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { json_schema: { From d8eb30676fc106b1791669e6a33d5935aa64d244 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 1 Apr 2024 11:39:12 +0200 Subject: [PATCH 08/85] fixed integrationtest --- integrationtest/bidder/main.go | 2 +- integrationtest/real-bidder/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationtest/bidder/main.go b/integrationtest/bidder/main.go index 622e78e5..9d6a94aa 100644 --- a/integrationtest/bidder/main.go +++ b/integrationtest/bidder/main.go @@ -217,7 +217,7 @@ func checkOrPrepay( bidderClient pb.BidderClient, logger *slog.Logger, ) error { - allowance, err := bidderClient.GetAllowance(context.Background(), &pb.EmptyMessage{}) + allowance, err := bidderClient.GetAllowance(context.Background(), &pb.GetAllowanceRequest{}) if err != nil { logger.Error("failed to get allowance", "error", err) return err diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index 227b69c2..4a60a040 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -185,7 +185,7 @@ func checkOrPrepay( bidderClient pb.BidderClient, logger *slog.Logger, ) error { - allowance, err := bidderClient.GetAllowance(context.Background(), &pb.EmptyMessage{}) + allowance, err := bidderClient.GetAllowance(context.Background(), &pb.GetAllowanceRequest{}) if err != nil { logger.Error("failed to get allowance", "err", err) return err From 62b05824580becfaec7a126e33a774db42f8440e Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 3 Apr 2024 18:50:53 +0200 Subject: [PATCH 09/85] added commitment opening --- .../preconfirmation/v1/preconfirmation.pb.go | 59 +++-- go.mod | 2 +- go.sum | 2 + .../preconfirmation/v1/preconfirmation.proto | 1 + .../bidder_registry/bidder_registry.go | 6 +- .../bidder_registry/bidder_registry_test.go | 12 +- pkg/contracts/block_tracker/block_tracker.go | 50 +++- pkg/contracts/preconf/preconf.go | 101 +++++++- pkg/contracts/preconf/preconf_test.go | 2 +- pkg/evmclient/evm.go | 4 + pkg/evmclient/evmclient.go | 10 + pkg/evmclient/mock/mock.go | 49 +++- pkg/evmclient/mockevm/mockevm.go | 32 +++ pkg/node/node.go | 36 ++- pkg/preconfirmation/preconfirmation.go | 226 +++++++++++++++--- pkg/preconfirmation/preconfirmation_test.go | 82 ++++--- pkg/rpc/bidder/service_test.go | 7 +- pkg/signer/preconfencryptor/encryptor.go | 36 +-- pkg/signer/preconfencryptor/encryptor_test.go | 4 +- 19 files changed, 592 insertions(+), 129 deletions(-) diff --git a/gen/go/preconfirmation/v1/preconfirmation.pb.go b/gen/go/preconfirmation/v1/preconfirmation.pb.go index e7e0cc1d..464c1418 100644 --- a/gen/go/preconfirmation/v1/preconfirmation.pb.go +++ b/gen/go/preconfirmation/v1/preconfirmation.pb.go @@ -254,8 +254,9 @@ type EncryptedPreConfirmation struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Commitment []byte `protobuf:"bytes,1,opt,name=commitment,proto3" json:"commitment,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + Commitment []byte `protobuf:"bytes,1,opt,name=commitment,proto3" json:"commitment,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + CommitmentIndex []byte `protobuf:"bytes,3,opt,name=commitmentIndex,proto3" json:"commitmentIndex,omitempty"` } func (x *EncryptedPreConfirmation) Reset() { @@ -304,6 +305,13 @@ func (x *EncryptedPreConfirmation) GetSignature() []byte { return nil } +func (x *EncryptedPreConfirmation) GetCommitmentIndex() []byte { + if x != nil { + return x.CommitmentIndex + } + return nil +} + var File_preconfirmation_v1_preconfirmation_proto protoreflect.FileDescriptor var file_preconfirmation_v1_preconfirmation_proto_rawDesc = []byte{ @@ -344,28 +352,31 @@ var file_preconfirmation_v1_preconfirmation_proto_rawDesc = []byte{ 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, - 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x58, 0x0a, 0x18, 0x45, 0x6e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 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, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x42, 0xe9, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x65, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x50, - 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x50, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x12, - 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x56, 0x31, 0xca, 0x02, 0x12, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50, 0x72, 0x65, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x82, 0x01, 0x0a, 0x18, 0x45, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0xe9, 0x01, + 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x50, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, + 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, + 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, + 0x3b, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x76, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x12, 0x50, 0x72, 0x65, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, + 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/go.mod b/go.mod index 5c0b6fb9..66a2d635 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.4-0.20240328210357-00b3c4b870a6 + github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index ac6ada77..7968f008 100644 --- a/go.sum +++ b/go.sum @@ -342,6 +342,8 @@ github.com/primevprotocol/contracts-abi v0.2.4-0.20240319201845-0e7b67b8e539 h1: github.com/primevprotocol/contracts-abi v0.2.4-0.20240319201845-0e7b67b8e539/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240328210357-00b3c4b870a6 h1:tyEa3/qAkvc21mQg/diqNP5iVAmc4acF+1P/5/sM3Ag= github.com/primevprotocol/contracts-abi v0.2.4-0.20240328210357-00b3c4b870a6/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a h1:bSmtNx7BXLtnKiOP4Ku8xpKIumScyBl96bb5hcBvvV8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= diff --git a/messages/preconfirmation/v1/preconfirmation.proto b/messages/preconfirmation/v1/preconfirmation.proto index 7acfa9ba..5a6e0fc8 100644 --- a/messages/preconfirmation/v1/preconfirmation.proto +++ b/messages/preconfirmation/v1/preconfirmation.proto @@ -28,4 +28,5 @@ message PreConfirmation { message EncryptedPreConfirmation { bytes commitment = 1; bytes signature = 2; + bytes commitmentIndex = 3; } \ No newline at end of file diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 35c89277..63d02783 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -29,7 +29,7 @@ type Interface interface { // GetMinAllowance returns the minimum stake required to register as a bidder. GetMinAllowance(ctx context.Context) (*big.Int, error) // CheckBidderRegistred returns true if bidder is registered - CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int) bool + CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int, blocksPerWindow *big.Int) bool } type bidderRegistryContract struct { @@ -143,6 +143,7 @@ func (r *bidderRegistryContract) CheckBidderAllowance( ctx context.Context, address common.Address, window *big.Int, + blocksPerWindow *big.Int, ) bool { minStake, err := r.GetMinAllowance(ctx) if err != nil { @@ -155,6 +156,5 @@ func (r *bidderRegistryContract) CheckBidderAllowance( r.logger.Error("error getting stake", "error", err) return false } - - return stake.Cmp(minStake) >= 0 + return (stake.Div(stake, blocksPerWindow)).Cmp(minStake) >= 0 } diff --git a/pkg/contracts/bidder_registry/bidder_registry_test.go b/pkg/contracts/bidder_registry/bidder_registry_test.go index 00b69ea3..5bab50ee 100644 --- a/pkg/contracts/bidder_registry/bidder_registry_test.go +++ b/pkg/contracts/bidder_registry/bidder_registry_test.go @@ -165,12 +165,16 @@ func TestBidderRegistryContract(t *testing.T) { t.Run("CheckBidderAllowance", func(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) + blocksPerWindow := big.NewInt(64) + amount := new(big.Int).Mul(big.NewInt(1000000000000000000), blocksPerWindow) address := common.HexToAddress("abcdef") + callCount := 0 + mockClient := mockevmclient.New( mockevmclient.WithCallFunc( func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { + callCount++; if req.To.Cmp(registryContractAddr) != 0 { t.Fatalf( "expected to address to be %s, got %s", @@ -178,6 +182,10 @@ func TestBidderRegistryContract(t *testing.T) { ) } + if callCount == 1 { + return new(big.Int).Div(amount, blocksPerWindow).FillBytes(make([]byte, 32)), nil + } + return amount.FillBytes(make([]byte, 32)), nil }, ), @@ -190,7 +198,7 @@ func TestBidderRegistryContract(t *testing.T) { ) window := big.NewInt(1) - isRegistered := registryContract.CheckBidderAllowance(context.Background(), address, window) + isRegistered := registryContract.CheckBidderAllowance(context.Background(), address, window, blocksPerWindow) if !isRegistered { t.Fatal("expected bidder to be registered") } diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 98f0b325..0278c3fb 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -7,11 +7,12 @@ import ( "math/big" "strings" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" // Update this import path - "github.com/primevprotocol/mev-commit/pkg/evmclient" // Update this import path accordingly + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" + "github.com/primevprotocol/mev-commit/pkg/evmclient" ) var blockTrackerABI = func() abi.ABI { @@ -37,6 +38,8 @@ type Interface interface { GetCurrentWindow(ctx context.Context) (uint64, error) // GetBlockWinner returns the winner of a specific block. GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) + // SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. + SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) } type blockTrackerContract struct { @@ -46,6 +49,12 @@ type blockTrackerContract struct { logger *slog.Logger } +type NewL1BlockEvent struct { + BlockNumber *big.Int + Winner common.Address + Window *big.Int +} + func New( blockTrackerContractAddr common.Address, client evmclient.Interface, @@ -267,3 +276,40 @@ func (btc *blockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber return winnerAddress, nil } + +// SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. +func (btc *blockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) { + query := ethereum.FilterQuery{ + Addresses: []common.Address{btc.blockTrackerContractAddr}, + Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, + } + + logsCh := make(chan types.Log) + sub, err := btc.client.SubscribeFilterLogs(ctx, query, logsCh) + if err != nil { + return nil, err + } + + go func() { + for { + select { + case log := <-logsCh: + event := NewL1BlockEvent{} + err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) + if err != nil { + btc.logger.Error("error unpacking NewL1Block event", "error", err) + continue + } + event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) + event.Winner = common.HexToAddress(log.Topics[2].Hex()) + event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) + eventCh <- event + case <-ctx.Done(): + sub.Unsubscribe() + return + } + } + }() + + return sub, nil +} diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 632f8b80..934640f4 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -2,7 +2,9 @@ package preconfcontract import ( "context" + "fmt" "log/slog" + "math/big" "strings" "time" @@ -27,7 +29,19 @@ type Interface interface { ctx context.Context, commitmentDigest []byte, commitmentSignature []byte, - ) error + ) (common.Hash, error) + OpenCommitment( + ctx context.Context, + encryptedCommitmentIndex []byte, + bid string, + blockNumber int64, + txnHash string, + decayStartTimeStamp int64, + decayEndTimeStamp int64, + bidSignature []byte, + commitmentSignature []byte, + sharedSecretKey []byte, + ) (common.Hash, error) } type preconfContract struct { @@ -54,8 +68,7 @@ func (p *preconfContract) StoreEncryptedCommitment( ctx context.Context, commitmentDigest []byte, commitmentSignature []byte, -) error { - +) (common.Hash, error) { callData, err := p.preconfABI.Pack( "storeEncryptedCommitment", [32]byte(commitmentDigest), @@ -63,7 +76,7 @@ func (p *preconfContract) StoreEncryptedCommitment( ) if err != nil { p.logger.Error("preconf contract storeEncryptedCommitment pack error", "err", err) - return err + return common.Hash{}, err } txnHash, err := p.client.Send(ctx, &evmclient.TxRequest{ @@ -71,10 +84,86 @@ func (p *preconfContract) StoreEncryptedCommitment( CallData: callData, }) if err != nil { - return err + return common.Hash{}, err + } + + receipt, err := p.client.WaitForReceipt(ctx, txnHash) + if err != nil { + return common.Hash{}, err // Updated to return common.Hash{} } p.logger.Info("preconf contract storeEncryptedCommitment successful", "txnHash", txnHash) + eventTopicHash := p.preconfABI.Events["EncryptedCommitmentStored"].ID // This is the event signature hash + + for _, log := range receipt.Logs { + if len(log.Topics) > 0 && log.Topics[0] == eventTopicHash { + commitmentIndex := log.Topics[1] // Topics[0] is the event signature, Topics[1] should be the first indexed argument + p.logger.Info("Encrypted commitment stored", "commitmentIndex", commitmentIndex.Hex()) + + return commitmentIndex, nil // Return the extracted commitmentIndex + } + } + + return common.Hash{}, nil +} + +func (p *preconfContract) OpenCommitment( + ctx context.Context, + encryptedCommitmentIndex []byte, + bid string, + blockNumber int64, + txnHash string, + decayStartTimeStamp int64, + decayEndTimeStamp int64, + bidSignature []byte, + commitmentSignature []byte, + sharedSecretKey []byte, +) (common.Hash, error) { + bidAmt, _ := new(big.Int).SetString(bid, 10) + callData, err := p.preconfABI.Pack( + "openCommitment", + encryptedCommitmentIndex, + bidAmt, + big.NewInt(blockNumber), + txnHash, + big.NewInt(decayStartTimeStamp), + big.NewInt(decayEndTimeStamp), + bidSignature, + commitmentSignature, + sharedSecretKey, + ) + if err != nil { + p.logger.Error("Error packing call data for openCommitment", "error", err) + return common.Hash{}, err + } + + txHash, err := p.client.Send(ctx, &evmclient.TxRequest{ + To: &p.preconfContractAddr, + CallData: callData, + }) + if err != nil { + return common.Hash{}, err + } + + receipt, err := p.client.WaitForReceipt(ctx, txHash) + if err != nil { + return common.Hash{}, err + } + + p.logger.Info("OpenCommitment transaction successful", "txnHash", txnHash) + + // Assuming "CommitmentOpened" is the event that gets emitted when openCommitment is successfully called + eventTopicHash := p.preconfABI.Events["CommitmentOpened"].ID + + for _, log := range receipt.Logs { + if len(log.Topics) > 0 && log.Topics[0] == eventTopicHash { + // Assuming the first indexed argument (Topics[1]) is the commitmentIndex + commitmentIndex := log.Topics[1] + p.logger.Info("Commitment opened", "commitmentIndex", commitmentIndex.Hex()) + + return commitmentIndex, nil + } + } - return nil + return common.Hash{}, fmt.Errorf("commitmentIndex not found in transaction receipt") } diff --git a/pkg/contracts/preconf/preconf_test.go b/pkg/contracts/preconf/preconf_test.go index c62b7323..0d3f8571 100644 --- a/pkg/contracts/preconf/preconf_test.go +++ b/pkg/contracts/preconf/preconf_test.go @@ -66,7 +66,7 @@ func TestPreconfContract(t *testing.T) { util.NewTestLogger(os.Stdout), ) - err = preConfContractClient.StoreEncryptedCommitment( + _, err = preConfContractClient.StoreEncryptedCommitment( context.Background(), commitment[:], commitmentSignature, diff --git a/pkg/evmclient/evm.go b/pkg/evmclient/evm.go index 65b7499b..50916a51 100644 --- a/pkg/evmclient/evm.go +++ b/pkg/evmclient/evm.go @@ -72,6 +72,8 @@ type EVM interface { NetworkID(ctx context.Context) (*big.Int, error) // BlockNumber returns the most recent block number BlockNumber(ctx context.Context) (uint64, error) + // BlockByNumber returns the block identified by number. + BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) // PendingNonceAt retrieves the current pending nonce associated with an account. PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) // NonceAt retrieves the current nonce associated with an account. @@ -101,6 +103,8 @@ type EVM interface { // mined yet. Note that the transaction may not be part of the canonical chain even if // it's not pending. TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) + // FilterLogs executes a filter query to return the logs that satisfy the specified + SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) } type Batcher interface { diff --git a/pkg/evmclient/evmclient.go b/pkg/evmclient/evmclient.go index 434634df..ed583c57 100644 --- a/pkg/evmclient/evmclient.go +++ b/pkg/evmclient/evmclient.go @@ -43,6 +43,8 @@ type Interface interface { WaitForReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) Call(ctx context.Context, tx *TxRequest) ([]byte, error) CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) + SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) + BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) } type EvmClient struct { @@ -383,6 +385,14 @@ func (c *EvmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.H return signedTx.Hash(), nil } +func (c *EvmClient) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, logsCh chan<- types.Log) (ethereum.Subscription, error) { + return c.ethClient.SubscribeFilterLogs(ctx, query, logsCh) +} + +func (c *EvmClient) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) { + return c.ethClient.BlockByNumber(ctx, blockNumber) +} + type TxnInfo struct { Hash string Nonce uint64 diff --git a/pkg/evmclient/mock/mock.go b/pkg/evmclient/mock/mock.go index 62d7bfe8..ee6b48c6 100644 --- a/pkg/evmclient/mock/mock.go +++ b/pkg/evmclient/mock/mock.go @@ -3,7 +3,9 @@ package mockevmclient import ( "context" "errors" + "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/primevprotocol/mev-commit/pkg/evmclient" @@ -51,11 +53,29 @@ func WithCancelFunc( } } +func WithSubscribeFilterLogs( + f func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error), +) Option { + return func(m *mockEvmClient) { + m.SubscribeFilterLogsFunc = f + } +} + +func WithBlockByNumber( + f func(ctx context.Context, number *big.Int) (*types.Block, error), +) Option { + return func(m *mockEvmClient) { + m.BlockByNumberFunc = f + } +} + type mockEvmClient struct { - SendFunc func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) - WaitForReceiptFunc func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) - CallFunc func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) - CancelFunc func(ctx context.Context, txHash common.Hash) (common.Hash, error) + SendFunc func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) + WaitForReceiptFunc func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) + CallFunc func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) + CancelFunc func(ctx context.Context, txHash common.Hash) (common.Hash, error) + SubscribeFilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) + BlockByNumberFunc func(ctx context.Context, number *big.Int) (*types.Block, error) } func (m *mockEvmClient) Send( @@ -91,3 +111,24 @@ func (m *mockEvmClient) CancelTx(ctx context.Context, txHash common.Hash) (commo } return m.CancelFunc(ctx, txHash) } + +func (m *mockEvmClient) SubscribeFilterLogs( + ctx context.Context, + query ethereum.FilterQuery, + ch chan<- types.Log, +) (ethereum.Subscription, error) { + if m.SubscribeFilterLogsFunc == nil { + return nil, errors.New("not implemented") + } + return m.SubscribeFilterLogsFunc(ctx, query, ch) +} + +func (m *mockEvmClient) BlockByNumber( + ctx context.Context, + number *big.Int, +) (*types.Block, error) { + if m.BlockByNumberFunc == nil { + return nil, errors.New("not implemented") + } + return m.BlockByNumber(ctx, number) +} diff --git a/pkg/evmclient/mockevm/mockevm.go b/pkg/evmclient/mockevm/mockevm.go index 1a07e1a1..bcc11efb 100644 --- a/pkg/evmclient/mockevm/mockevm.go +++ b/pkg/evmclient/mockevm/mockevm.go @@ -16,6 +16,7 @@ type mockEvm struct { networkID *big.Int batcherFunc func() evmclient.Batcher blockNumFunc func(ctx context.Context) (uint64, error) + blockByNumberFunc func(ctx context.Context, blockNumber *big.Int) (*types.Block, error) pendingNonceAtFunc func(ctx context.Context, account common.Address) (uint64, error) nonceAtFunc func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) suggestGasPriceFunc func(ctx context.Context) (*big.Int, error) @@ -25,6 +26,7 @@ type mockEvm struct { callContractFunc func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) transactionReceiptFunc func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) transactionByHasFunc func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) + subscribeLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) } type Option func(*mockEvm) @@ -49,6 +51,12 @@ func WithBlockNumFunc(blockNumFunc func(ctx context.Context) (uint64, error)) Op } } +func WithBlockByNumberFunc(blockByNumberFunc func(ctx context.Context, blockNumber *big.Int) (*types.Block, error)) Option { + return func(m *mockEvm) { + m.blockByNumberFunc = blockByNumberFunc + } +} + func WithPendingNonceAtFunc(pendingNonceAtFunc func(ctx context.Context, account common.Address) (uint64, error)) Option { return func(m *mockEvm) { m.pendingNonceAtFunc = pendingNonceAtFunc @@ -103,6 +111,12 @@ func WithTransactionByHashFunc(transactionByHashFunc func(ctx context.Context, t } } +func WithSubscribeLogsFunc(subscribeLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)) Option { + return func(m *mockEvm) { + m.subscribeLogsFunc = subscribeLogsFunc + } +} + func NewMockEvm(networkID uint64, opts ...Option) *mockEvm { m := &mockEvm{} for _, opt := range opts { @@ -132,6 +146,13 @@ func (m *mockEvm) BlockNumber(ctx context.Context) (uint64, error) { return 0, ErrNotImplemented } +func (m *mockEvm) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) { + if m.blockByNumberFunc != nil { + return m.blockByNumberFunc(ctx, blockNumber) + } + return nil, ErrNotImplemented +} + func (m *mockEvm) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { if m.pendingNonceAtFunc != nil { return m.pendingNonceAtFunc(ctx, account) @@ -204,3 +225,14 @@ func (m *mockEvm) TransactionByHash( } return nil, false, ErrNotImplemented } + +func (m *mockEvm) SubscribeFilterLogs( + ctx context.Context, + query ethereum.FilterQuery, + ch chan<- types.Log, +) (ethereum.Subscription, error) { + if m.subscribeLogsFunc != nil { + return m.subscribeLogsFunc(ctx, query, ch) + } + return nil, ErrNotImplemented +} \ No newline at end of file diff --git a/pkg/node/node.go b/pkg/node/node.go index 2d5ab2d4..609e327d 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -63,6 +63,7 @@ type Options struct { ProviderRegistryContract string BidderRegistryContract string RPCEndpoint string + L1RPCUrl string NatAddr string TLSCertificateFile string TLSPrivateKeyFile string @@ -94,6 +95,17 @@ func NewNode(opts *Options) (*Node, error) { } nd.closers = append(nd.closers, evmClient) + l1RPC, err := ethclient.Dial(opts.L1RPCUrl) + evmL1Client, err := evmclient.New( + opts.KeySigner, + evmclient.WrapEthClient(l1RPC), + opts.Logger.With("component", "evmclient"), + ) + if err != nil { + return nil, err + } + nd.closers = append(nd.closers, evmL1Client) + srv.MetricsRegistry().MustRegister(evmClient.Metrics()...) bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) @@ -197,7 +209,6 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "blocktrackercontract"), ) - switch opts.PeerType { case p2p.PeerTypeProvider.String(): providerAPI := providerapi.NewService( @@ -220,6 +231,7 @@ func NewNode(opts *Options) (*Node, error) { ) preconfProto := preconfirmation.New( + keyKeeper.GetAddress(), topo, p2pSvc, preconfEncryptor, @@ -227,6 +239,7 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, + evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) // Only register handler for provider @@ -244,6 +257,7 @@ func NewNode(opts *Options) (*Node, error) { case p2p.PeerTypeBidder.String(): preconfProto := preconfirmation.New( + keyKeeper.GetAddress(), topo, p2pSvc, preconfEncryptor, @@ -251,6 +265,7 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, + evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) @@ -422,8 +437,23 @@ func (noOpCommitmentDA) StoreEncryptedCommitment( _ context.Context, _ []byte, _ []byte, -) error { - return nil +) (common.Hash, error) { + return common.Hash{}, nil +} + +func (noOpCommitmentDA) OpenCommitment( + _ context.Context, + _ []byte, + _ string, + _ int64, + _ string, + _ int64, + _ int64, + _ []byte, + _ []byte, + _ []byte, +) (common.Hash, error) { + return common.Hash{}, nil } func (noOpCommitmentDA) Close() error { diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index d09d31b9..e17f89dc 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -13,6 +13,7 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" + "github.com/primevprotocol/mev-commit/pkg/evmclient" "github.com/primevprotocol/mev-commit/pkg/p2p" encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" @@ -25,16 +26,26 @@ const ( ProtocolVersion = "1.0.0" ) +type EncryptedPreConfirmationWithDecrypted struct { + *preconfpb.EncryptedPreConfirmation + *preconfpb.PreConfirmation +} + type Preconfirmation struct { - encryptor encryptor.Encryptor - topo Topology - streamer p2p.Streamer - us BidderStore - processer BidProcessor - commitmentDA preconfcontract.Interface - blockTracker blocktrackercontract.Interface - logger *slog.Logger - metrics *metrics + owner common.Address + // todo: store the bids in a database + commitmentByTxHashes map[string]*EncryptedPreConfirmationWithDecrypted + commitmentsByProvidersByBlockNumbers map[int64]map[string]*EncryptedPreConfirmationWithDecrypted + encryptor encryptor.Encryptor + topo Topology + streamer p2p.Streamer + us BidderStore + processer BidProcessor + commitmentDA preconfcontract.Interface + blockTracker blocktrackercontract.Interface + evmL1Client evmclient.Interface + logger *slog.Logger + metrics *metrics } type Topology interface { @@ -42,7 +53,7 @@ type Topology interface { } type BidderStore interface { - CheckBidderAllowance(context.Context, common.Address, *big.Int) bool + CheckBidderAllowance(context.Context, common.Address, *big.Int, *big.Int) bool } type BidProcessor interface { @@ -50,6 +61,7 @@ type BidProcessor interface { } func New( + owner common.Address, topo Topology, streamer p2p.Streamer, encryptor encryptor.Encryptor, @@ -57,18 +69,24 @@ func New( processor BidProcessor, commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, + evmL1Client evmclient.Interface, logger *slog.Logger, ) *Preconfirmation { + commitmentByTxHashes := make(map[string]*EncryptedPreConfirmationWithDecrypted) + commitmentsByProvidersByBlockNumbers := make(map[int64]map[string]*EncryptedPreConfirmationWithDecrypted) return &Preconfirmation{ - topo: topo, - streamer: streamer, - encryptor: encryptor, - us: us, - processer: processor, - commitmentDA: commitmentDA, - blockTracker: blockTracker, - logger: logger, - metrics: newMetrics(), + commitmentByTxHashes: commitmentByTxHashes, + commitmentsByProvidersByBlockNumbers: commitmentsByProvidersByBlockNumbers, + topo: topo, + streamer: streamer, + encryptor: encryptor, + us: us, + processer: processor, + commitmentDA: commitmentDA, + blockTracker: blockTracker, + evmL1Client: evmL1Client, + logger: logger, + metrics: newMetrics(), } } @@ -96,12 +114,12 @@ func (p *Preconfirmation) SendBid( decayStartTimestamp int64, decayEndTimestamp int64, ) (chan *preconfpb.PreConfirmation, error) { - bid, signedBid, err := p.encryptor.ConstructEncryptedBid(txHash, bidAmt, blockNumber, decayStartTimestamp, decayEndTimestamp) + bid, encryptedBid, err := p.encryptor.ConstructEncryptedBid(txHash, bidAmt, blockNumber, decayStartTimestamp, decayEndTimestamp) if err != nil { - p.logger.Error("constructing signed bid", "error", err, "txHash", txHash) + p.logger.Error("constructing encrypted bid", "error", err, "txHash", txHash) return nil, err } - p.logger.Info("constructed signed bid", "signedBid", signedBid) + p.logger.Info("constructed encrypted bid", "encryptedBid", encryptedBid) providers := p.topo.GetPeers(topology.Query{Type: p2p.PeerTypeProvider}) if len(providers) == 0 { @@ -131,9 +149,9 @@ func (p *Preconfirmation) SendBid( return } - logger.Info("sending signed bid", "signedBid", signedBid) + logger.Info("sending encrypted bid", "encryptedBid", encryptedBid) - err = providerStream.WriteMsg(ctx, signedBid) + err = providerStream.WriteMsg(ctx, encryptedBid) if err != nil { _ = providerStream.Reset() logger.Error("writing message", "error", err) @@ -152,21 +170,29 @@ func (p *Preconfirmation) SendBid( _ = providerStream.Close() // Process preConfirmation as a bidder - providerAddress, err := p.encryptor.VerifyEncryptedPreConfirmation(provider.Keys.NIKEPublicKey, bid.Digest, encryptedPreConfirmation) + sharedSecretKey, providerAddress, err := p.encryptor.VerifyEncryptedPreConfirmation(provider.Keys.NIKEPublicKey, bid.Digest, encryptedPreConfirmation) if err != nil { logger.Error("verifying provider signature", "error", err) return } preConfirmation := &preconfpb.PreConfirmation{ - Bid: bid, - Digest: encryptedPreConfirmation.Commitment, - Signature: encryptedPreConfirmation.Signature, + Bid: bid, + SharedSecret: sharedSecretKey, + Digest: encryptedPreConfirmation.Commitment, + Signature: encryptedPreConfirmation.Signature, } preConfirmation.ProviderAddress = make([]byte, len(providerAddress)) copy(preConfirmation.ProviderAddress, providerAddress[:]) + if p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber] == nil { + p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber] = make(map[string]*EncryptedPreConfirmationWithDecrypted) + } + p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber][providerAddress.String()] = &EncryptedPreConfirmationWithDecrypted{ + EncryptedPreConfirmation: encryptedPreConfirmation, + PreConfirmation: preConfirmation, + } logger.Info("received preconfirmation", "preConfirmation", preConfirmation) p.metrics.ReceivedPreconfsCount.Inc() @@ -215,14 +241,20 @@ func (p *Preconfirmation) handleBid( if err != nil { return err } - + window, err := p.blockTracker.GetCurrentWindow(ctx) if err != nil { p.logger.Error("getting window", "error", err) return status.Errorf(codes.Internal, "failed to get window: %v", err) } - if !p.us.CheckBidderAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window)) { + blocksPerWindow, err := p.blockTracker.GetBlocksPerWindow(ctx) + if err != nil { + p.logger.Error("getting blocks per window", "error", err) + return status.Errorf(codes.Internal, "failed to get blocks per window: %v", err) + } + + if !p.us.CheckBidderAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window), new(big.Int).SetUint64(blocksPerWindow)) { p.logger.Error("bidder does not have enough allowance", "ethAddress", ethAddress) return status.Errorf(codes.FailedPrecondition, "bidder not allowed") } @@ -243,23 +275,141 @@ func (p *Preconfirmation) handleBid( case providerapiv1.BidResponse_STATUS_REJECTED: return status.Errorf(codes.Internal, "bid rejected") case providerapiv1.BidResponse_STATUS_ACCEPTED: - preConfirmation, err := p.encryptor.ConstructEncryptedPreConfirmation(bid) + preConfirmation, encryptedPreConfirmation, err := p.encryptor.ConstructEncryptedPreConfirmation(bid) if err != nil { return status.Errorf(codes.Internal, "failed to constuct encrypted preconfirmation: %v", err) } - p.logger.Info("sending preconfirmation", "preConfirmation", preConfirmation) - // todo: update SC - err = p.commitmentDA.StoreEncryptedCommitment( + p.logger.Info("sending preconfirmation", "preConfirmation", encryptedPreConfirmation) + commitmentIndex, err := p.commitmentDA.StoreEncryptedCommitment( ctx, - preConfirmation.Commitment, - preConfirmation.Signature, + encryptedPreConfirmation.Commitment, + encryptedPreConfirmation.Signature, ) if err != nil { p.logger.Error("storing commitment", "error", err) - return status.Errorf(codes.Internal, "failed to store commitments: %v", err) + return status.Errorf(codes.Internal, "failed to store commitments: %v", err) } - return stream.WriteMsg(ctx, preConfirmation) + + encryptedPreConfirmation.CommitmentIndex = commitmentIndex.Bytes() + p.commitmentByTxHashes[bid.TxHash] = &EncryptedPreConfirmationWithDecrypted{ + EncryptedPreConfirmation: encryptedPreConfirmation, + PreConfirmation: preConfirmation, + } + return stream.WriteMsg(ctx, encryptedPreConfirmation) } } return nil } + +func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { + ch := make(chan blocktrackercontract.NewL1BlockEvent) + sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) // Use ctx instead of context.Background() + if err != nil { + p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) + return + } + defer sub.Unsubscribe() + + for { + select { + case event := <-ch: + handler(ctx, event) // Call the handler function + case err := <-sub.Err(): + p.logger.Error("Subscription error", "error", err) + return + case <-ctx.Done(): // Handle cancellation + p.logger.Info("Subscription context cancelled") + return + } + } +} + +func (p *Preconfirmation) handleProviderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { + p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) + + block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) + if err != nil { + p.logger.Error("Failed to fetch block", "blockNumber", event.BlockNumber, "error", err) + return + } + + validatorAddress := block.Coinbase() + peerAddress := p.owner + + if validatorAddress != peerAddress { + return + } + + for _, tx := range block.Transactions() { + commitment := p.commitmentByTxHashes[tx.Hash().String()] + if commitment == nil { + continue + } + _, err := p.commitmentDA.OpenCommitment( + context.Background(), + commitment.EncryptedPreConfirmation.CommitmentIndex, + commitment.Bid.BidAmount, + commitment.Bid.BlockNumber, + commitment.Bid.TxHash, + commitment.Bid.DecayStartTimestamp, + commitment.Bid.DecayEndTimestamp, + commitment.Bid.Signature, + commitment.PreConfirmation.Signature, + commitment.PreConfirmation.SharedSecret, + ) + if err != nil { + p.logger.Error("Failed to open commitment", "error", err) + return + } + p.logger.Info("Opened commitment", "txHash", tx.Hash().String()) + delete(p.commitmentByTxHashes, tx.Hash().String()) + } +} + + +func (p *Preconfirmation) handleBidderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { + p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) + + block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) + if err != nil { + p.logger.Error("Failed to fetch block", "blockNumber", event.BlockNumber, "error", err) + return + } + + validatorAddress := block.Coinbase() + // todo: with that approach only one bid could be in the block, fix this + commitment := p.commitmentsByProvidersByBlockNumbers[event.BlockNumber.Int64()][validatorAddress.String()] + + if commitment == nil { + return + } + isTxPresent := false + for _, tx := range block.Transactions() { + if tx.Hash().String() == commitment.Bid.TxHash { + isTxPresent = true + break + } + } + + if isTxPresent { + return + } + + _, err = p.commitmentDA.OpenCommitment( + ctx, + commitment.EncryptedPreConfirmation.CommitmentIndex, + commitment.Bid.BidAmount, + commitment.Bid.BlockNumber, + commitment.Bid.TxHash, + commitment.Bid.DecayStartTimestamp, + commitment.Bid.DecayEndTimestamp, + commitment.Bid.Signature, + commitment.PreConfirmation.Signature, + commitment.PreConfirmation.SharedSecret, + ) + if err != nil { + p.logger.Error("Failed to open commitment", "error", err) + return + } + p.logger.Info("Opened commitment", "txHash", commitment.Bid.TxHash) +} diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index e0f6eadd..28b91508 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -12,10 +12,13 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" + mockevmclient "github.com/primevprotocol/mev-commit/pkg/evmclient/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" @@ -32,25 +35,27 @@ func (t *testTopo) GetPeers(q topology.Query) []p2p.Peer { type testBidderStore struct{} -func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Address, _ *big.Int) bool { +func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Address, _ *big.Int, _ *big.Int) bool { return true } type testEncryptor struct { - bidHash []byte - encryptedBid *preconfpb.EncryptedBid - bid *preconfpb.Bid - preConfirmation *preconfpb.EncryptedPreConfirmation - bidSigner common.Address - preConfirmationSigner common.Address + bidHash []byte + encryptedBid *preconfpb.EncryptedBid + bid *preconfpb.Bid + encryptedPreConfirmation *preconfpb.EncryptedPreConfirmation + preConfirmation *preconfpb.PreConfirmation + sharedSecretKey []byte + bidSigner common.Address + preConfirmationSigner common.Address } func (t *testEncryptor) ConstructEncryptedBid(_ string, _ string, _ int64, _ int64, _ int64) (*preconfpb.Bid, *preconfpb.EncryptedBid, error) { return t.bid, t.encryptedBid, nil } -func (t *testEncryptor) ConstructEncryptedPreConfirmation(_ *preconfpb.Bid) (*preconfpb.EncryptedPreConfirmation, error) { - return t.preConfirmation, nil +func (t *testEncryptor) ConstructEncryptedPreConfirmation(_ *preconfpb.Bid) (*preconfpb.PreConfirmation, *preconfpb.EncryptedPreConfirmation, error) { + return t.preConfirmation, t.encryptedPreConfirmation, nil } func (t *testEncryptor) VerifyBid(_ *preconfpb.Bid) (*common.Address, error) { @@ -65,8 +70,8 @@ func (t *testEncryptor) DecryptBidData(_ common.Address, _ *preconfpb.EncryptedB return t.bid, nil } -func (t *testEncryptor) VerifyEncryptedPreConfirmation(*ecdh.PublicKey, []byte, *preconfpb.EncryptedPreConfirmation) (*common.Address, error) { - return &t.preConfirmationSigner, nil +func (t *testEncryptor) VerifyEncryptedPreConfirmation(*ecdh.PublicKey, []byte, *preconfpb.EncryptedPreConfirmation) ([]byte, *common.Address, error) { + return t.sharedSecretKey, &t.preConfirmationSigner, nil } type testProcessor struct { @@ -87,8 +92,23 @@ func (t *testCommitmentDA) StoreEncryptedCommitment( _ context.Context, _ []byte, _ []byte, -) error { - return nil +) (common.Hash, error) { + return common.Hash{}, nil +} + +func (t *testCommitmentDA) OpenCommitment( + _ context.Context, + _ []byte, + _ string, + _ int64, + _ string, + _ int64, + _ int64, + _ []byte, + _ []byte, + _ []byte, +) (common.Hash, error) { + return common.Hash{}, nil } func (t *testCommitmentDA) Close() error { @@ -97,9 +117,9 @@ func (t *testCommitmentDA) Close() error { type testBlockTrackerContract struct { blockNumberToWinner map[uint64]common.Address - lastBlockNumber uint64 - lastBlockWinner common.Address - blocksPerWindow uint64 + lastBlockNumber uint64 + lastBlockWinner common.Address + blocksPerWindow uint64 } // RecordBlock records a new block and its winner. @@ -138,6 +158,10 @@ func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (ui return btc.blocksPerWindow, nil } +func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent) (ethereum.Subscription, error) { + return nil, nil +} + func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { t.Helper() @@ -189,11 +213,11 @@ func TestPreconfBidSubmission(t *testing.T) { Ciphertext: []byte("test"), } - // preConfirmation := &preconfencryptor.PreConfirmation{ - // Bid: *bid, - // Digest: []byte("test"), - // Signature: []byte("test"), - // } + preConfirmation := &preconfpb.PreConfirmation{ + Bid: bid, + Digest: []byte("test"), + Signature: []byte("test"), + } encryptedPreConfirmation := &preconfpb.EncryptedPreConfirmation{ Commitment: []byte("test"), @@ -209,15 +233,18 @@ func TestPreconfBidSubmission(t *testing.T) { status: providerapiv1.BidResponse_STATUS_ACCEPTED, } signer := &testEncryptor{ - bidHash: bid.Digest, - encryptedBid: encryptedBid, - bid: bid, - preConfirmation: encryptedPreConfirmation, - bidSigner: common.HexToAddress("0x1"), - preConfirmationSigner: common.HexToAddress("0x2"), + bidHash: bid.Digest, + encryptedBid: encryptedBid, + bid: bid, + preConfirmation: preConfirmation, + encryptedPreConfirmation: encryptedPreConfirmation, + bidSigner: common.HexToAddress("0x1"), + preConfirmationSigner: common.HexToAddress("0x2"), } + mockL1Client := mockevmclient.New() p := preconfirmation.New( + client.EthAddress, topo, svc, signer, @@ -225,6 +252,7 @@ func TestPreconfBidSubmission(t *testing.T) { proc, &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, + mockL1Client, newTestLogger(t, os.Stdout), ) diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 238601a0..a0d2cbc1 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -11,6 +11,8 @@ import ( "strings" "testing" + "github.com/ethereum/go-ethereum" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" "github.com/bufbuild/protovalidate-go" "github.com/ethereum/go-ethereum/common" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" @@ -93,7 +95,7 @@ func (t *testRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, e return t.minAllowance, nil } -func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int) bool { +func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int, numberOfRounds *big.Int) bool { return t.allowance.Cmp(t.minAllowance) > 0 } @@ -140,6 +142,9 @@ func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (ui return btc.blocksPerWindow, nil } +func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent) (ethereum.Subscription, error) { + return nil, nil +} func startServer(t *testing.T) bidderapiv1.BidderClient { lis := bufconn.Listen(bufferSize) diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index 5d21e711..989de1a9 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -24,12 +24,11 @@ var ( ErrInvalidCommitment = errors.New("commitment is incorrect") ) - type Encryptor interface { ConstructEncryptedBid(string, string, int64, int64, int64) (*preconfpb.Bid, *preconfpb.EncryptedBid, error) - ConstructEncryptedPreConfirmation(*preconfpb.Bid) (*preconfpb.EncryptedPreConfirmation, error) + ConstructEncryptedPreConfirmation(*preconfpb.Bid) (*preconfpb.PreConfirmation, *preconfpb.EncryptedPreConfirmation, error) VerifyBid(*preconfpb.Bid) (*common.Address, error) - VerifyEncryptedPreConfirmation(*ecdh.PublicKey, []byte, *preconfpb.EncryptedPreConfirmation) (*common.Address, error) + VerifyEncryptedPreConfirmation(providerNikePK *ecdh.PublicKey, bidHash []byte, c *preconfpb.EncryptedPreConfirmation) ([]byte, *common.Address, error) DecryptBidData(common.Address, *preconfpb.EncryptedBid) (*preconfpb.Bid, error) } @@ -105,21 +104,21 @@ func (e *encryptor) ConstructEncryptedBid( return bid, &preconfpb.EncryptedBid{Ciphertext: encryptedBidData}, nil } -func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*preconfpb.EncryptedPreConfirmation, error) { +func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*preconfpb.PreConfirmation, *preconfpb.EncryptedPreConfirmation, error) { _, err := e.VerifyBid(bid) if err != nil { - return nil, err + return nil, nil, err } bidDataPublicKey, err := ecdh.Curve.NewPublicKey(ecdh.P256(), bid.NikePublicKey) if err != nil { - return nil, err + return nil, nil, err } providerKK := e.keyKeeper.(*keykeeper.ProviderKeyKeeper) sharedSecredProviderSk, err := providerKK.GetNIKEPrivateKey().ECDH(bidDataPublicKey) if err != nil { - return nil, err + return nil, nil, err } preConfirmation := &preconfpb.PreConfirmation{ @@ -130,19 +129,19 @@ func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*prec // todo: update to take preconf hash into hash calculation preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) if err != nil { - return nil, err + return nil, nil, err } sig, err := e.keyKeeper.SignHash(preConfirmationHash) if err != nil { - return nil, err + return nil, nil, err } if sig[64] == 0 || sig[64] == 1 { sig[64] += 27 // Transform V from 0/1 to 27/28 } - return &preconfpb.EncryptedPreConfirmation{ + return preConfirmation, &preconfpb.EncryptedPreConfirmation{ Commitment: preConfirmationHash, Signature: sig, }, nil @@ -183,9 +182,9 @@ func (e *encryptor) DecryptBidData(bidderAddress common.Address, bid *preconfpb. // VerifyPreConfirmation verifies the preconfirmation message, and returns the address of the provider // that signed the preconfirmation. -func (e *encryptor) VerifyEncryptedPreConfirmation(providerNikePK *ecdh.PublicKey, bidHash []byte, c *preconfpb.EncryptedPreConfirmation) (*common.Address, error) { +func (e *encryptor) VerifyEncryptedPreConfirmation(providerNikePK *ecdh.PublicKey, bidHash []byte, c *preconfpb.EncryptedPreConfirmation) ([]byte, *common.Address, error) { if c.Signature == nil { - return nil, ErrMissingHashSignature + return nil, nil, ErrMissingHashSignature } bidHashStr := hex.EncodeToString(bidHash) @@ -194,20 +193,27 @@ func (e *encryptor) VerifyEncryptedPreConfirmation(providerNikePK *ecdh.PublicKe bidderKK := e.keyKeeper.(*keykeeper.BidderKeyKeeper) sharedSecredBidderSk, err := bidderKK.BidHashesToNIKE[bidHashStr].ECDH(providerNikePK) if err != nil { - return nil, err + return nil, nil, err } preConfirmation := &preconfpb.PreConfirmation{ Bid: bid, + Digest: bidHash, + Signature: c.Signature, SharedSecret: sharedSecredBidderSk, } preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) if err != nil { - return nil, err + return nil, nil, err + } + + address, err := eipVerify(preConfirmationHash, c.Commitment, c.Signature) + if err != nil { + return nil, nil, err } - return eipVerify(preConfirmationHash, c.Commitment, c.Signature) + return sharedSecredBidderSk, address, nil } func eipVerify( diff --git a/pkg/signer/preconfencryptor/encryptor_test.go b/pkg/signer/preconfencryptor/encryptor_test.go index c86d6875..638b6c3a 100644 --- a/pkg/signer/preconfencryptor/encryptor_test.go +++ b/pkg/signer/preconfencryptor/encryptor_test.go @@ -100,12 +100,12 @@ func TestBids(t *testing.T) { if err != nil { t.Fatal(err) } - encryptedPreConfirmation, err := providerEncryptor.ConstructEncryptedPreConfirmation(decryptedBid) + _, encryptedPreConfirmation, err := providerEncryptor.ConstructEncryptedPreConfirmation(decryptedBid) if err != nil { t.Fail() } - address, err := bidderEncryptor.VerifyEncryptedPreConfirmation(providerKeyKeeper.GetNIKEPublicKey(), bid.Digest, encryptedPreConfirmation) + _, address, err := bidderEncryptor.VerifyEncryptedPreConfirmation(providerKeyKeeper.GetNIKEPublicKey(), bid.Digest, encryptedPreConfirmation) if err != nil { t.Fail() } From 4046df87e8f922f515d48fa8e559fb54eed1074b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 3 Apr 2024 22:42:16 +0200 Subject: [PATCH 10/85] added event listening to preconf --- pkg/node/node.go | 3 +++ pkg/preconfirmation/preconfirmation.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 609e327d..9443ae73 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -242,6 +242,8 @@ func NewNode(opts *Options) (*Node, error) { evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) + preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleProviderNewL1BlockEvent) + // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) @@ -268,6 +270,7 @@ func NewNode(opts *Options) (*Node, error) { evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) + preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleBidderNewL1BlockEvent) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) bidderAPI := bidderapi.NewService( diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index e17f89dc..206e9884 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -324,7 +324,7 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, } } -func (p *Preconfirmation) handleProviderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { +func (p *Preconfirmation) HandleProviderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) @@ -367,7 +367,7 @@ func (p *Preconfirmation) handleProviderNewL1BlockEvent(ctx context.Context, eve } -func (p *Preconfirmation) handleBidderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { +func (p *Preconfirmation) HandleBidderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) From d71caba025ecc851cc95d5a4f4b84cf3bfbb5932 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 4 Apr 2024 14:32:47 +0200 Subject: [PATCH 11/85] added missed rpc for l1 --- cmd/main.go | 7 +++++++ integrationtest/config/bidder.yaml | 1 + integrationtest/config/bootnode.yaml | 1 + integrationtest/config/provider.yaml | 1 + pkg/node/node.go | 4 ++++ 5 files changed, 14 insertions(+) diff --git a/cmd/main.go b/cmd/main.go index 34292841..63ef39aa 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -199,6 +199,12 @@ var ( Value: "http://localhost:8545", }) + optionL1RPCUrl = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "l1-rpc-url", + Usage: "rpc url of the L1 node", + EnvVars: []string{"MEV_COMMIT_L1_RPC_URL"}, + }) + optionNATAddr = altsrc.NewStringFlag(&cli.StringFlag{ Name: "nat-addr", Usage: "external address of the node", @@ -247,6 +253,7 @@ func main() { optionProviderRegistryAddr, optionPreconfStoreAddr, optionSettlementRPCEndpoint, + optionL1RPCUrl, optionNATAddr, optionNATPort, optionServerTLSCert, diff --git a/integrationtest/config/bidder.yaml b/integrationtest/config/bidder.yaml index 70994abf..313ec2b6 100644 --- a/integrationtest/config/bidder.yaml +++ b/integrationtest/config/bidder.yaml @@ -13,3 +13,4 @@ provider-registry-contract: settlement-rpc-endpoint: bootnodes: - /ip4/172.29.18.2/tcp/13522/p2p/16Uiu2HAmLYUvthfDCewNMdfPhrVefBbsfaPL22fWWfC2zuoh5SpV +l1-rpc-url: diff --git a/integrationtest/config/bootnode.yaml b/integrationtest/config/bootnode.yaml index a04da47b..1a8115db 100644 --- a/integrationtest/config/bootnode.yaml +++ b/integrationtest/config/bootnode.yaml @@ -11,3 +11,4 @@ server-tls-private-key: /server-key.pem bidder-registry-contract: provider-registry-contract: settlement-rpc-endpoint: +l1-rpc-url: diff --git a/integrationtest/config/provider.yaml b/integrationtest/config/provider.yaml index 56fcb6ba..5ebd122e 100644 --- a/integrationtest/config/provider.yaml +++ b/integrationtest/config/provider.yaml @@ -14,3 +14,4 @@ provider-registry-contract: settlement-rpc-endpoint: bootnodes: - /ip4/172.29.18.2/tcp/13522/p2p/16Uiu2HAmLYUvthfDCewNMdfPhrVefBbsfaPL22fWWfC2zuoh5SpV +l1-rpc-url: diff --git a/pkg/node/node.go b/pkg/node/node.go index 9443ae73..b4de907a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -96,6 +96,10 @@ func NewNode(opts *Options) (*Node, error) { nd.closers = append(nd.closers, evmClient) l1RPC, err := ethclient.Dial(opts.L1RPCUrl) + if err != nil { + return nil, err + } + evmL1Client, err := evmclient.New( opts.KeySigner, evmclient.WrapEthClient(l1RPC), From 4368f26283e8d67c86936cde6707e720cccd47d4 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 4 Apr 2024 15:48:05 +0200 Subject: [PATCH 12/85] fix L1RPCUrl in node.Options --- cmd/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index 63ef39aa..bd94aab1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -204,7 +204,7 @@ var ( Usage: "rpc url of the L1 node", EnvVars: []string{"MEV_COMMIT_L1_RPC_URL"}, }) - + optionNATAddr = altsrc.NewStringFlag(&cli.StringFlag{ Name: "nat-addr", Usage: "external address of the node", @@ -338,6 +338,7 @@ func launchNodeWithConfig(c *cli.Context) error { ProviderRegistryContract: c.String(optionProviderRegistryAddr.Name), BidderRegistryContract: c.String(optionBidderRegistryAddr.Name), RPCEndpoint: c.String(optionSettlementRPCEndpoint.Name), + L1RPCUrl: c.String(optionL1RPCUrl.Name), NatAddr: natAddr, TLSCertificateFile: crtFile, TLSPrivateKeyFile: keyFile, From e0be814ecda798561cf74140fd43a113db833f50 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 4 Apr 2024 18:44:28 +0200 Subject: [PATCH 13/85] fixed wrong initialization --- pkg/node/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index b4de907a..a88d2ad7 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -131,12 +131,12 @@ func NewNode(opts *Options) (*Node, error) { var keyKeeper keykeeper.KeyKeeper switch opts.PeerType { case p2p.PeerTypeProvider.String(): - keyKeeper, err = keykeeper.NewBidderKeyKeeper(opts.KeySigner) + keyKeeper, err = keykeeper.NewProviderKeyKeeper(opts.KeySigner) if err != nil { return nil, errors.Join(err, nd.Close()) } case p2p.PeerTypeBidder.String(): - keyKeeper, err = keykeeper.NewProviderKeyKeeper(opts.KeySigner) + keyKeeper, err = keykeeper.NewBidderKeyKeeper(opts.KeySigner) if err != nil { return nil, errors.Join(err, nd.Close()) } From 3132a88c3b1815108a50da4caa0eb405396dda8b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 11:02:53 +0200 Subject: [PATCH 14/85] fixed preconf encrypted --- pkg/node/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index a88d2ad7..0a4147fe 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -194,7 +194,7 @@ func NewNode(opts *Options) (*Node, error) { } grpcServer := grpc.NewServer(grpc.Creds(tlsCredentials)) - preconfEncryptor := preconfencryptor.NewEncryptor(opts.KeySigner) + preconfEncryptor := preconfencryptor.NewEncryptor(keyKeeper) validator, err := protovalidate.New() if err != nil { return nil, errors.Join(err, nd.Close()) From ec36610663e9a0e819f74ba0001a4651a3ce0805 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 13:42:48 +0200 Subject: [PATCH 15/85] fixes for keyexchange --- pkg/keyexchange/keyexchange.go | 7 ++++--- pkg/node/node.go | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go index 15b1ae80..c031ac1a 100644 --- a/pkg/keyexchange/keyexchange.go +++ b/pkg/keyexchange/keyexchange.go @@ -11,12 +11,13 @@ import ( "sync" "time" - keyexchangepb "github.com/primevprotocol/mev-commit/gen/go/keyexchange" "github.com/ethereum/go-ethereum/crypto/ecies" + keyexchangepb "github.com/primevprotocol/mev-commit/gen/go/keyexchange" "github.com/primevprotocol/mev-commit/pkg/keykeeper" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/signer" "github.com/primevprotocol/mev-commit/pkg/topology" + "google.golang.org/protobuf/proto" ) func New( @@ -137,7 +138,7 @@ func (ke *KeyExchange) createSignedMessage(encryptedKeys [][]byte, timestampMess TimestampMessage: timestampMessage, } - messageBytes, err := json.Marshal(message) + messageBytes, err := proto.Marshal(&message) if err != nil { return nil, fmt.Errorf("failed to marshal message: %w", err) } @@ -245,7 +246,7 @@ func (ke *KeyExchange) decryptMessage(ekmWithSignature *keyexchangepb.EKMWithSig message keyexchangepb.EncryptedKeysMessage ) - err = json.Unmarshal(ekmWithSignature.Message, &message) + err = proto.Unmarshal(ekmWithSignature.Message, &message) if err != nil { return nil, nil, fmt.Errorf("failed to unmarshal message: %w", err) } diff --git a/pkg/node/node.go b/pkg/node/node.go index 0a4147fe..008b6a39 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -294,7 +294,10 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) - keyexchange.SendTimestampMessage() + err := keyexchange.SendTimestampMessage() + if err != nil { + return nil, errors.Join(err, nd.Close()) + } srv.RegisterMetricsCollectors(bidderAPI.Metrics()...) } From 620124e252d239b37880056737ce6f8e0d43fb97 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 13:45:08 +0200 Subject: [PATCH 16/85] deleted redundant import --- pkg/keyexchange/keyexchange.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go index c031ac1a..bac2585f 100644 --- a/pkg/keyexchange/keyexchange.go +++ b/pkg/keyexchange/keyexchange.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "crypto/rand" - "encoding/json" "errors" "fmt" "log/slog" From 49546a0f33f80454e5a72e5b30d2eca3f81bf5a5 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 14:35:18 +0200 Subject: [PATCH 17/85] fixed concurrent access --- pkg/keyexchange/keyexchange.go | 14 +++++++------- pkg/keyexchange/keyexchange_test.go | 4 ++-- pkg/keykeeper/keykeeper.go | 19 +++++++++++++++++-- pkg/keykeeper/models.go | 6 ++++-- pkg/signer/preconfencryptor/encryptor_test.go | 5 ++--- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go index bac2585f..0455aa5d 100644 --- a/pkg/keyexchange/keyexchange.go +++ b/pkg/keyexchange/keyexchange.go @@ -27,11 +27,11 @@ func New( signer signer.Signer, ) *KeyExchange { return &KeyExchange{ - topo: topo, - streamer: streamer, - keyKeeper: keyKeeper, - logger: logger, - signer: signer, + topo: topo, + streamer: streamer, + keyKeeper: keyKeeper, + logger: logger, + signer: signer, } } @@ -195,7 +195,7 @@ func (ke *KeyExchange) handleTimestampMessage(ctx context.Context, peer p2p.Peer return fmt.Errorf("validate and process timestamp failed: %w", err) } - ke.keyKeeper.(*keykeeper.ProviderKeyKeeper).BiddersAESKeys[peer.EthAddress] = aesKey + ke.keyKeeper.(*keykeeper.ProviderKeyKeeper).SetAESKey(peer.EthAddress, aesKey) return nil } @@ -245,7 +245,7 @@ func (ke *KeyExchange) decryptMessage(ekmWithSignature *keyexchangepb.EKMWithSig message keyexchangepb.EncryptedKeysMessage ) - err = proto.Unmarshal(ekmWithSignature.Message, &message) + err = proto.Unmarshal(ekmWithSignature.Message, &message) if err != nil { return nil, nil, fmt.Errorf("failed to unmarshal message: %w", err) } diff --git a/pkg/keyexchange/keyexchange_test.go b/pkg/keyexchange/keyexchange_test.go index 3d3d7085..82cba0d5 100644 --- a/pkg/keyexchange/keyexchange_test.go +++ b/pkg/keyexchange/keyexchange_test.go @@ -94,8 +94,8 @@ func TestKeyExchange_SendAndHandleTimestampMessage(t *testing.T) { if time.Since(start) > 5*time.Second { t.Fatal("timed out") } - if _, exists := providerKK.BiddersAESKeys[bidderPeer.EthAddress]; exists { - aesKey := providerKK.BiddersAESKeys[bidderPeer.EthAddress] + aesKey, exists := providerKK.GetAESKey(bidderPeer.EthAddress) + if exists { if !bytes.Equal(bidderKK.AESKey, aesKey) { t.Fatal("AES keys are not equal") } diff --git a/pkg/keykeeper/keykeeper.go b/pkg/keykeeper/keykeeper.go index a0723594..396bbdf3 100644 --- a/pkg/keykeeper/keykeeper.go +++ b/pkg/keykeeper/keykeeper.go @@ -6,6 +6,7 @@ import ( "crypto/elliptic" "crypto/rand" "encoding/hex" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" @@ -72,8 +73,9 @@ func NewProviderKeyKeeper(keysigner keysigner.KeySigner) (*ProviderKeyKeeper, er } return &ProviderKeyKeeper{ - BaseKeyKeeper: NewBaseKeyKeeper(keysigner), - BiddersAESKeys: biddersAESKeys, + BaseKeyKeeper: NewBaseKeyKeeper(keysigner), + BiddersAESKeys: biddersAESKeys, + bidderAESKeysMutex: &sync.RWMutex{}, keys: ProviderKeys{ EncryptionPrivateKey: encryptionPrivateKey, EncryptionPublicKey: &encryptionPrivateKey.PublicKey, @@ -98,3 +100,16 @@ func (pkk *ProviderKeyKeeper) DecryptWithECIES(message []byte) ([]byte, error) { func (pkk *ProviderKeyKeeper) GetNIKEPrivateKey() *ecdh.PrivateKey { return pkk.keys.NIKEPrivateKey } + +func (pkk *ProviderKeyKeeper) SetAESKey(bidder common.Address, key []byte) { + pkk.bidderAESKeysMutex.Lock() + defer pkk.bidderAESKeysMutex.Unlock() + pkk.BiddersAESKeys[bidder] = key +} + +func (pkk *ProviderKeyKeeper) GetAESKey(bidder common.Address) ([]byte, bool) { + pkk.bidderAESKeysMutex.RLock() + defer pkk.bidderAESKeysMutex.RUnlock() + key, exists := pkk.BiddersAESKeys[bidder] + return key, exists +} diff --git a/pkg/keykeeper/models.go b/pkg/keykeeper/models.go index c337bc67..286f5dc0 100644 --- a/pkg/keykeeper/models.go +++ b/pkg/keykeeper/models.go @@ -3,6 +3,7 @@ package keykeeper import ( "crypto/ecdh" "crypto/ecdsa" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" @@ -29,8 +30,9 @@ type ProviderKeys struct { type ProviderKeyKeeper struct { *BaseKeyKeeper - keys ProviderKeys - BiddersAESKeys map[common.Address][]byte + keys ProviderKeys + bidderAESKeysMutex *sync.RWMutex + BiddersAESKeys map[common.Address][]byte } type BidderKeyKeeper struct { diff --git a/pkg/signer/preconfencryptor/encryptor_test.go b/pkg/signer/preconfencryptor/encryptor_test.go index 638b6c3a..b6a9ea66 100644 --- a/pkg/signer/preconfencryptor/encryptor_test.go +++ b/pkg/signer/preconfencryptor/encryptor_test.go @@ -41,7 +41,7 @@ func TestBids(t *testing.T) { if err != nil { t.Fatal(err) } - providerKeyKeeper.BiddersAESKeys[address] = keyKeeper.AESKey + providerKeyKeeper.SetAESKey(address, keyKeeper.AESKey) encryptorProvider := preconfencryptor.NewEncryptor(providerKeyKeeper) bid, err := encryptorProvider.DecryptBidData(address, encryptedBid) if err != nil { @@ -85,8 +85,7 @@ func TestBids(t *testing.T) { t.Fatal(err) } - providerKeyKeeper.BiddersAESKeys[bidderAddress] = bidderKeyKeeper.AESKey - + providerKeyKeeper.SetAESKey(bidderAddress, bidderKeyKeeper.AESKey) providerEncryptor := preconfencryptor.NewEncryptor(providerKeyKeeper) start := time.Now().UnixMilli() end := start + 100000 From 8be8126d160f736783ae864fb194f41e3ae99967 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 14:35:33 +0200 Subject: [PATCH 18/85] fixed concurrent access --- pkg/signer/preconfencryptor/encryptor.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index 989de1a9..0f16ec01 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -166,7 +166,10 @@ func (e *encryptor) VerifyBid(bid *preconfpb.Bid) (*common.Address, error) { func (e *encryptor) DecryptBidData(bidderAddress common.Address, bid *preconfpb.EncryptedBid) (*preconfpb.Bid, error) { pkk := e.keyKeeper.(*keykeeper.ProviderKeyKeeper) - aesKey := pkk.BiddersAESKeys[bidderAddress] + aesKey, exists := pkk.GetAESKey(bidderAddress) + if !exists { + return nil, errors.New("no AES key found for bidder") + } decryptedBytes, err := keykeeper.DecryptWithAESGCM(aesKey, bid.Ciphertext) if err != nil { return nil, err From f535ee42e9780ced7545e0775d94a977de4cff2b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 5 Apr 2024 23:57:31 +0200 Subject: [PATCH 19/85] updated handshake --- .../libp2p/internal/handshake/handshake.go | 23 ++++++++++++++++--- .../internal/handshake/handshake_test.go | 6 +++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index c990ae6a..8ebaa601 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -11,8 +11,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/protocol" - "github.com/primevprotocol/mev-commit/pkg/keykeeper" handshakepb "github.com/primevprotocol/mev-commit/gen/go/handshake/v1" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/signer" ) @@ -255,8 +255,25 @@ func (h *Service) Handshake( return nil, err } - return &p2p.Peer{ + p := &p2p.Peer{ EthAddress: ethAddress, Type: p2p.FromString(ack.PeerType), - }, nil + } + + if ack.PeerType == p2p.PeerTypeProvider.String() { + ppk, err := keykeeper.DeserializePublicKey(ack.Keys.PKEPublicKey) + if err != nil { + return &p2p.Peer{}, err + } + npk, err := ecdh.P256().NewPublicKey(ack.Keys.NIKEPublicKey) + if err != nil { + return &p2p.Peer{}, err + } + p.Keys = &p2p.Keys{ + PKEPublicKey: ppk, + NIKEPublicKey: npk, + } + } + + return p, nil } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 3047f5b6..36ce06f7 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -132,6 +132,12 @@ func TestHandshake(t *testing.T) { if p.Type != p2p.PeerTypeProvider { t.Fatalf("expected peer type %s, got %s", p2p.PeerTypeProvider, p.Type) } + if !p.Keys.NIKEPublicKey.Equal(kk1.GetNIKEPublicKey()) { + t.Fatalf("expected nike pk %s, got %s", p.Keys.NIKEPublicKey.Bytes(), kk1.GetNIKEPublicKey().Bytes()) + } + if !p.Keys.PKEPublicKey.ExportECDSA().Equal(kk1.GetECIESPublicKey().ExportECDSA()) { + t.Fatalf("expected pke pk is not equal to present") + } <-done }) } From 58fce1137eb729061077ad0c8c034549dc12dc7f Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 8 Apr 2024 20:42:19 +0200 Subject: [PATCH 20/85] changed logic for the peer connection and commitment opening --- pkg/keyexchange/models.go | 10 +- pkg/node/node.go | 17 ++- pkg/preconfirmation/preconfirmation.go | 131 ++++++-------------- pkg/preconfirmation/preconfirmation_test.go | 3 - pkg/topology/topology.go | 8 ++ 5 files changed, 57 insertions(+), 112 deletions(-) diff --git a/pkg/keyexchange/models.go b/pkg/keyexchange/models.go index ff048a07..ff41c9f0 100644 --- a/pkg/keyexchange/models.go +++ b/pkg/keyexchange/models.go @@ -27,11 +27,11 @@ var ( // KeyExchange manages the key exchange process. type KeyExchange struct { - keyKeeper keykeeper.KeyKeeper - topo Topology - streamer p2p.Streamer - signer signer.Signer - logger *slog.Logger + keyKeeper keykeeper.KeyKeeper + topo Topology + streamer p2p.Streamer + signer signer.Signer + logger *slog.Logger } // Topology interface to get peers. diff --git a/pkg/node/node.go b/pkg/node/node.go index 008b6a39..3c2bfaba 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -243,10 +243,9 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, - evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) - preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleProviderNewL1BlockEvent) + preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) @@ -271,10 +270,9 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, - evmL1Client, opts.Logger.With("component", "preconfirmation_protocol"), ) - preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleBidderNewL1BlockEvent) + preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) bidderAPI := bidderapi.NewService( @@ -294,11 +292,12 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) - err := keyexchange.SendTimestampMessage() - if err != nil { - return nil, errors.Join(err, nd.Close()) - } - + topo.SubscribePeer(func(p p2p.Peer) { + if p.Type == p2p.PeerTypeProvider { + keyexchange.SendTimestampMessage() + } + }) + srv.RegisterMetricsCollectors(bidderAPI.Metrics()...) } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 206e9884..94a9b18c 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -13,7 +13,6 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" - "github.com/primevprotocol/mev-commit/pkg/evmclient" "github.com/primevprotocol/mev-commit/pkg/p2p" encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" @@ -33,9 +32,8 @@ type EncryptedPreConfirmationWithDecrypted struct { type Preconfirmation struct { owner common.Address - // todo: store the bids in a database - commitmentByTxHashes map[string]*EncryptedPreConfirmationWithDecrypted - commitmentsByProvidersByBlockNumbers map[int64]map[string]*EncryptedPreConfirmationWithDecrypted + // todo: store the commitments in a database + commitmentByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted encryptor encryptor.Encryptor topo Topology streamer p2p.Streamer @@ -43,7 +41,6 @@ type Preconfirmation struct { processer BidProcessor commitmentDA preconfcontract.Interface blockTracker blocktrackercontract.Interface - evmL1Client evmclient.Interface logger *slog.Logger metrics *metrics } @@ -69,14 +66,12 @@ func New( processor BidProcessor, commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, - evmL1Client evmclient.Interface, logger *slog.Logger, ) *Preconfirmation { - commitmentByTxHashes := make(map[string]*EncryptedPreConfirmationWithDecrypted) - commitmentsByProvidersByBlockNumbers := make(map[int64]map[string]*EncryptedPreConfirmationWithDecrypted) + commitmentsByBlockNumber := make(map[int64][]*EncryptedPreConfirmationWithDecrypted) return &Preconfirmation{ - commitmentByTxHashes: commitmentByTxHashes, - commitmentsByProvidersByBlockNumbers: commitmentsByProvidersByBlockNumbers, + owner: owner, + commitmentByBlockNumber: commitmentsByBlockNumber, topo: topo, streamer: streamer, encryptor: encryptor, @@ -84,7 +79,6 @@ func New( processer: processor, commitmentDA: commitmentDA, blockTracker: blockTracker, - evmL1Client: evmL1Client, logger: logger, metrics: newMetrics(), } @@ -186,13 +180,17 @@ func (p *Preconfirmation) SendBid( preConfirmation.ProviderAddress = make([]byte, len(providerAddress)) copy(preConfirmation.ProviderAddress, providerAddress[:]) - if p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber] == nil { - p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber] = make(map[string]*EncryptedPreConfirmationWithDecrypted) - } - p.commitmentsByProvidersByBlockNumbers[bid.BlockNumber][providerAddress.String()] = &EncryptedPreConfirmationWithDecrypted{ + encryptedAndDecryptedPreconfirmation := &EncryptedPreConfirmationWithDecrypted{ EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, } + + if _, exists := p.commitmentByBlockNumber[blockNumber]; exists { + p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) + } else { + p.commitmentByBlockNumber[blockNumber] = []*EncryptedPreConfirmationWithDecrypted{encryptedAndDecryptedPreconfirmation} + } + logger.Info("received preconfirmation", "preConfirmation", preConfirmation) p.metrics.ReceivedPreconfsCount.Inc() @@ -291,10 +289,18 @@ func (p *Preconfirmation) handleBid( } encryptedPreConfirmation.CommitmentIndex = commitmentIndex.Bytes() - p.commitmentByTxHashes[bid.TxHash] = &EncryptedPreConfirmationWithDecrypted{ + encryptedAndDecryptedPreconfirmation := &EncryptedPreConfirmationWithDecrypted{ EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, } + blockNumber := preConfirmation.Bid.BlockNumber + + if _, exists := p.commitmentByBlockNumber[blockNumber]; exists { + p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) + } else { + p.commitmentByBlockNumber[blockNumber] = []*EncryptedPreConfirmationWithDecrypted{encryptedAndDecryptedPreconfirmation} + } + return stream.WriteMsg(ctx, encryptedPreConfirmation) } } @@ -324,92 +330,27 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, } } -func (p *Preconfirmation) HandleProviderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { +func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) - - block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) - if err != nil { - p.logger.Error("Failed to fetch block", "blockNumber", event.BlockNumber, "error", err) - return - } - - validatorAddress := block.Coinbase() - peerAddress := p.owner - - if validatorAddress != peerAddress { - return - } - - for _, tx := range block.Transactions() { - commitment := p.commitmentByTxHashes[tx.Hash().String()] - if commitment == nil { - continue - } + for _, commitment := range p.commitmentByBlockNumber[event.BlockNumber.Int64()] { _, err := p.commitmentDA.OpenCommitment( - context.Background(), + ctx, commitment.EncryptedPreConfirmation.CommitmentIndex, - commitment.Bid.BidAmount, - commitment.Bid.BlockNumber, - commitment.Bid.TxHash, - commitment.Bid.DecayStartTimestamp, - commitment.Bid.DecayEndTimestamp, - commitment.Bid.Signature, + commitment.PreConfirmation.Bid.BidAmount, + commitment.PreConfirmation.Bid.BlockNumber, + commitment.PreConfirmation.Bid.TxHash, + commitment.PreConfirmation.Bid.DecayStartTimestamp, + commitment.PreConfirmation.Bid.DecayEndTimestamp, + commitment.PreConfirmation.Bid.Signature, commitment.PreConfirmation.Signature, commitment.PreConfirmation.SharedSecret, ) if err != nil { p.logger.Error("Failed to open commitment", "error", err) - return - } - p.logger.Info("Opened commitment", "txHash", tx.Hash().String()) - delete(p.commitmentByTxHashes, tx.Hash().String()) - } -} - - -func (p *Preconfirmation) HandleBidderNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { - p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) - - block, err := p.evmL1Client.BlockByNumber(context.Background(), event.BlockNumber) - if err != nil { - p.logger.Error("Failed to fetch block", "blockNumber", event.BlockNumber, "error", err) - return - } - - validatorAddress := block.Coinbase() - // todo: with that approach only one bid could be in the block, fix this - commitment := p.commitmentsByProvidersByBlockNumbers[event.BlockNumber.Int64()][validatorAddress.String()] - - if commitment == nil { - return - } - isTxPresent := false - for _, tx := range block.Transactions() { - if tx.Hash().String() == commitment.Bid.TxHash { - isTxPresent = true - break + continue + } else { + p.logger.Info("Opened commitment", "txHash", commitment.PreConfirmation.Bid.TxHash) } } - - if isTxPresent { - return - } - - _, err = p.commitmentDA.OpenCommitment( - ctx, - commitment.EncryptedPreConfirmation.CommitmentIndex, - commitment.Bid.BidAmount, - commitment.Bid.BlockNumber, - commitment.Bid.TxHash, - commitment.Bid.DecayStartTimestamp, - commitment.Bid.DecayEndTimestamp, - commitment.Bid.Signature, - commitment.PreConfirmation.Signature, - commitment.PreConfirmation.SharedSecret, - ) - if err != nil { - p.logger.Error("Failed to open commitment", "error", err) - return - } - p.logger.Info("Opened commitment", "txHash", commitment.Bid.TxHash) -} + delete(p.commitmentByBlockNumber, event.BlockNumber.Int64()) +} \ No newline at end of file diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 28b91508..e14ac9f1 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -18,7 +18,6 @@ import ( preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" - mockevmclient "github.com/primevprotocol/mev-commit/pkg/evmclient/mock" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" @@ -242,7 +241,6 @@ func TestPreconfBidSubmission(t *testing.T) { preConfirmationSigner: common.HexToAddress("0x2"), } - mockL1Client := mockevmclient.New() p := preconfirmation.New( client.EthAddress, topo, @@ -252,7 +250,6 @@ func TestPreconfBidSubmission(t *testing.T) { proc, &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, - mockL1Client, newTestLogger(t, os.Stdout), ) diff --git a/pkg/topology/topology.go b/pkg/topology/topology.go index 4c329c2d..4a3f6ebf 100644 --- a/pkg/topology/topology.go +++ b/pkg/topology/topology.go @@ -25,6 +25,11 @@ type Topology struct { addressbook p2p.Addressbook announcer Announcer metrics *metrics + subs []func(p2p.Peer) +} + +func (t *Topology) SubscribePeer(handler func(p2p.Peer)) { + t.subs = append(t.subs, handler) } func New(a p2p.Addressbook, logger *slog.Logger) *Topology { @@ -127,6 +132,9 @@ func (t *Topology) Disconnected(p p2p.Peer) { func (t *Topology) AddPeers(peers ...p2p.Peer) { for _, p := range peers { t.add(p) + for _, sub := range t.subs { + sub(p) + } } } From ab659d096a9fb8211f4d52780b7ee5f09dad2128 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 8 Apr 2024 20:50:29 +0200 Subject: [PATCH 21/85] fixing lint issues --- pkg/node/node.go | 9 +++-- pkg/preconfirmation/preconfirmation.go | 56 +++++++++++--------------- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 3c2bfaba..3fe4839a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -99,7 +99,7 @@ func NewNode(opts *Options) (*Node, error) { if err != nil { return nil, err } - + evmL1Client, err := evmclient.New( opts.KeySigner, evmclient.WrapEthClient(l1RPC), @@ -294,10 +294,13 @@ func NewNode(opts *Options) (*Node, error) { ) topo.SubscribePeer(func(p p2p.Peer) { if p.Type == p2p.PeerTypeProvider { - keyexchange.SendTimestampMessage() + err = keyexchange.SendTimestampMessage() + if err != nil { + opts.Logger.Error("failed to send timestamp message", "error", err) + } } }) - + srv.RegisterMetricsCollectors(bidderAPI.Metrics()...) } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 94a9b18c..632bcda4 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -33,16 +33,16 @@ type EncryptedPreConfirmationWithDecrypted struct { type Preconfirmation struct { owner common.Address // todo: store the commitments in a database - commitmentByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted - encryptor encryptor.Encryptor - topo Topology - streamer p2p.Streamer - us BidderStore - processer BidProcessor - commitmentDA preconfcontract.Interface - blockTracker blocktrackercontract.Interface - logger *slog.Logger - metrics *metrics + commitmentByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted + encryptor encryptor.Encryptor + topo Topology + streamer p2p.Streamer + us BidderStore + processer BidProcessor + commitmentDA preconfcontract.Interface + blockTracker blocktrackercontract.Interface + logger *slog.Logger + metrics *metrics } type Topology interface { @@ -70,17 +70,17 @@ func New( ) *Preconfirmation { commitmentsByBlockNumber := make(map[int64][]*EncryptedPreConfirmationWithDecrypted) return &Preconfirmation{ - owner: owner, - commitmentByBlockNumber: commitmentsByBlockNumber, - topo: topo, - streamer: streamer, - encryptor: encryptor, - us: us, - processer: processor, - commitmentDA: commitmentDA, - blockTracker: blockTracker, - logger: logger, - metrics: newMetrics(), + owner: owner, + commitmentByBlockNumber: commitmentsByBlockNumber, + topo: topo, + streamer: streamer, + encryptor: encryptor, + us: us, + processer: processor, + commitmentDA: commitmentDA, + blockTracker: blockTracker, + logger: logger, + metrics: newMetrics(), } } @@ -185,11 +185,7 @@ func (p *Preconfirmation) SendBid( PreConfirmation: preConfirmation, } - if _, exists := p.commitmentByBlockNumber[blockNumber]; exists { - p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) - } else { - p.commitmentByBlockNumber[blockNumber] = []*EncryptedPreConfirmationWithDecrypted{encryptedAndDecryptedPreconfirmation} - } + p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) logger.Info("received preconfirmation", "preConfirmation", preConfirmation) p.metrics.ReceivedPreconfsCount.Inc() @@ -295,11 +291,7 @@ func (p *Preconfirmation) handleBid( } blockNumber := preConfirmation.Bid.BlockNumber - if _, exists := p.commitmentByBlockNumber[blockNumber]; exists { - p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) - } else { - p.commitmentByBlockNumber[blockNumber] = []*EncryptedPreConfirmationWithDecrypted{encryptedAndDecryptedPreconfirmation} - } + p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) return stream.WriteMsg(ctx, encryptedPreConfirmation) } @@ -353,4 +345,4 @@ func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event block } } delete(p.commitmentByBlockNumber, event.BlockNumber.Int64()) -} \ No newline at end of file +} From fbfac6a67925a796f0f2d5b85fe47bd47d5e5e4d Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 8 Apr 2024 21:42:52 +0200 Subject: [PATCH 22/85] commented docker --- .github/workflows/goreleaser.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index dfda67b3..66859949 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -22,10 +22,10 @@ jobs: with: go-version: 1.21 cache: true - - name: GHCR Docker Login - run: echo "${{ secrets.CR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USERNAME }} --password-stdin - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + # - name: GHCR Docker Login + # run: echo "${{ secrets.CR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USERNAME }} --password-stdin + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v2 - uses: goreleaser/goreleaser-action@v4 with: distribution: goreleaser From 16bd615e415377a7fef767023200f6bb7754d10b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 8 Apr 2024 22:16:35 +0200 Subject: [PATCH 23/85] uncommented ghcr --- .github/workflows/goreleaser.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index 66859949..dfda67b3 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -22,10 +22,10 @@ jobs: with: go-version: 1.21 cache: true - # - name: GHCR Docker Login - # run: echo "${{ secrets.CR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USERNAME }} --password-stdin - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v2 + - name: GHCR Docker Login + run: echo "${{ secrets.CR_PAT }}" | docker login ghcr.io -u ${{ secrets.GHCR_USERNAME }} --password-stdin + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - uses: goreleaser/goreleaser-action@v4 with: distribution: goreleaser From 6f4dbe191463f6fef9fae7eeadb4453ce162a08d Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 13:20:24 +0200 Subject: [PATCH 24/85] switched from subscribtion to wss to pollInterval --- cmd/main.go | 9 ++++ .../keyexchange/{ => v1}/keyexchange.proto | 0 pkg/contracts/block_tracker/block_tracker.go | 54 ++++++++++++++++++- pkg/evmclient/evm.go | 4 +- pkg/evmclient/evmclient.go | 5 ++ pkg/evmclient/mock/mock.go | 16 ++++++ pkg/evmclient/mockevm/mockevm.go | 17 ++++++ pkg/node/node.go | 1 + pkg/preconfirmation/preconfirmation.go | 48 ++++++++++++----- pkg/preconfirmation/preconfirmation_test.go | 4 ++ pkg/rpc/bidder/service_test.go | 11 ++-- 11 files changed, 152 insertions(+), 17 deletions(-) rename messages/keyexchange/{ => v1}/keyexchange.proto (100%) diff --git a/cmd/main.go b/cmd/main.go index bd94aab1..a5ac0668 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -23,6 +23,7 @@ const ( defaultHTTPPort = 13523 defaultRPCPort = 13524 + defaultWSRPCPort = 13525 defaultConfigDir = "~/.mev-commit" defaultKeyFile = "key" @@ -128,6 +129,13 @@ var ( Value: "", }) + optionWSRPCPort = altsrc.NewIntFlag(&cli.IntFlag{ + Name: "ws-rpc-port", + Usage: "port to listen for websocket rpc connections", + EnvVars: []string{"MEV_COMMIT_WS_RPC_PORT"}, + Value: 0, + }) + optionBootnodes = altsrc.NewStringSliceFlag(&cli.StringSliceFlag{ Name: "bootnodes", Usage: "list of bootnodes to connect to", @@ -258,6 +266,7 @@ func main() { optionNATPort, optionServerTLSCert, optionServerTLSPrivateKey, + optionWSRPCPort, } app := &cli.App{ diff --git a/messages/keyexchange/keyexchange.proto b/messages/keyexchange/v1/keyexchange.proto similarity index 100% rename from messages/keyexchange/keyexchange.proto rename to messages/keyexchange/v1/keyexchange.proto diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 0278c3fb..6fd7bc86 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -6,13 +6,14 @@ import ( "log/slog" "math/big" "strings" + "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" - "github.com/primevprotocol/mev-commit/pkg/evmclient" + "github.com/primevprotocol/mev-commit/pkg/evmclient" ) var blockTrackerABI = func() abi.ABI { @@ -40,6 +41,8 @@ type Interface interface { GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) // SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) + // PollNewL1BlockEvents polls for NewL1Block events and sends them to the event channel. + PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error } type blockTrackerContract struct { @@ -313,3 +316,52 @@ func (btc *blockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventC return sub, nil } + +func (btc *blockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error { + ticker := time.NewTicker(pollInterval) + defer ticker.Stop() + + startBlock := uint64(0) // todo: take this variable from config + + for { + select { + case <-ticker.C: + // Update the query to search for events from startBlock to the latest block + query := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(startBlock)), + Addresses: []common.Address{btc.blockTrackerContractAddr}, + Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, + } + + // Use FilterLogs to get the logs synchronously + logs, err := btc.client.FilterLogs(ctx, query) + if err != nil { + btc.logger.Error("error filtering NewL1Block events", "error", err) + continue + } + + for _, log := range logs { + event := NewL1BlockEvent{} + err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) + if err != nil { + btc.logger.Error("error unpacking NewL1Block event", "error", err) + continue + } + event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) + event.Winner = common.HexToAddress(log.Topics[2].Hex()) + event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) + + eventCh <- event + } + + // Update startBlock for the next query to start from the latest checked block + if len(logs) > 0 { + lastLog := logs[len(logs)-1] + startBlock = lastLog.BlockNumber + 1 + } + + case <-ctx.Done(): + return ctx.Err() + } + } +} diff --git a/pkg/evmclient/evm.go b/pkg/evmclient/evm.go index 50916a51..6efcfa52 100644 --- a/pkg/evmclient/evm.go +++ b/pkg/evmclient/evm.go @@ -103,8 +103,10 @@ type EVM interface { // mined yet. Note that the transaction may not be part of the canonical chain even if // it's not pending. TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) - // FilterLogs executes a filter query to return the logs that satisfy the specified + // SubscribeFilterLogs creates a new subscription to filter logs. It returns a subscription SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) + // FilterLogs executes a filter query to return the logs that satisfy the specified + FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) } type Batcher interface { diff --git a/pkg/evmclient/evmclient.go b/pkg/evmclient/evmclient.go index ed583c57..c33eec0b 100644 --- a/pkg/evmclient/evmclient.go +++ b/pkg/evmclient/evmclient.go @@ -45,6 +45,7 @@ type Interface interface { CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) + FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) } type EvmClient struct { @@ -393,6 +394,10 @@ func (c *EvmClient) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*t return c.ethClient.BlockByNumber(ctx, blockNumber) } +func (c *EvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { + return c.ethClient.FilterLogs(ctx, query) +} + type TxnInfo struct { Hash string Nonce uint64 diff --git a/pkg/evmclient/mock/mock.go b/pkg/evmclient/mock/mock.go index ee6b48c6..7d566054 100644 --- a/pkg/evmclient/mock/mock.go +++ b/pkg/evmclient/mock/mock.go @@ -69,6 +69,14 @@ func WithBlockByNumber( } } +func WithFilterLogs( + f func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error), +) Option { + return func(m *mockEvmClient) { + m.FilterLogsFunc = f + } +} + type mockEvmClient struct { SendFunc func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) WaitForReceiptFunc func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) @@ -76,6 +84,7 @@ type mockEvmClient struct { CancelFunc func(ctx context.Context, txHash common.Hash) (common.Hash, error) SubscribeFilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) BlockByNumberFunc func(ctx context.Context, number *big.Int) (*types.Block, error) + FilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) } func (m *mockEvmClient) Send( @@ -132,3 +141,10 @@ func (m *mockEvmClient) BlockByNumber( } return m.BlockByNumber(ctx, number) } + +func (m *mockEvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { + if m.FilterLogsFunc == nil { + return nil, errors.New("not implemented") + } + return m.FilterLogsFunc(ctx, query) +} \ No newline at end of file diff --git a/pkg/evmclient/mockevm/mockevm.go b/pkg/evmclient/mockevm/mockevm.go index bcc11efb..dc65fd57 100644 --- a/pkg/evmclient/mockevm/mockevm.go +++ b/pkg/evmclient/mockevm/mockevm.go @@ -27,6 +27,7 @@ type mockEvm struct { transactionReceiptFunc func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) transactionByHasFunc func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) subscribeLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) + filterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) } type Option func(*mockEvm) @@ -117,6 +118,12 @@ func WithSubscribeLogsFunc(subscribeLogsFunc func(ctx context.Context, query eth } } +func WithFilterLogs(filterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)) Option { + return func(m *mockEvm) { + m.filterLogsFunc = filterLogsFunc + } +} + func NewMockEvm(networkID uint64, opts ...Option) *mockEvm { m := &mockEvm{} for _, opt := range opts { @@ -235,4 +242,14 @@ func (m *mockEvm) SubscribeFilterLogs( return m.subscribeLogsFunc(ctx, query, ch) } return nil, ErrNotImplemented +} + +func (m *mockEvm) FilterLogs( + ctx context.Context, + query ethereum.FilterQuery, +) ([]types.Log, error) { + if m.filterLogsFunc != nil { + return m.filterLogsFunc(ctx, query) + } + return nil, ErrNotImplemented } \ No newline at end of file diff --git a/pkg/node/node.go b/pkg/node/node.go index 3fe4839a..4a2de75a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -57,6 +57,7 @@ type Options struct { P2PAddr string HTTPAddr string RPCAddr string + WSRPCAddr string Bootnodes []string PreconfContract string BlockTrackerContract string diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 632bcda4..8412e3bc 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -299,24 +299,48 @@ func (p *Preconfirmation) handleBid( return nil } +// func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { +// ch := make(chan blocktrackercontract.NewL1BlockEvent) + +// sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) +// if err != nil { +// p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) +// return +// } +// defer sub.Unsubscribe() + +// for { +// select { +// case event := <-ch: +// handler(ctx, event) +// case err := <-sub.Err(): +// p.logger.Error("Subscription error", "error", err) +// return +// case <-ctx.Done(): +// p.logger.Info("Subscription context cancelled") +// return +// } +// } +// } + func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { ch := make(chan blocktrackercontract.NewL1BlockEvent) - sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) // Use ctx instead of context.Background() - if err != nil { - p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) - return - } - defer sub.Unsubscribe() + + pollInterval := time.Second * 10 + + go func() { + err := p.blockTracker.PollNewL1BlockEvents(ctx, ch, pollInterval) + if err != nil { + p.logger.Error("Failed to poll NewL1Block events", "error", err) + } + }() for { select { case event := <-ch: - handler(ctx, event) // Call the handler function - case err := <-sub.Err(): - p.logger.Error("Subscription error", "error", err) - return - case <-ctx.Done(): // Handle cancellation - p.logger.Info("Subscription context cancelled") + handler(ctx, event) + case <-ctx.Done(): + p.logger.Info("Polling context cancelled") return } } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index e14ac9f1..8cffc0ee 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -161,6 +161,10 @@ func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, ev return nil, nil } +func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { + return nil +} + func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { t.Helper() diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index a0d2cbc1..28f6b2ac 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -10,19 +10,20 @@ import ( "os" "strings" "testing" + "time" - "github.com/ethereum/go-ethereum" - blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" - "google.golang.org/protobuf/types/known/wrapperspb" "github.com/primevprotocol/mev-commit/pkg/util" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/test/bufconn" + "google.golang.org/protobuf/types/known/wrapperspb" ) const ( @@ -146,6 +147,10 @@ func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, ev return nil, nil } +func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { + return nil +} + func startServer(t *testing.T) bidderapiv1.BidderClient { lis := bufconn.Listen(bufferSize) From 4505776535679d9d09653832bc520442448d7fec Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 18:11:44 +0200 Subject: [PATCH 25/85] get rid of ethclient dial to l1 --- integrationtest/config/bidder.yaml | 1 - integrationtest/config/bootnode.yaml | 1 - integrationtest/config/provider.yaml | 1 - pkg/node/node.go | 16 ---------------- 4 files changed, 19 deletions(-) diff --git a/integrationtest/config/bidder.yaml b/integrationtest/config/bidder.yaml index 313ec2b6..70994abf 100644 --- a/integrationtest/config/bidder.yaml +++ b/integrationtest/config/bidder.yaml @@ -13,4 +13,3 @@ provider-registry-contract: settlement-rpc-endpoint: bootnodes: - /ip4/172.29.18.2/tcp/13522/p2p/16Uiu2HAmLYUvthfDCewNMdfPhrVefBbsfaPL22fWWfC2zuoh5SpV -l1-rpc-url: diff --git a/integrationtest/config/bootnode.yaml b/integrationtest/config/bootnode.yaml index 1a8115db..a04da47b 100644 --- a/integrationtest/config/bootnode.yaml +++ b/integrationtest/config/bootnode.yaml @@ -11,4 +11,3 @@ server-tls-private-key: /server-key.pem bidder-registry-contract: provider-registry-contract: settlement-rpc-endpoint: -l1-rpc-url: diff --git a/integrationtest/config/provider.yaml b/integrationtest/config/provider.yaml index 5ebd122e..56fcb6ba 100644 --- a/integrationtest/config/provider.yaml +++ b/integrationtest/config/provider.yaml @@ -14,4 +14,3 @@ provider-registry-contract: settlement-rpc-endpoint: bootnodes: - /ip4/172.29.18.2/tcp/13522/p2p/16Uiu2HAmLYUvthfDCewNMdfPhrVefBbsfaPL22fWWfC2zuoh5SpV -l1-rpc-url: diff --git a/pkg/node/node.go b/pkg/node/node.go index 4a2de75a..bdccbc74 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -64,7 +64,6 @@ type Options struct { ProviderRegistryContract string BidderRegistryContract string RPCEndpoint string - L1RPCUrl string NatAddr string TLSCertificateFile string TLSPrivateKeyFile string @@ -96,21 +95,6 @@ func NewNode(opts *Options) (*Node, error) { } nd.closers = append(nd.closers, evmClient) - l1RPC, err := ethclient.Dial(opts.L1RPCUrl) - if err != nil { - return nil, err - } - - evmL1Client, err := evmclient.New( - opts.KeySigner, - evmclient.WrapEthClient(l1RPC), - opts.Logger.With("component", "evmclient"), - ) - if err != nil { - return nil, err - } - nd.closers = append(nd.closers, evmL1Client) - srv.MetricsRegistry().MustRegister(evmClient.Metrics()...) bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) From 9f77daa17bae3a1fc886db09688d7b1808efa664 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 18:21:56 +0200 Subject: [PATCH 26/85] fixed golint --- cmd/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index a5ac0668..be8f8f30 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -347,7 +347,6 @@ func launchNodeWithConfig(c *cli.Context) error { ProviderRegistryContract: c.String(optionProviderRegistryAddr.Name), BidderRegistryContract: c.String(optionBidderRegistryAddr.Name), RPCEndpoint: c.String(optionSettlementRPCEndpoint.Name), - L1RPCUrl: c.String(optionL1RPCUrl.Name), NatAddr: natAddr, TLSCertificateFile: crtFile, TLSPrivateKeyFile: keyFile, From ba3bb142ecf664adc954dc7c91bc62f310d62afe Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 22:25:08 +0200 Subject: [PATCH 27/85] added logs for provider init --- pkg/node/node.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index bdccbc74..7c6cab41 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -57,7 +57,7 @@ type Options struct { P2PAddr string HTTPAddr string RPCAddr string - WSRPCAddr string + WSRPCAddr string Bootnodes []string PreconfContract string BlockTrackerContract string @@ -208,9 +208,10 @@ func NewNode(opts *Options) (*Node, error) { validator, ) providerapiv1.RegisterProviderServer(grpcServer, providerAPI) + opts.Logger.Info("registered provider api") bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) - + opts.Logger.Info("registered provider api metrics") preconfContractAddr := common.HexToAddress(opts.PreconfContract) commitmentDA = preconfcontract.New( @@ -218,7 +219,7 @@ func NewNode(opts *Options) (*Node, error) { evmClient, opts.Logger.With("component", "preconfcontract"), ) - + opts.Logger.Info("registered preconf contract") preconfProto := preconfirmation.New( keyKeeper.GetAddress(), topo, @@ -230,11 +231,12 @@ func NewNode(opts *Options) (*Node, error) { blockTracker, opts.Logger.With("component", "preconfirmation_protocol"), ) + opts.Logger.Info("registered preconfirmation protocol") preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) - + opts.Logger.Info("registered stream handlers") keyexchange := keyexchange.New( topo, p2pSvc, @@ -242,8 +244,10 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) + opts.Logger.Info("registered keyexchange protocol") p2pSvc.AddStreamHandlers(keyexchange.Streams()...) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) + opts.Logger.Info("registered metrics collectors") case p2p.PeerTypeBidder.String(): preconfProto := preconfirmation.New( @@ -375,6 +379,7 @@ func NewNode(opts *Options) (*Node, error) { }, ), ) + opts.Logger.Info("grpc server connected and handlers are started", "state", grpcConn.GetState()) } server := &http.Server{ From 317c78dac87aca72ce593b3912ccd9f2b58130de Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 22:32:02 +0200 Subject: [PATCH 28/85] added log errors --- pkg/node/node.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/node/node.go b/pkg/node/node.go index 7c6cab41..faeeca59 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -83,6 +83,7 @@ func NewNode(opts *Options) (*Node, error) { contractRPC, err := ethclient.Dial(opts.RPCEndpoint) if err != nil { + opts.Logger.Error("failed to connect to rpc", "error", err) return nil, err } evmClient, err := evmclient.New( @@ -91,6 +92,7 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "evmclient"), ) if err != nil { + opts.Logger.Error("failed to create evm client", "error", err) return nil, err } nd.closers = append(nd.closers, evmClient) @@ -118,11 +120,13 @@ func NewNode(opts *Options) (*Node, error) { case p2p.PeerTypeProvider.String(): keyKeeper, err = keykeeper.NewProviderKeyKeeper(opts.KeySigner) if err != nil { + opts.Logger.Error("failed to create provider key keeper", "error", err) return nil, errors.Join(err, nd.Close()) } case p2p.PeerTypeBidder.String(): keyKeeper, err = keykeeper.NewBidderKeyKeeper(opts.KeySigner) if err != nil { + opts.Logger.Error("failed to create bidder key keeper", "error", err) return nil, errors.Join(err, nd.Close()) } default: @@ -141,6 +145,7 @@ func NewNode(opts *Options) (*Node, error) { NatAddr: opts.NatAddr, }) if err != nil { + opts.Logger.Error("failed to create p2p service", "error", err) return nil, err } nd.closers = append(nd.closers, p2pSvc) @@ -164,6 +169,7 @@ func NewNode(opts *Options) (*Node, error) { if opts.PeerType != p2p.PeerTypeBootnode.String() { lis, err := net.Listen("tcp", opts.RPCAddr) if err != nil { + opts.Logger.Error("failed to listen", "error", err) return nil, errors.Join(err, nd.Close()) } @@ -174,6 +180,7 @@ func NewNode(opts *Options) (*Node, error) { opts.TLSPrivateKeyFile, ) if err != nil { + opts.Logger.Error("failed to load TLS credentials", "error", err) return nil, fmt.Errorf("unable to load TLS credentials: %w", err) } } @@ -182,6 +189,7 @@ func NewNode(opts *Options) (*Node, error) { preconfEncryptor := preconfencryptor.NewEncryptor(keyKeeper) validator, err := protovalidate.New() if err != nil { + opts.Logger.Error("failed to create proto validator", "error", err) return nil, errors.Join(err, nd.Close()) } From 6a737216d822a4d64eaf9b1c9bc77e6f2b7428c4 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 9 Apr 2024 23:00:19 +0200 Subject: [PATCH 29/85] added go func for blocking go routine --- pkg/preconfirmation/preconfirmation.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 8412e3bc..e57ddc91 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -335,15 +335,17 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, } }() - for { - select { - case event := <-ch: - handler(ctx, event) - case <-ctx.Done(): - p.logger.Info("Polling context cancelled") - return + go func() { + for { + select { + case event := <-ch: + handler(ctx, event) + case <-ctx.Done(): + p.logger.Info("Polling context cancelled") + return + } } - } + }() } func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { From 6b5656d9e0e06c83f48462e53188bf8730e325ce Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 10 Apr 2024 14:22:45 +0200 Subject: [PATCH 30/85] added prints for minStake call --- cmd/main.go | 7 ------- pkg/contracts/block_tracker/block_tracker.go | 1 - pkg/contracts/provider_registry/registry.go | 2 ++ pkg/preconfirmation/preconfirmation.go | 1 + 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index be8f8f30..b52c0023 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -207,12 +207,6 @@ var ( Value: "http://localhost:8545", }) - optionL1RPCUrl = altsrc.NewStringFlag(&cli.StringFlag{ - Name: "l1-rpc-url", - Usage: "rpc url of the L1 node", - EnvVars: []string{"MEV_COMMIT_L1_RPC_URL"}, - }) - optionNATAddr = altsrc.NewStringFlag(&cli.StringFlag{ Name: "nat-addr", Usage: "external address of the node", @@ -261,7 +255,6 @@ func main() { optionProviderRegistryAddr, optionPreconfStoreAddr, optionSettlementRPCEndpoint, - optionL1RPCUrl, optionNATAddr, optionNATPort, optionServerTLSCert, diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 6fd7bc86..e9f6d6e4 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -333,7 +333,6 @@ func (btc *blockTrackerContract) PollNewL1BlockEvents(ctx context.Context, event Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, } - // Use FilterLogs to get the logs synchronously logs, err := btc.client.FilterLogs(ctx, query) if err != nil { btc.logger.Error("error filtering NewL1Block events", "error", err) diff --git a/pkg/contracts/provider_registry/registry.go b/pkg/contracts/provider_registry/registry.go index 9c37ecdf..9736f6f4 100644 --- a/pkg/contracts/provider_registry/registry.go +++ b/pkg/contracts/provider_registry/registry.go @@ -126,9 +126,11 @@ func (r *registryContract) GetMinStake(ctx context.Context) (*big.Int, error) { CallData: callData, }) if err != nil { + r.logger.Error("error calling contract", "error", err) return nil, err } + r.logger.Info("minStake result", "result", result) results, err := r.registryABI.Unpack("minStake", result) if err != nil { r.logger.Error("error unpacking result", "error", err) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index e57ddc91..6d7fe3d0 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -335,6 +335,7 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, } }() + // todo: fix this go func() { for { select { From a56afca02b4145e87969a878c7ab38f65a51299d Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 10 Apr 2024 17:04:22 +0200 Subject: [PATCH 31/85] added json marshal/unmarshal for the keys --- pkg/p2p/p2p.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/pkg/p2p/p2p.go b/pkg/p2p/p2p.go index 06e84c40..770cf695 100644 --- a/pkg/p2p/p2p.go +++ b/pkg/p2p/p2p.go @@ -3,11 +3,14 @@ package p2p import ( "context" "crypto/ecdh" + "encoding/base64" + "encoding/json" "errors" "io" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" + "github.com/primevprotocol/mev-commit/pkg/keykeeper" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" @@ -61,6 +64,55 @@ type Keys struct { NIKEPublicKey *ecdh.PublicKey } +type jsonKeys struct { + PKEPublicKey string `json:"pkePublicKey"` + NIKEPublicKey string `json:"nikePublicKey"` +} + +func (k *Keys) MarshalJSON() ([]byte, error) { + ppk := keykeeper.SerializePublicKey(k.PKEPublicKey) + pkePublicKeyB64 := base64.StdEncoding.EncodeToString(ppk) + + npk := k.NIKEPublicKey.Bytes() + nikePublicKeyB64 := base64.StdEncoding.EncodeToString(npk) + + return json.Marshal(jsonKeys{ + PKEPublicKey: pkePublicKeyB64, + NIKEPublicKey: nikePublicKeyB64, + }) +} + +func (k *Keys) UnmarshalJSON(data []byte) error { + var jk jsonKeys + if err := json.Unmarshal(data, &jk); err != nil { + return err + } + + pkePublicKeyBytes, err := base64.StdEncoding.DecodeString(jk.PKEPublicKey) + if err != nil { + return err + } + + pkePublicKey, err := keykeeper.DeserializePublicKey(pkePublicKeyBytes) + if err != nil { + return err + } + + nikePublicKeyBytes, err := base64.StdEncoding.DecodeString(jk.NIKEPublicKey) + if err != nil { + return err + } + nikePublicKey, err := ecdh.P256().NewPublicKey(nikePublicKeyBytes) + if err != nil { + return err + } + + k.PKEPublicKey = pkePublicKey + k.NIKEPublicKey = nikePublicKey + + return nil +} + type Peer struct { EthAddress common.Address Type PeerType From 1829544953efebf653cd767777ae631843028fe9 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 10 Apr 2024 17:31:33 +0200 Subject: [PATCH 32/85] added block tracker contract to main.go --- cmd/main.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/main.go b/cmd/main.go index b52c0023..d9977fcb 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -200,6 +200,13 @@ var ( Value: contracts.TestnetContracts.PreconfCommitmentStore, }) + optionBlockTrackerAddr = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "block-tracker-contract", + Usage: "address of the block tracker contract", + EnvVars: []string{"MEV_COMMIT_BLOCK_TRACKER_ADDR"}, + Value: contracts.TestnetContracts.BlockTracker, + }) + optionSettlementRPCEndpoint = altsrc.NewStringFlag(&cli.StringFlag{ Name: "settlement-rpc-endpoint", Usage: "rpc endpoint of the settlement layer", @@ -254,6 +261,7 @@ func main() { optionBidderRegistryAddr, optionProviderRegistryAddr, optionPreconfStoreAddr, + optionBlockTrackerAddr, optionSettlementRPCEndpoint, optionNATAddr, optionNATPort, @@ -339,6 +347,7 @@ func launchNodeWithConfig(c *cli.Context) error { PreconfContract: c.String(optionPreconfStoreAddr.Name), ProviderRegistryContract: c.String(optionProviderRegistryAddr.Name), BidderRegistryContract: c.String(optionBidderRegistryAddr.Name), + BlockTrackerContract: c.String(optionBlockTrackerAddr.Name), RPCEndpoint: c.String(optionSettlementRPCEndpoint.Name), NatAddr: natAddr, TLSCertificateFile: crtFile, From d7650f1208dc13334b77c2e055e1bcf921fb5a73 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 10 Apr 2024 17:44:49 +0200 Subject: [PATCH 33/85] updated contract-abi link --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 66a2d635..101e3c32 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a + github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index 7968f008..e000a57e 100644 --- a/go.sum +++ b/go.sum @@ -344,6 +344,8 @@ github.com/primevprotocol/contracts-abi v0.2.4-0.20240328210357-00b3c4b870a6 h1: github.com/primevprotocol/contracts-abi v0.2.4-0.20240328210357-00b3c4b870a6/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a h1:bSmtNx7BXLtnKiOP4Ku8xpKIumScyBl96bb5hcBvvV8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad h1:Gvv4EwVerh4gpBBT4uU7gMHhuSGwFnXDZUQxsxWQ0ls= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= From c15ce3c1d4ed3dc81926784cdab4626ef44cf4dc Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 11 Apr 2024 10:30:02 +0200 Subject: [PATCH 34/85] fixed link to block tracker contract --- pkg/node/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index faeeca59..dcae62ab 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -198,7 +198,7 @@ func NewNode(opts *Options) (*Node, error) { commitmentDA preconfcontract.Interface = noOpCommitmentDA{} ) - blockTrackerAddr := common.HexToAddress(opts.PreconfContract) + blockTrackerAddr := common.HexToAddress(opts.BlockTrackerContract) blockTracker := blocktrackercontract.New( blockTrackerAddr, From 3f089255c884927d0cf10e422b5cc30467facce8 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 11 Apr 2024 16:09:39 +0200 Subject: [PATCH 35/85] added more logs to sc calls --- pkg/contracts/bidder_registry/bidder_registry.go | 7 +++++++ pkg/keyexchange/keyexchange.go | 2 ++ pkg/rpc/bidder/service.go | 2 ++ 3 files changed, 11 insertions(+) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 63d02783..354df2b5 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -156,5 +156,12 @@ func (r *bidderRegistryContract) CheckBidderAllowance( r.logger.Error("error getting stake", "error", err) return false } + r.logger.Info("checking bidder allowance", + "stake", stake.Int64(), + "blocksPerWindow", blocksPerWindow.Int64(), + "minStake", minStake.Int64(), + "window", window.Int64(), + "address", address.Hex(), + ) return (stake.Div(stake, blocksPerWindow)).Cmp(minStake) >= 0 } diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go index 0455aa5d..b346a42e 100644 --- a/pkg/keyexchange/keyexchange.go +++ b/pkg/keyexchange/keyexchange.go @@ -196,6 +196,8 @@ func (ke *KeyExchange) handleTimestampMessage(ctx context.Context, peer p2p.Peer } ke.keyKeeper.(*keykeeper.ProviderKeyKeeper).SetAESKey(peer.EthAddress, aesKey) + + ke.logger.Info("successfully processed timestamp message", "peer", peer.EthAddress, "key", aesKey) return nil } diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index c93cb831..8d3c6de0 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -136,6 +136,8 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } + s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", currentWindow+1) + return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil } From 2c631ea45d59ede300c60a990dc7120bf90d949e Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 11 Apr 2024 21:01:18 +0200 Subject: [PATCH 36/85] switched to ws port to connect to ethereum --- cmd/main.go | 18 ++-- pkg/contracts/block_tracker/block_tracker.go | 97 ++++++++++---------- pkg/contracts/provider_registry/registry.go | 1 - pkg/evmclient/evm.go | 2 +- pkg/node/node.go | 24 ++++- pkg/preconfirmation/preconfirmation.go | 88 +++++++++--------- pkg/preconfirmation/preconfirmation_test.go | 6 +- pkg/rpc/bidder/service_test.go | 7 +- 8 files changed, 128 insertions(+), 115 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index d9977fcb..96981094 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -23,7 +23,6 @@ const ( defaultHTTPPort = 13523 defaultRPCPort = 13524 - defaultWSRPCPort = 13525 defaultConfigDir = "~/.mev-commit" defaultKeyFile = "key" @@ -129,13 +128,6 @@ var ( Value: "", }) - optionWSRPCPort = altsrc.NewIntFlag(&cli.IntFlag{ - Name: "ws-rpc-port", - Usage: "port to listen for websocket rpc connections", - EnvVars: []string{"MEV_COMMIT_WS_RPC_PORT"}, - Value: 0, - }) - optionBootnodes = altsrc.NewStringSliceFlag(&cli.StringSliceFlag{ Name: "bootnodes", Usage: "list of bootnodes to connect to", @@ -214,6 +206,13 @@ var ( Value: "http://localhost:8545", }) + optionSettlementWSRPCEndpoint = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "settlement-ws-rpc-endpoint", + Usage: "ws rpc endpoint of the settlement layer", + EnvVars: []string{"MEV_COMMIT_SETTLEMENT_WS_RPC_ENDPOINT"}, + Value: "ws://localhost:8546", + }) + optionNATAddr = altsrc.NewStringFlag(&cli.StringFlag{ Name: "nat-addr", Usage: "external address of the node", @@ -263,11 +262,11 @@ func main() { optionPreconfStoreAddr, optionBlockTrackerAddr, optionSettlementRPCEndpoint, + optionSettlementWSRPCEndpoint, optionNATAddr, optionNATPort, optionServerTLSCert, optionServerTLSPrivateKey, - optionWSRPCPort, } app := &cli.App{ @@ -349,6 +348,7 @@ func launchNodeWithConfig(c *cli.Context) error { BidderRegistryContract: c.String(optionBidderRegistryAddr.Name), BlockTrackerContract: c.String(optionBlockTrackerAddr.Name), RPCEndpoint: c.String(optionSettlementRPCEndpoint.Name), + WSRPCEndpoint: c.String(optionSettlementWSRPCEndpoint.Name), NatAddr: natAddr, TLSCertificateFile: crtFile, TLSPrivateKeyFile: keyFile, diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index e9f6d6e4..6d776e55 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -6,7 +6,6 @@ import ( "log/slog" "math/big" "strings" - "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" @@ -42,7 +41,7 @@ type Interface interface { // SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) // PollNewL1BlockEvents polls for NewL1Block events and sends them to the event channel. - PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error + // PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error } type blockTrackerContract struct { @@ -317,50 +316,50 @@ func (btc *blockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventC return sub, nil } -func (btc *blockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error { - ticker := time.NewTicker(pollInterval) - defer ticker.Stop() - - startBlock := uint64(0) // todo: take this variable from config - - for { - select { - case <-ticker.C: - // Update the query to search for events from startBlock to the latest block - query := ethereum.FilterQuery{ - FromBlock: big.NewInt(int64(startBlock)), - Addresses: []common.Address{btc.blockTrackerContractAddr}, - Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, - } - - logs, err := btc.client.FilterLogs(ctx, query) - if err != nil { - btc.logger.Error("error filtering NewL1Block events", "error", err) - continue - } - - for _, log := range logs { - event := NewL1BlockEvent{} - err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) - if err != nil { - btc.logger.Error("error unpacking NewL1Block event", "error", err) - continue - } - event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) - event.Winner = common.HexToAddress(log.Topics[2].Hex()) - event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) - - eventCh <- event - } - - // Update startBlock for the next query to start from the latest checked block - if len(logs) > 0 { - lastLog := logs[len(logs)-1] - startBlock = lastLog.BlockNumber + 1 - } - - case <-ctx.Done(): - return ctx.Err() - } - } -} +// func (btc *blockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error { +// ticker := time.NewTicker(pollInterval) +// defer ticker.Stop() + +// startBlock := uint64(0) // todo: take this variable from config + +// for { +// select { +// case <-ticker.C: +// // Update the query to search for events from startBlock to the latest block +// query := ethereum.FilterQuery{ +// FromBlock: big.NewInt(int64(startBlock)), +// Addresses: []common.Address{btc.blockTrackerContractAddr}, +// Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, +// } + +// logs, err := btc.client.FilterLogs(ctx, query) +// if err != nil { +// btc.logger.Error("error filtering NewL1Block events", "error", err) +// continue +// } + +// for _, log := range logs { +// event := NewL1BlockEvent{} +// err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) +// if err != nil { +// btc.logger.Error("error unpacking NewL1Block event", "error", err) +// continue +// } +// event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) +// event.Winner = common.HexToAddress(log.Topics[2].Hex()) +// event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) + +// eventCh <- event +// } + +// // Update startBlock for the next query to start from the latest checked block +// if len(logs) > 0 { +// lastLog := logs[len(logs)-1] +// startBlock = lastLog.BlockNumber + 1 +// } + +// case <-ctx.Done(): +// return ctx.Err() +// } +// } +// } diff --git a/pkg/contracts/provider_registry/registry.go b/pkg/contracts/provider_registry/registry.go index 9736f6f4..b81563a6 100644 --- a/pkg/contracts/provider_registry/registry.go +++ b/pkg/contracts/provider_registry/registry.go @@ -130,7 +130,6 @@ func (r *registryContract) GetMinStake(ctx context.Context) (*big.Int, error) { return nil, err } - r.logger.Info("minStake result", "result", result) results, err := r.registryABI.Unpack("minStake", result) if err != nil { r.logger.Error("error unpacking result", "error", err) diff --git a/pkg/evmclient/evm.go b/pkg/evmclient/evm.go index 6efcfa52..1f12128c 100644 --- a/pkg/evmclient/evm.go +++ b/pkg/evmclient/evm.go @@ -143,4 +143,4 @@ func WrapEthClient(client *ethclient.Client) EVM { return &evm{ Client: client, } -} +} \ No newline at end of file diff --git a/pkg/node/node.go b/pkg/node/node.go index dcae62ab..0ed5f0ce 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -57,13 +57,13 @@ type Options struct { P2PAddr string HTTPAddr string RPCAddr string - WSRPCAddr string Bootnodes []string PreconfContract string BlockTrackerContract string ProviderRegistryContract string BidderRegistryContract string RPCEndpoint string + WSRPCEndpoint string NatAddr string TLSCertificateFile string TLSPrivateKeyFile string @@ -96,9 +96,25 @@ func NewNode(opts *Options) (*Node, error) { return nil, err } nd.closers = append(nd.closers, evmClient) - srv.MetricsRegistry().MustRegister(evmClient.Metrics()...) + wsRPC, err := ethclient.Dial(opts.WSRPCEndpoint) + if err != nil { + opts.Logger.Error("failed to connect to ws rpc", "error", err) + return nil, err + } + wsEvmClient, err := evmclient.New( + opts.KeySigner, + evmclient.WrapEthClient(wsRPC), + opts.Logger.With("component", "wsevmclient"), + ) + if err != nil { + opts.Logger.Error("failed to create ws evm client", "error", err) + return nil, err + } + nd.closers = append(nd.closers, wsEvmClient) + srv.MetricsRegistry().MustRegister(wsEvmClient.Metrics()...) + bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) bidderRegistry := bidder_registrycontract.New( @@ -240,7 +256,7 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "preconfirmation_protocol"), ) opts.Logger.Info("registered preconfirmation protocol") - preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) + go preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) @@ -269,7 +285,7 @@ func NewNode(opts *Options) (*Node, error) { blockTracker, opts.Logger.With("component", "preconfirmation_protocol"), ) - preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) + go preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) bidderAPI := bidderapi.NewService( diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 6d7fe3d0..e3d8e51b 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -299,56 +299,56 @@ func (p *Preconfirmation) handleBid( return nil } -// func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { -// ch := make(chan blocktrackercontract.NewL1BlockEvent) - -// sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) -// if err != nil { -// p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) -// return -// } -// defer sub.Unsubscribe() - -// for { -// select { -// case event := <-ch: -// handler(ctx, event) -// case err := <-sub.Err(): -// p.logger.Error("Subscription error", "error", err) -// return -// case <-ctx.Done(): -// p.logger.Info("Subscription context cancelled") -// return -// } -// } -// } - func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { ch := make(chan blocktrackercontract.NewL1BlockEvent) - pollInterval := time.Second * 10 - - go func() { - err := p.blockTracker.PollNewL1BlockEvents(ctx, ch, pollInterval) - if err != nil { - p.logger.Error("Failed to poll NewL1Block events", "error", err) - } - }() - - // todo: fix this - go func() { - for { - select { - case event := <-ch: - handler(ctx, event) - case <-ctx.Done(): - p.logger.Info("Polling context cancelled") - return - } + sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) + if err != nil { + p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) + return + } + defer sub.Unsubscribe() + + for { + select { + case event := <-ch: + handler(ctx, event) + case err := <-sub.Err(): + p.logger.Error("Subscription error", "error", err) + return + case <-ctx.Done(): + p.logger.Info("Subscription context cancelled") + return } - }() + } } +// func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { +// ch := make(chan blocktrackercontract.NewL1BlockEvent) + +// pollInterval := time.Second * 10 + +// go func() { +// err := p.blockTracker.PollNewL1BlockEvents(ctx, ch, pollInterval) +// if err != nil { +// p.logger.Error("Failed to poll NewL1Block events", "error", err) +// } +// }() + +// // todo: fix this +// go func() { +// for { +// select { +// case event := <-ch: +// handler(ctx, event) +// case <-ctx.Done(): +// p.logger.Info("Polling context cancelled") +// return +// } +// } +// }() +// } + func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) for _, commitment := range p.commitmentByBlockNumber[event.BlockNumber.Int64()] { diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 8cffc0ee..0bc61db7 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -161,9 +161,9 @@ func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, ev return nil, nil } -func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { - return nil -} +// func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { +// return nil +// } func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { t.Helper() diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 28f6b2ac..36107ec3 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -10,7 +10,6 @@ import ( "os" "strings" "testing" - "time" "github.com/bufbuild/protovalidate-go" "github.com/ethereum/go-ethereum" @@ -147,9 +146,9 @@ func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, ev return nil, nil } -func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { - return nil -} +// func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { +// return nil +// } func startServer(t *testing.T) bidderapiv1.BidderClient { lis := bufconn.Listen(bufferSize) From aa3f0a3ae5a82f8e67b2a495b7a1cfc5f96810c4 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 11 Apr 2024 22:10:07 +0200 Subject: [PATCH 37/85] fixed double metrics --- pkg/contracts/block_tracker/block_tracker.go | 5 ++++- pkg/node/node.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 6d776e55..2c0adf61 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -48,6 +48,7 @@ type blockTrackerContract struct { blockTrackerABI abi.ABI blockTrackerContractAddr common.Address client evmclient.Interface + wsClient evmclient.Interface logger *slog.Logger } @@ -60,12 +61,14 @@ type NewL1BlockEvent struct { func New( blockTrackerContractAddr common.Address, client evmclient.Interface, + wsClient evmclient.Interface, logger *slog.Logger, ) Interface { return &blockTrackerContract{ blockTrackerABI: blockTrackerABI, blockTrackerContractAddr: blockTrackerContractAddr, client: client, + wsClient: wsClient, logger: logger, } } @@ -287,7 +290,7 @@ func (btc *blockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventC } logsCh := make(chan types.Log) - sub, err := btc.client.SubscribeFilterLogs(ctx, query, logsCh) + sub, err := btc.wsClient.SubscribeFilterLogs(ctx, query, logsCh) if err != nil { return nil, err } diff --git a/pkg/node/node.go b/pkg/node/node.go index 0ed5f0ce..f7fcabaa 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -113,7 +113,6 @@ func NewNode(opts *Options) (*Node, error) { return nil, err } nd.closers = append(nd.closers, wsEvmClient) - srv.MetricsRegistry().MustRegister(wsEvmClient.Metrics()...) bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) @@ -219,6 +218,7 @@ func NewNode(opts *Options) (*Node, error) { blockTracker := blocktrackercontract.New( blockTrackerAddr, evmClient, + wsEvmClient, opts.Logger.With("component", "blocktrackercontract"), ) From 0471cd0f01a3f3bc7f60ad21fa44813a06d47299 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 12 Apr 2024 12:30:57 +0200 Subject: [PATCH 38/85] added window++ to GetAllowance method --- pkg/preconfirmation/preconfirmation.go | 1 - pkg/rpc/bidder/service.go | 1 + pkg/signer/preconfencryptor/encryptor.go | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index e3d8e51b..491effac 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -335,7 +335,6 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, // } // }() -// // todo: fix this // go func() { // for { // select { diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 8d3c6de0..4def377f 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -154,6 +154,7 @@ func (s *Service) GetAllowance( if err != nil { return nil, status.Errorf(codes.Internal, "getting current window: %v", err) } + window++ } else { window = r.WindowNumber.Value } diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index 0f16ec01..b71762d7 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -126,7 +126,6 @@ func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*prec SharedSecret: sharedSecredProviderSk, } - // todo: update to take preconf hash into hash calculation preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) if err != nil { return nil, nil, err From d08ff1a2343446f03d7d5453c80965fb338d286b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 12 Apr 2024 15:56:05 +0200 Subject: [PATCH 39/85] deleted wait receipt from open commitment --- pkg/contracts/preconf/preconf.go | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 934640f4..d79f29cd 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -87,6 +87,7 @@ func (p *preconfContract) StoreEncryptedCommitment( return common.Hash{}, err } + // todo: add event tracker to add commitment to avoid waiting receipt, err := p.client.WaitForReceipt(ctx, txnHash) if err != nil { return common.Hash{}, err // Updated to return common.Hash{} @@ -137,7 +138,7 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } - txHash, err := p.client.Send(ctx, &evmclient.TxRequest{ + _, err = p.client.Send(ctx, &evmclient.TxRequest{ To: &p.preconfContractAddr, CallData: callData, }) @@ -145,25 +146,5 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } - receipt, err := p.client.WaitForReceipt(ctx, txHash) - if err != nil { - return common.Hash{}, err - } - - p.logger.Info("OpenCommitment transaction successful", "txnHash", txnHash) - - // Assuming "CommitmentOpened" is the event that gets emitted when openCommitment is successfully called - eventTopicHash := p.preconfABI.Events["CommitmentOpened"].ID - - for _, log := range receipt.Logs { - if len(log.Topics) > 0 && log.Topics[0] == eventTopicHash { - // Assuming the first indexed argument (Topics[1]) is the commitmentIndex - commitmentIndex := log.Topics[1] - p.logger.Info("Commitment opened", "commitmentIndex", commitmentIndex.Hex()) - - return commitmentIndex, nil - } - } - return common.Hash{}, fmt.Errorf("commitmentIndex not found in transaction receipt") } From 421c600ac63784fef4697e08d6c27caf30f29a42 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 12 Apr 2024 20:21:24 +0200 Subject: [PATCH 40/85] added log parsing for the bidder --- pkg/contracts/bidder_registry/bidder_registry.go | 14 ++++++++++++++ pkg/preconfirmation/preconfirmation.go | 1 + 2 files changed, 15 insertions(+) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 354df2b5..389b0017 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -82,6 +82,20 @@ func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *bi return err } + var bidderRegistered struct { + Bidder common.Address + PrepaidAmount *big.Int + WindowNumber *big.Int + } + for _, log := range receipt.Logs { + err := r.bidderRegistryABI.UnpackIntoInterface(&bidderRegistered, "BidderRegistered", log.Data) + if err != nil { + r.logger.Debug("Failed to unpack event", "err", err) + continue + } + r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "prepaidAmount", bidderRegistered.PrepaidAmount.Uint64(), "windowNumber", bidderRegistered.WindowNumber.Int64()) + } + r.logger.Info("prepay successful for bidder registry", "txnHash", txnHash) return nil diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 491effac..a79f5fc0 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -350,6 +350,7 @@ func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) + // todo: for provider check if winner == providerAddress, for bidder if committerAddress for _, commitment := range p.commitmentByBlockNumber[event.BlockNumber.Int64()] { _, err := p.commitmentDA.OpenCommitment( ctx, From 08734544317f965b0a7455e984260c934229ec30 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Sat, 13 Apr 2024 16:31:36 +0200 Subject: [PATCH 41/85] added logs --- pkg/contracts/bidder_registry/bidder_registry.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 389b0017..451d12ac 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -83,11 +83,12 @@ func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *bi } var bidderRegistered struct { - Bidder common.Address + Bidder string PrepaidAmount *big.Int WindowNumber *big.Int } for _, log := range receipt.Logs { + r.logger.Info("bidder registry log", "logData", log.Data) err := r.bidderRegistryABI.UnpackIntoInterface(&bidderRegistered, "BidderRegistered", log.Data) if err != nil { r.logger.Debug("Failed to unpack event", "err", err) @@ -96,7 +97,7 @@ func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *bi r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "prepaidAmount", bidderRegistered.PrepaidAmount.Uint64(), "windowNumber", bidderRegistered.WindowNumber.Int64()) } - r.logger.Info("prepay successful for bidder registry", "txnHash", txnHash) + r.logger.Info("prepay successful for bidder registry", "txnHash", txnHash, "bidder", bidderRegistered.Bidder) return nil } @@ -171,10 +172,10 @@ func (r *bidderRegistryContract) CheckBidderAllowance( return false } r.logger.Info("checking bidder allowance", - "stake", stake.Int64(), - "blocksPerWindow", blocksPerWindow.Int64(), - "minStake", minStake.Int64(), - "window", window.Int64(), + "stake", stake.Uint64(), + "blocksPerWindow", blocksPerWindow.Uint64(), + "minStake", minStake.Uint64(), + "window", window.Uint64(), "address", address.Hex(), ) return (stake.Div(stake, blocksPerWindow)).Cmp(minStake) >= 0 From 51a109d2ca46b84b412cd1cc748d3bfed19c9d66 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Sat, 13 Apr 2024 19:34:42 +0200 Subject: [PATCH 42/85] updated bidder.proto to allow big integers --- gen/go/bidderapi/v1/bidderapi.pb.go | 527 +++++++++--------- gen/go/keyexchange/{ => v1}/keyexchange.pb.go | 118 ++-- pkg/keyexchange/keyexchange.go | 4 +- rpc/bidderapi/v1/bidderapi.proto | 2 +- 4 files changed, 325 insertions(+), 326 deletions(-) rename gen/go/keyexchange/{ => v1}/keyexchange.pb.go (50%) diff --git a/gen/go/bidderapi/v1/bidderapi.pb.go b/gen/go/bidderapi/v1/bidderapi.pb.go index 2c8a63c4..65119795 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.go @@ -415,274 +415,273 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, - 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xa5, 0x01, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8c, 0x01, 0x92, 0x41, 0x2e, - 0x32, 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, - 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6e, - 0x20, 0x77, 0x65, 0x69, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, - 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, - 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, - 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, - 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x3a, 0x7a, 0x92, 0x41, 0x77, 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, - 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, - 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, - 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x9e, 0x01, - 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x74, 0x92, 0x41, 0x71, 0x0a, 0x4b, 0x2a, - 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0x38, 0x47, 0x65, 0x74, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x0e, - 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb6, - 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xdb, 0x01, 0x92, 0x41, - 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, - 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x70, 0xba, 0x01, 0x6d, 0x0a, 0x0c, 0x77, 0x69, - 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, - 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x2e, 0x1a, 0x26, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x3d, - 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, - 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, - 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, - 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, - 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, - 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, - 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, - 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, - 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, - 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, - 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, - 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, - 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, - 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, - 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, - 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, - 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, - 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, - 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, - 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, - 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa0, 0x02, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x01, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x7a, 0x92, 0x41, 0x2e, 0x32, + 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, + 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x20, + 0x77, 0x65, 0x69, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x46, + 0xba, 0x01, 0x43, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x18, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, + 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x7a, + 0x92, 0x41, 0x77, 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x9e, 0x01, 0x0a, 0x0e, 0x50, + 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x74, 0x92, 0x41, 0x71, 0x0a, 0x4b, 0x2a, 0x0f, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, + 0x65, 0x74, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, + 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x9e, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, + 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xdb, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, + 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x2e, 0xba, 0x48, 0x70, 0xba, 0x01, 0x6d, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x26, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, + 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, + 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, + 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, + 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, + 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, + 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, + 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, + 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, + 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, + 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, + 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, + 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, - 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, - 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, - 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, - 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, - 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, - 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, - 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, - 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, - 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, - 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, - 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, - 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, - 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, - 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, - 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, - 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, - 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, - 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, - 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, - 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, - 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, - 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, - 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, - 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, - 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, - 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, - 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, - 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, - 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, - 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, - 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, - 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, - 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, - 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, + 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, + 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, + 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, - 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, - 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, - 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, - 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, - 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, - 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, - 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, - 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, - 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, - 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, - 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x42, 0xb6, - 0x02, 0x92, 0x41, 0x7a, 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, - 0x50, 0x49, 0x2a, 0x5d, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, - 0x31, 0x12, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, - 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, - 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, - 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x42, 0x0e, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, - 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, - 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, - 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, - 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, + 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, + 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, + 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, + 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, + 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, + 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, + 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, + 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, + 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, + 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, + 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, + 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, + 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, + 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, + 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, + 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, + 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, + 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, + 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, + 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, + 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, + 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, + 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, + 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, + 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, + 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, + 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, + 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, + 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, + 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, + 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, + 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, + 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, + 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, + 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, + 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, + 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, + 0x69, 0x6e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, + 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, + 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, + 0x7a, 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, + 0x5d, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, + 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, + 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, + 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, + 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, + 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gen/go/keyexchange/keyexchange.pb.go b/gen/go/keyexchange/v1/keyexchange.pb.go similarity index 50% rename from gen/go/keyexchange/keyexchange.pb.go rename to gen/go/keyexchange/v1/keyexchange.pb.go index 9b2ee2a4..b82a8cec 100644 --- a/gen/go/keyexchange/keyexchange.pb.go +++ b/gen/go/keyexchange/v1/keyexchange.pb.go @@ -2,9 +2,9 @@ // versions: // protoc-gen-go v1.31.0 // protoc (unknown) -// source: keyexchange/keyexchange.proto +// source: keyexchange/v1/keyexchange.proto -package keyexchange +package v1 import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -33,7 +33,7 @@ type EncryptedKeysMessage struct { func (x *EncryptedKeysMessage) Reset() { *x = EncryptedKeysMessage{} if protoimpl.UnsafeEnabled { - mi := &file_keyexchange_keyexchange_proto_msgTypes[0] + mi := &file_keyexchange_v1_keyexchange_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -46,7 +46,7 @@ func (x *EncryptedKeysMessage) String() string { func (*EncryptedKeysMessage) ProtoMessage() {} func (x *EncryptedKeysMessage) ProtoReflect() protoreflect.Message { - mi := &file_keyexchange_keyexchange_proto_msgTypes[0] + mi := &file_keyexchange_v1_keyexchange_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -59,7 +59,7 @@ func (x *EncryptedKeysMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use EncryptedKeysMessage.ProtoReflect.Descriptor instead. func (*EncryptedKeysMessage) Descriptor() ([]byte, []int) { - return file_keyexchange_keyexchange_proto_rawDescGZIP(), []int{0} + return file_keyexchange_v1_keyexchange_proto_rawDescGZIP(), []int{0} } func (x *EncryptedKeysMessage) GetEncryptedKeys() [][]byte { @@ -89,7 +89,7 @@ type EKMWithSignature struct { func (x *EKMWithSignature) Reset() { *x = EKMWithSignature{} if protoimpl.UnsafeEnabled { - mi := &file_keyexchange_keyexchange_proto_msgTypes[1] + mi := &file_keyexchange_v1_keyexchange_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -102,7 +102,7 @@ func (x *EKMWithSignature) String() string { func (*EKMWithSignature) ProtoMessage() {} func (x *EKMWithSignature) ProtoReflect() protoreflect.Message { - mi := &file_keyexchange_keyexchange_proto_msgTypes[1] + mi := &file_keyexchange_v1_keyexchange_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -115,7 +115,7 @@ func (x *EKMWithSignature) ProtoReflect() protoreflect.Message { // Deprecated: Use EKMWithSignature.ProtoReflect.Descriptor instead. func (*EKMWithSignature) Descriptor() ([]byte, []int) { - return file_keyexchange_keyexchange_proto_rawDescGZIP(), []int{1} + return file_keyexchange_v1_keyexchange_proto_rawDescGZIP(), []int{1} } func (x *EKMWithSignature) GetMessage() []byte { @@ -132,55 +132,55 @@ func (x *EKMWithSignature) GetSignature() []byte { return nil } -var File_keyexchange_keyexchange_proto protoreflect.FileDescriptor - -var file_keyexchange_keyexchange_proto_rawDesc = []byte{ - 0x0a, 0x1d, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2f, 0x6b, 0x65, - 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x0b, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x68, 0x0a, 0x14, - 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, - 0x64, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x45, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4a, 0x0a, 0x10, 0x45, 0x4b, 0x4d, 0x57, 0x69, 0x74, - 0x68, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x42, 0xa8, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6b, 0x65, 0x79, 0x65, 0x78, - 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x10, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0xa2, 0x02, 0x03, 0x4b, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x4b, 0x65, 0x79, 0x65, - 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xca, 0x02, 0x0b, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0xe2, 0x02, 0x17, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x0b, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, +var File_keyexchange_v1_keyexchange_proto protoreflect.FileDescriptor + +var file_keyexchange_v1_keyexchange_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2f, 0x76, 0x31, + 0x2f, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0b, 0x6b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, + 0x68, 0x0a, 0x14, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0d, + 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x2a, 0x0a, + 0x10, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x4a, 0x0a, 0x10, 0x45, 0x4b, 0x4d, + 0x57, 0x69, 0x74, 0x68, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0xab, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6b, 0x65, + 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x10, 0x4b, 0x65, 0x79, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x6b, 0x65, 0x79, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2f, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4b, 0x58, 0x58, 0xaa, + 0x02, 0x0b, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xca, 0x02, 0x0b, + 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xe2, 0x02, 0x17, 0x4b, 0x65, + 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0b, 0x4b, 0x65, 0x79, 0x65, 0x78, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_keyexchange_keyexchange_proto_rawDescOnce sync.Once - file_keyexchange_keyexchange_proto_rawDescData = file_keyexchange_keyexchange_proto_rawDesc + file_keyexchange_v1_keyexchange_proto_rawDescOnce sync.Once + file_keyexchange_v1_keyexchange_proto_rawDescData = file_keyexchange_v1_keyexchange_proto_rawDesc ) -func file_keyexchange_keyexchange_proto_rawDescGZIP() []byte { - file_keyexchange_keyexchange_proto_rawDescOnce.Do(func() { - file_keyexchange_keyexchange_proto_rawDescData = protoimpl.X.CompressGZIP(file_keyexchange_keyexchange_proto_rawDescData) +func file_keyexchange_v1_keyexchange_proto_rawDescGZIP() []byte { + file_keyexchange_v1_keyexchange_proto_rawDescOnce.Do(func() { + file_keyexchange_v1_keyexchange_proto_rawDescData = protoimpl.X.CompressGZIP(file_keyexchange_v1_keyexchange_proto_rawDescData) }) - return file_keyexchange_keyexchange_proto_rawDescData + return file_keyexchange_v1_keyexchange_proto_rawDescData } -var file_keyexchange_keyexchange_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_keyexchange_keyexchange_proto_goTypes = []interface{}{ +var file_keyexchange_v1_keyexchange_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_keyexchange_v1_keyexchange_proto_goTypes = []interface{}{ (*EncryptedKeysMessage)(nil), // 0: keyexchange.EncryptedKeysMessage (*EKMWithSignature)(nil), // 1: keyexchange.EKMWithSignature } -var file_keyexchange_keyexchange_proto_depIdxs = []int32{ +var file_keyexchange_v1_keyexchange_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name @@ -188,13 +188,13 @@ var file_keyexchange_keyexchange_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_keyexchange_keyexchange_proto_init() } -func file_keyexchange_keyexchange_proto_init() { - if File_keyexchange_keyexchange_proto != nil { +func init() { file_keyexchange_v1_keyexchange_proto_init() } +func file_keyexchange_v1_keyexchange_proto_init() { + if File_keyexchange_v1_keyexchange_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_keyexchange_keyexchange_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_keyexchange_v1_keyexchange_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EncryptedKeysMessage); i { case 0: return &v.state @@ -206,7 +206,7 @@ func file_keyexchange_keyexchange_proto_init() { return nil } } - file_keyexchange_keyexchange_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_keyexchange_v1_keyexchange_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EKMWithSignature); i { case 0: return &v.state @@ -223,18 +223,18 @@ func file_keyexchange_keyexchange_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_keyexchange_keyexchange_proto_rawDesc, + RawDescriptor: file_keyexchange_v1_keyexchange_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, - GoTypes: file_keyexchange_keyexchange_proto_goTypes, - DependencyIndexes: file_keyexchange_keyexchange_proto_depIdxs, - MessageInfos: file_keyexchange_keyexchange_proto_msgTypes, + GoTypes: file_keyexchange_v1_keyexchange_proto_goTypes, + DependencyIndexes: file_keyexchange_v1_keyexchange_proto_depIdxs, + MessageInfos: file_keyexchange_v1_keyexchange_proto_msgTypes, }.Build() - File_keyexchange_keyexchange_proto = out.File - file_keyexchange_keyexchange_proto_rawDesc = nil - file_keyexchange_keyexchange_proto_goTypes = nil - file_keyexchange_keyexchange_proto_depIdxs = nil + File_keyexchange_v1_keyexchange_proto = out.File + file_keyexchange_v1_keyexchange_proto_rawDesc = nil + file_keyexchange_v1_keyexchange_proto_goTypes = nil + file_keyexchange_v1_keyexchange_proto_depIdxs = nil } diff --git a/pkg/keyexchange/keyexchange.go b/pkg/keyexchange/keyexchange.go index b346a42e..fce96c17 100644 --- a/pkg/keyexchange/keyexchange.go +++ b/pkg/keyexchange/keyexchange.go @@ -11,7 +11,7 @@ import ( "time" "github.com/ethereum/go-ethereum/crypto/ecies" - keyexchangepb "github.com/primevprotocol/mev-commit/gen/go/keyexchange" + keyexchangepb "github.com/primevprotocol/mev-commit/gen/go/keyexchange/v1" "github.com/primevprotocol/mev-commit/pkg/keykeeper" "github.com/primevprotocol/mev-commit/pkg/p2p" "github.com/primevprotocol/mev-commit/pkg/signer" @@ -196,7 +196,7 @@ func (ke *KeyExchange) handleTimestampMessage(ctx context.Context, peer p2p.Peer } ke.keyKeeper.(*keykeeper.ProviderKeyKeeper).SetAESKey(peer.EthAddress, aesKey) - + ke.logger.Info("successfully processed timestamp message", "peer", peer.EthAddress, "key", aesKey) return nil diff --git a/rpc/bidderapi/v1/bidderapi.proto b/rpc/bidderapi/v1/bidderapi.proto index 8fdb10b3..fa553a11 100644 --- a/rpc/bidderapi/v1/bidderapi.proto +++ b/rpc/bidderapi/v1/bidderapi.proto @@ -65,7 +65,7 @@ message PrepayRequest { }, (buf.validate.field).cel = { id: "amount", message: "amount must be a valid integer.", - expression: "this.matches('^[0-9]+$') && uint(this) > 0" + expression: "this.matches('^[0-9]+$')" }]; }; From c835490ceccc089767224b356c8c42249874892b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Sat, 13 Apr 2024 19:39:47 +0200 Subject: [PATCH 43/85] commented prepay test --- pkg/rpc/bidder/service_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 36107ec3..33461d6d 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -213,18 +213,18 @@ func TestAllowanceHandling(t *testing.T) { } for _, tc := range []testCase{ - { - amount: "", - err: "amount must be a valid integer", - }, - { - amount: "0000000000000000000", - err: "amount must be a valid integer", - }, - { - amount: "asdf", - err: "amount must be a valid integer", - }, + // { + // amount: "", + // err: "amount must be a valid integer", + // }, + // { + // amount: "0000000000000000000", + // err: "amount must be a valid integer", + // }, + // { + // amount: "asdf", + // err: "amount must be a valid integer", + // }, { amount: "1000000000000000000", err: "", From 4574dd7a3c15d1537d63a87aa61d22f012e39ef2 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 11:17:19 +0200 Subject: [PATCH 44/85] updated bidder_registry event parsing --- pkg/contracts/bidder_registry/bidder_registry.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 451d12ac..ebe41ee1 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -83,12 +83,15 @@ func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *bi } var bidderRegistered struct { - Bidder string + Bidder common.Address PrepaidAmount *big.Int WindowNumber *big.Int } for _, log := range receipt.Logs { - r.logger.Info("bidder registry log", "logData", log.Data) + if len(log.Topics) > 1 { + bidderRegistered.Bidder = common.HexToAddress(log.Topics[1].Hex()) + } + err := r.bidderRegistryABI.UnpackIntoInterface(&bidderRegistered, "BidderRegistered", log.Data) if err != nil { r.logger.Debug("Failed to unpack event", "err", err) From a7b40d001ce208f235a41ef517cd05f52ee63c8c Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 14:20:09 +0200 Subject: [PATCH 45/85] changed type of encryptedCommitmentIndex from bytes to bytes32 for SC call --- pkg/contracts/preconf/preconf.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index d79f29cd..c1360a19 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -121,9 +121,13 @@ func (p *preconfContract) OpenCommitment( sharedSecretKey []byte, ) (common.Hash, error) { bidAmt, _ := new(big.Int).SetString(bid, 10) + var eciBytes [32]byte + + copy(eciBytes[:], encryptedCommitmentIndex) + callData, err := p.preconfABI.Pack( "openCommitment", - encryptedCommitmentIndex, + eciBytes, bidAmt, big.NewInt(blockNumber), txnHash, From 1ad227a2e9da75c0b5045d243edfcd8900a1ef6f Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 14:20:43 +0200 Subject: [PATCH 46/85] changes spaces --- pkg/contracts/preconf/preconf.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index c1360a19..328b8c93 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -121,8 +121,8 @@ func (p *preconfContract) OpenCommitment( sharedSecretKey []byte, ) (common.Hash, error) { bidAmt, _ := new(big.Int).SetString(bid, 10) + var eciBytes [32]byte - copy(eciBytes[:], encryptedCommitmentIndex) callData, err := p.preconfABI.Pack( From 7b426edbd599e7255a9afe9941604b81dea2dc34 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 15:13:43 +0200 Subject: [PATCH 47/85] openCommitment return txHash --- pkg/contracts/preconf/preconf.go | 12 ++++++------ pkg/preconfirmation/preconfirmation.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 328b8c93..dfdd9c72 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -128,11 +128,11 @@ func (p *preconfContract) OpenCommitment( callData, err := p.preconfABI.Pack( "openCommitment", eciBytes, - bidAmt, - big.NewInt(blockNumber), + bidAmt.Uint64(), + big.NewInt(blockNumber).Uint64(), txnHash, - big.NewInt(decayStartTimeStamp), - big.NewInt(decayEndTimeStamp), + big.NewInt(decayStartTimeStamp).Uint64(), + big.NewInt(decayEndTimeStamp).Uint64(), bidSignature, commitmentSignature, sharedSecretKey, @@ -142,7 +142,7 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } - _, err = p.client.Send(ctx, &evmclient.TxRequest{ + txHash, err := p.client.Send(ctx, &evmclient.TxRequest{ To: &p.preconfContractAddr, CallData: callData, }) @@ -150,5 +150,5 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } - return common.Hash{}, fmt.Errorf("commitmentIndex not found in transaction receipt") + return txHash, nil } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index a79f5fc0..d18ce074 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -352,7 +352,7 @@ func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event block p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) // todo: for provider check if winner == providerAddress, for bidder if committerAddress for _, commitment := range p.commitmentByBlockNumber[event.BlockNumber.Int64()] { - _, err := p.commitmentDA.OpenCommitment( + txHash, err := p.commitmentDA.OpenCommitment( ctx, commitment.EncryptedPreConfirmation.CommitmentIndex, commitment.PreConfirmation.Bid.BidAmount, @@ -368,7 +368,7 @@ func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event block p.logger.Error("Failed to open commitment", "error", err) continue } else { - p.logger.Info("Opened commitment", "txHash", commitment.PreConfirmation.Bid.TxHash) + p.logger.Info("Opened commitment", "txHash", txHash) } } delete(p.commitmentByBlockNumber, event.BlockNumber.Int64()) From bd80a56c0ea101907df3c45db913e5a24ab6398f Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 15:17:14 +0200 Subject: [PATCH 48/85] added waitReceipt for OpenCommitment --- pkg/contracts/preconf/preconf.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index dfdd9c72..2a2ae100 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -150,5 +150,12 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } + receipt, err := p.client.WaitForReceipt(ctx, txHash) + if err != nil { + return common.Hash{}, err // Updated to return common.Hash{} + } + + p.logger.Info("preconf contract openCommitment successful", "txHash", txHash, "receiptStatus", receipt.Status) + return txHash, nil } From ab67608617b9dfa0436b18b7f101aa1a980a039e Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 15:19:38 +0200 Subject: [PATCH 49/85] fixed wrong import --- pkg/contracts/preconf/preconf.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 2a2ae100..08c24435 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -2,7 +2,6 @@ package preconfcontract import ( "context" - "fmt" "log/slog" "math/big" "strings" From fdafe6e67d3ec13c7e6c7078799c959cfb60029d Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 17:10:17 +0200 Subject: [PATCH 50/85] fixed incorrect bid hash --- pkg/signer/preconfencryptor/encryptor.go | 2 +- pkg/signer/preconfencryptor/encryptor_test.go | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index b71762d7..a9a46ed7 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -316,7 +316,7 @@ func GetPreConfirmationHash(c *preconfpb.PreConfirmation) ([]byte, error) { // EIP712_MESSAGE_TYPEHASH eip712MessageTypeHash := crypto.Keccak256Hash( - []byte("PreConfCommitment(string txnHash,uint64 bid,uint64 blockNumber,uint64 decayStartTimeStamp,uint64 decayEndTimeStamp,string bidHash,string signature,string sharedSecret)"), + []byte("PreConfCommitment(string txnHash,uint64 bid,uint64 blockNumber,uint64 decayStartTimeStamp,uint64 decayEndTimeStamp,bytes32 bidHash,string signature,string sharedSecretKey)"), ) // Convert the txnHash to a byte array and hash it diff --git a/pkg/signer/preconfencryptor/encryptor_test.go b/pkg/signer/preconfencryptor/encryptor_test.go index b6a9ea66..5a33cad1 100644 --- a/pkg/signer/preconfencryptor/encryptor_test.go +++ b/pkg/signer/preconfencryptor/encryptor_test.go @@ -119,10 +119,10 @@ func TestHashing(t *testing.T) { t.Run("bid", func(t *testing.T) { bid := &preconfpb.Bid{ TxHash: "0xkartik", - BidAmount: "200", - BlockNumber: 3000, + BidAmount: "2", + BlockNumber: 2, DecayStartTimestamp: 10, - DecayEndTimestamp: 30, + DecayEndTimestamp: 20, } hash, err := preconfencryptor.GetBidHash(bid) @@ -132,7 +132,7 @@ func TestHashing(t *testing.T) { hashStr := hex.EncodeToString(hash) // This hash is sourced from the solidity contract to ensure interoperability - expHash := "a837b0c680d4b9b11011ac6225670498d845e65f1dc340b00694d74a6ca0a049" + expHash := "a0327970258c49b922969af74d60299a648c50f69a2d98d6ab43f32f64ac2100" if hashStr != expHash { t.Fatalf("hash mismatch: %s != %s", hashStr, expHash) } @@ -161,8 +161,11 @@ func TestHashing(t *testing.T) { Signature: bidSigBytes, } + sharedSecretBytes := []byte("0xsecret") + preConfirmation := &preconfpb.PreConfirmation{ - Bid: bid, + Bid: bid, + SharedSecret: sharedSecretBytes, } hash, err := preconfencryptor.GetPreConfirmationHash(preConfirmation) @@ -171,7 +174,7 @@ func TestHashing(t *testing.T) { } hashStr := hex.EncodeToString(hash) - expHash := "7492710e0487466ee0cd9f795ce1bb72e1b17ebe6d7b0bb729f2a65a8e756f9b" + expHash := "65618f8f9e46b8f0790c621ca2989cfe4c949594a4a3a81261baa682e8883840" if hashStr != expHash { t.Fatalf("hash mismatch: %s != %s", hashStr, expHash) } From 6e0b1e698736b0a6080c5eac47ff2707493d3021 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 19:05:43 +0200 Subject: [PATCH 51/85] added missing fields for the provider preconf --- pkg/contracts/preconf/preconf.go | 2 +- pkg/signer/preconfencryptor/encryptor.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 08c24435..76990ca5 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -151,7 +151,7 @@ func (p *preconfContract) OpenCommitment( receipt, err := p.client.WaitForReceipt(ctx, txHash) if err != nil { - return common.Hash{}, err // Updated to return common.Hash{} + return common.Hash{}, err } p.logger.Info("preconf contract openCommitment successful", "txHash", txHash, "receiptStatus", receipt.Status) diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index a9a46ed7..b1987a34 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -122,8 +122,11 @@ func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*prec } preConfirmation := &preconfpb.PreConfirmation{ - Bid: bid, - SharedSecret: sharedSecredProviderSk, + Bid: bid, + Digest: bid.Digest, + Signature: bid.Signature, + SharedSecret: sharedSecredProviderSk, + ProviderAddress: providerKK.GetAddress().Bytes(), } preConfirmationHash, err := GetPreConfirmationHash(preConfirmation) From 9e16af32864214b49a4d8ab32e43677258b2ddea Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 15 Apr 2024 19:12:32 +0200 Subject: [PATCH 52/85] fixed preconf digest and sig --- pkg/signer/preconfencryptor/encryptor.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/signer/preconfencryptor/encryptor.go b/pkg/signer/preconfencryptor/encryptor.go index b1987a34..e88a27a9 100644 --- a/pkg/signer/preconfencryptor/encryptor.go +++ b/pkg/signer/preconfencryptor/encryptor.go @@ -123,8 +123,6 @@ func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*prec preConfirmation := &preconfpb.PreConfirmation{ Bid: bid, - Digest: bid.Digest, - Signature: bid.Signature, SharedSecret: sharedSecredProviderSk, ProviderAddress: providerKK.GetAddress().Bytes(), } @@ -143,6 +141,9 @@ func (e *encryptor) ConstructEncryptedPreConfirmation(bid *preconfpb.Bid) (*prec sig[64] += 27 // Transform V from 0/1 to 27/28 } + preConfirmation.Digest = preConfirmationHash + preConfirmation.Signature = sig + return preConfirmation, &preconfpb.EncryptedPreConfirmation{ Commitment: preConfirmationHash, Signature: sig, From c8ead5531ff5e28797558abc3e5a3c3e4e10f7f0 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 16 Apr 2024 14:52:46 +0200 Subject: [PATCH 53/85] fixed bidder init --- pkg/contracts/preconf/preconf.go | 7 ++++++- pkg/node/node.go | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 76990ca5..aea337c4 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -2,6 +2,7 @@ package preconfcontract import ( "context" + "fmt" "log/slog" "math/big" "strings" @@ -119,7 +120,11 @@ func (p *preconfContract) OpenCommitment( commitmentSignature []byte, sharedSecretKey []byte, ) (common.Hash, error) { - bidAmt, _ := new(big.Int).SetString(bid, 10) + bidAmt, ok := new(big.Int).SetString(bid, 10) + if !ok { + p.logger.Error("Error converting bid to big.Int", "bid", bid) + return common.Hash{}, fmt.Errorf("error converting bid to big.Int, bid: %s", bid) + } var eciBytes [32]byte copy(eciBytes[:], encryptedCommitmentIndex) diff --git a/pkg/node/node.go b/pkg/node/node.go index f7fcabaa..60bb67bb 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -237,13 +237,13 @@ func NewNode(opts *Options) (*Node, error) { srv.RegisterMetricsCollectors(providerAPI.Metrics()...) opts.Logger.Info("registered provider api metrics") preconfContractAddr := common.HexToAddress(opts.PreconfContract) - commitmentDA = preconfcontract.New( preconfContractAddr, evmClient, opts.Logger.With("component", "preconfcontract"), ) opts.Logger.Info("registered preconf contract") + preconfProto := preconfirmation.New( keyKeeper.GetAddress(), topo, From 5d5c0c03f5ed9105fd0ffad2712af99148447473 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 16 Apr 2024 21:00:02 +0200 Subject: [PATCH 54/85] added event handler from oracle --- pkg/events/events.go | 283 ++++++++++++++++++++ pkg/events/events_test.go | 277 +++++++++++++++++++ pkg/evmclient/evmclient.go | 5 + pkg/evmclient/mock/mock.go | 20 +- pkg/node/node.go | 78 +++++- pkg/preconfirmation/preconfirmation.go | 130 +++++---- pkg/preconfirmation/preconfirmation_test.go | 46 +++- pkg/store/store.go | 34 +++ 8 files changed, 797 insertions(+), 76 deletions(-) create mode 100644 pkg/events/events.go create mode 100644 pkg/events/events_test.go create mode 100644 pkg/store/store.go diff --git a/pkg/events/events.go b/pkg/events/events.go new file mode 100644 index 00000000..9823e4f3 --- /dev/null +++ b/pkg/events/events.go @@ -0,0 +1,283 @@ +package events + +import ( + "bytes" + "context" + "fmt" + "log/slog" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// EVMClient is an interface for interacting with an Ethereum client for event subscription. +type EVMClient interface { + BlockNumber(ctx context.Context) (uint64, error) + FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) +} + +// ProgressStore is an interface for storing the last block number processed by the event listener. +type ProgressStore interface { + LastBlock() (uint64, error) + SetLastBlock(block uint64) error +} + +// EventManager is an interface for subscribing to events. This interface is a stand-in for +// the generic event handlers that are used to subscribe to events. +type EventHandler interface { + EventName() string + Handle(types.Log) error + SetTopicAndContract(topic common.Hash, contract *abi.ABI) + Topic() common.Hash +} + +// eventHandler is a generic implementation of EventHandler for type-safe event handling. +type eventHandler[T any] struct { + handler func(*T) error + name string + topicID common.Hash + contract *abi.ABI +} + +// NewEventHandler creates a new EventHandler for the given event name from the known contracts. +// The handler function is called when an event is received. The handler function should +// return an error if the event is a fatal error, otherwise it should return nil. The event +// handler should be used to subscribe to events using the EventManager interface. +func NewEventHandler[T any](name string, handler func(*T) error) EventHandler { + return &eventHandler[T]{ + handler: handler, + name: name, + } +} + +func (h *eventHandler[T]) EventName() string { + return h.name +} + +func (h *eventHandler[T]) SetTopicAndContract(topic common.Hash, contract *abi.ABI) { + h.topicID = topic + h.contract = contract +} + +func (h *eventHandler[T]) Handle(log types.Log) error { + if h.contract == nil { + return fmt.Errorf("contract not set") + } + + if !bytes.Equal(log.Topics[0].Bytes(), h.topicID.Bytes()) { + return nil + } + + obj := new(T) + + if len(log.Data) > 0 { + err := h.contract.UnpackIntoInterface(obj, h.name, log.Data) + if err != nil { + return err + } + } + + var indexed abi.Arguments + for _, arg := range h.contract.Events[h.name].Inputs { + if arg.Indexed { + indexed = append(indexed, arg) + } + } + + if len(indexed) > 0 { + err := abi.ParseTopics(obj, indexed, log.Topics[1:]) + if err != nil { + return err + } + } + + return h.handler(obj) +} + +func (h *eventHandler[T]) Topic() common.Hash { + return h.topicID +} + +type EventManager interface { + Subscribe(event EventHandler) (Subscription, error) +} + +type Subscription interface { + Unsubscribe() + Err() <-chan error +} + +type Listener struct { + logger *slog.Logger + evmClient EVMClient + progressStore ProgressStore + subMu sync.RWMutex + subscribers map[common.Hash][]*subscription + contracts map[common.Address]*abi.ABI +} + +func NewListener( + logger *slog.Logger, + evmClient EVMClient, + progressStore ProgressStore, + contracts map[common.Address]*abi.ABI, +) *Listener { + return &Listener{ + logger: logger, + evmClient: evmClient, + progressStore: progressStore, + subscribers: make(map[common.Hash][]*subscription), + contracts: contracts, + } +} + +type subscription struct { + event EventHandler + unsub func() + errCh chan error +} + +func (s *subscription) Unsubscribe() { + s.unsub() +} + +func (s *subscription) Err() <-chan error { + return s.errCh +} + +func (l *Listener) Subscribe(event EventHandler) (Subscription, error) { + found := false + for _, c := range l.contracts { + for _, e := range c.Events { + if e.Name == event.EventName() { + event.SetTopicAndContract(e.ID, c) + found = true + break + } + } + } + + if !found { + return nil, fmt.Errorf("event not found") + } + + l.subMu.Lock() + defer l.subMu.Unlock() + + sub := &subscription{ + event: event, + errCh: make(chan error), + unsub: func() { l.unsubscribe(event) }, + } + + l.subscribers[event.Topic()] = append(l.subscribers[event.Topic()], sub) + + return sub, nil +} + +func (l *Listener) unsubscribe(event EventHandler) { + l.subMu.Lock() + defer l.subMu.Unlock() + + events := l.subscribers[event.Topic()] + for i, e := range events { + if e.event == event { + events = append(events[:i], events[i+1:]...) + break + } + } + + l.subscribers[event.Topic()] = events +} + +func (l *Listener) publishLogEvent(ctx context.Context, log types.Log) { + l.subMu.RLock() + defer l.subMu.RUnlock() + + events := l.subscribers[log.Topics[0]] + for _, event := range events { + ev := event + go func() { + if err := ev.event.Handle(log); err != nil { + l.logger.Error("failed to handle log", "error", err) + select { + case ev.errCh <- err: + case <-ctx.Done(): + } + } + }() + } +} + +func (l *Listener) Start(ctx context.Context) <-chan struct{} { + doneChan := make(chan struct{}) + + if len(l.contracts) == 0 { + close(doneChan) + return doneChan + } + + go func() { + defer close(doneChan) + + lastBlock, err := l.progressStore.LastBlock() + if err != nil { + l.logger.Error("failed to get last block", "error", err) + return + } + + contracts := make([]common.Address, 0, len(l.contracts)) + for addr := range l.contracts { + contracts = append(contracts, addr) + } + + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + blockNumber, err := l.evmClient.BlockNumber(ctx) + if err != nil { + l.logger.Error("failed to get block number", "error", err) + return + } + + if blockNumber > lastBlock { + q := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(lastBlock + 1)), + ToBlock: big.NewInt(int64(blockNumber)), + Addresses: contracts, + } + + logs, err := l.evmClient.FilterLogs(ctx, q) + if err != nil { + l.logger.Error("failed to filter logs", "error", err) + return + } + + for _, logMsg := range logs { + // process log + l.publishLogEvent(ctx, logMsg) + } + + if err := l.progressStore.SetLastBlock(blockNumber); err != nil { + l.logger.Error("failed to set last block", "error", err) + return + } + l.logger.Info("processed logs", "from", lastBlock+1, "to", blockNumber, "count", len(logs)) + lastBlock = blockNumber + } + } + } + }() + + return doneChan +} diff --git a/pkg/events/events_test.go b/pkg/events/events_test.go new file mode 100644 index 00000000..5f884ded --- /dev/null +++ b/pkg/events/events_test.go @@ -0,0 +1,277 @@ +package events_test + +import ( + "context" + "fmt" + "io" + "log/slog" + "math/big" + "strings" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + bidderregistry "github.com/primevprotocol/contracts-abi/clients/BidderRegistry" + "github.com/primevprotocol/mev-commit/pkg/events" +) + +func TestEventHandler(t *testing.T) { + t.Parallel() + + b := bidderregistry.BidderregistryBidderRegistered{ + Bidder: common.HexToAddress("0xabcd"), + PrepaidAmount: big.NewInt(1000), + WindowNumber: big.NewInt(99), + } + + evtHdlr := events.NewEventHandler( + "BidderRegistered", + func(ev *bidderregistry.BidderregistryBidderRegistered) error { + if ev.Bidder.Hex() != b.Bidder.Hex() { + return fmt.Errorf("expected bidder %s, got %s", b.Bidder.Hex(), ev.Bidder.Hex()) + } + if ev.PrepaidAmount.Cmp(b.PrepaidAmount) != 0 { + return fmt.Errorf("expected prepaid amount %d, got %d", b.PrepaidAmount, ev.PrepaidAmount) + } + if ev.WindowNumber.Cmp(b.WindowNumber) != 0 { + return fmt.Errorf("expected window number %d, got %d", b.WindowNumber, ev.WindowNumber) + } + return nil + }, + ) + + bidderABI, err := abi.JSON(strings.NewReader(bidderregistry.BidderregistryABI)) + if err != nil { + t.Fatal(err) + } + + event := bidderABI.Events["BidderRegistered"] + + evtHdlr.SetTopicAndContract(event.ID, &bidderABI) + + if evtHdlr.Topic().Cmp(event.ID) != 0 { + t.Fatalf("expected topic %s, got %s", event.ID, evtHdlr.Topic()) + } + + if evtHdlr.EventName() != "BidderRegistered" { + t.Fatalf("expected event name BidderRegistered, got %s", evtHdlr.EventName()) + } + + buf, err := event.Inputs.NonIndexed().Pack( + b.PrepaidAmount, + b.WindowNumber, + ) + if err != nil { + t.Fatal(err) + } + + bidder := common.HexToHash(b.Bidder.Hex()) + + // Creating a Log object + testLog := types.Log{ + Topics: []common.Hash{ + event.ID, // The first topic is the hash of the event signature + bidder, // The next topics are the indexed event parameters + }, + Data: buf, + } + + if err := evtHdlr.Handle(testLog); err != nil { + t.Fatal(err) + } +} + +func TestEventManager(t *testing.T) { + t.Parallel() + + bidders := []bidderregistry.BidderregistryBidderRegistered{ + { + Bidder: common.HexToAddress("0xabcd"), + PrepaidAmount: big.NewInt(1000), + WindowNumber: big.NewInt(99), + }, + { + Bidder: common.HexToAddress("0xcdef"), + PrepaidAmount: big.NewInt(2000), + WindowNumber: big.NewInt(100), + }, + } + + count := 0 + + handlerTriggered1 := make(chan struct{}) + handlerTriggered2 := make(chan struct{}) + + evtHdlr := events.NewEventHandler( + "BidderRegistered", + func(ev *bidderregistry.BidderregistryBidderRegistered) error { + if count >= len(bidders) { + return fmt.Errorf("unexpected event") + } + if ev.Bidder.Hex() != bidders[count].Bidder.Hex() { + return fmt.Errorf("expected bidder %s, got %s", bidders[count].Bidder.Hex(), ev.Bidder.Hex()) + } + if ev.PrepaidAmount.Cmp(bidders[count].PrepaidAmount) != 0 { + return fmt.Errorf("expected prepaid amount %d, got %d", bidders[count].PrepaidAmount, ev.PrepaidAmount) + } + if ev.WindowNumber.Cmp(bidders[count].WindowNumber) != 0 { + return fmt.Errorf("expected window number %d, got %d", bidders[count].WindowNumber, ev.WindowNumber) + } + count++ + if count == 1 { + close(handlerTriggered1) + } else { + close(handlerTriggered2) + } + return nil + }, + ) + + bidderABI, err := abi.JSON(strings.NewReader(bidderregistry.BidderregistryABI)) + if err != nil { + t.Fatal(err) + } + + data1, err := bidderABI.Events["BidderRegistered"].Inputs.NonIndexed().Pack( + bidders[0].PrepaidAmount, + bidders[0].WindowNumber, + ) + if err != nil { + t.Fatal(err) + } + + data2, err := bidderABI.Events["BidderRegistered"].Inputs.NonIndexed().Pack( + bidders[1].PrepaidAmount, + bidders[1].WindowNumber, + ) + if err != nil { + t.Fatal(err) + } + + evmClient := &testEVMClient{ + logs: []types.Log{ + { + Topics: []common.Hash{ + bidderABI.Events["BidderRegistered"].ID, + common.HexToHash(bidders[0].Bidder.Hex()), + }, + Data: data1, + BlockNumber: 1, + }, + { + Topics: []common.Hash{ + bidderABI.Events["BidderRegistered"].ID, + common.HexToHash(bidders[1].Bidder.Hex()), + }, + Data: data2, + BlockNumber: 2, + }, + }, + } + + store := &testStore{} + + contracts := map[common.Address]*abi.ABI{ + common.HexToAddress("0xabcd"): &bidderABI, + } + + evtMgr := events.NewListener( + slog.New(slog.NewTextHandler(io.Discard, nil)), + evmClient, + store, + contracts, + ) + + ctx, cancel := context.WithCancel(context.Background()) + done := evtMgr.Start(ctx) + + sub, err := evtMgr.Subscribe(evtHdlr) + if err != nil { + t.Fatal(err) + } + + defer sub.Unsubscribe() + + evmClient.SetBlockNumber(1) + + select { + case <-handlerTriggered1: + case <-time.After(5 * time.Second): + t.Fatal("timed out waiting for handler to be triggered") + } + + evmClient.SetBlockNumber(2) + select { + case <-handlerTriggered2: + case <-time.After(5 * time.Second): + t.Fatal("timed out waiting for handler to be triggered") + } + + if b, err := store.LastBlock(); err != nil || b != 2 { + t.Fatalf("expected block number 1, got %d", store.blockNumber) + } + + cancel() + <-done +} + +type testEVMClient struct { + mu sync.Mutex + blockNum uint64 + logs []types.Log +} + +func (t *testEVMClient) SetBlockNumber(blockNum uint64) { + t.mu.Lock() + defer t.mu.Unlock() + + t.blockNum = blockNum +} + +func (t *testEVMClient) BlockNumber(context.Context) (uint64, error) { + t.mu.Lock() + defer t.mu.Unlock() + + return t.blockNum, nil +} + +func (t *testEVMClient) FilterLogs( + ctx context.Context, + q ethereum.FilterQuery, +) ([]types.Log, error) { + t.mu.Lock() + defer t.mu.Unlock() + + logs := make([]types.Log, 0, len(t.logs)) + for _, log := range t.logs { + if log.BlockNumber >= q.FromBlock.Uint64() && log.BlockNumber <= q.ToBlock.Uint64() { + logs = append(logs, log) + } + } + + return logs, nil +} + +type testStore struct { + mu sync.Mutex + blockNumber uint64 +} + +func (t *testStore) LastBlock() (uint64, error) { + t.mu.Lock() + defer t.mu.Unlock() + + return t.blockNumber, nil +} + +func (t *testStore) SetLastBlock(blockNumber uint64) error { + t.mu.Lock() + defer t.mu.Unlock() + + t.blockNumber = blockNumber + return nil +} diff --git a/pkg/evmclient/evmclient.go b/pkg/evmclient/evmclient.go index c33eec0b..71815946 100644 --- a/pkg/evmclient/evmclient.go +++ b/pkg/evmclient/evmclient.go @@ -45,6 +45,7 @@ type Interface interface { CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) + BlockNumber(ctx context.Context) (uint64, error) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) } @@ -394,6 +395,10 @@ func (c *EvmClient) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*t return c.ethClient.BlockByNumber(ctx, blockNumber) } +func (c *EvmClient) BlockNumber(ctx context.Context) (uint64, error) { + return c.ethClient.BlockNumber(ctx) +} + func (c *EvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { return c.ethClient.FilterLogs(ctx, query) } diff --git a/pkg/evmclient/mock/mock.go b/pkg/evmclient/mock/mock.go index 7d566054..c365260e 100644 --- a/pkg/evmclient/mock/mock.go +++ b/pkg/evmclient/mock/mock.go @@ -69,6 +69,14 @@ func WithBlockByNumber( } } +func WithBlockNumber( + f func(ctx context.Context) (uint64, error), +) Option { + return func(m *mockEvmClient) { + m.BlockNumberFunc = f + } +} + func WithFilterLogs( f func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error), ) Option { @@ -84,7 +92,15 @@ type mockEvmClient struct { CancelFunc func(ctx context.Context, txHash common.Hash) (common.Hash, error) SubscribeFilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) BlockByNumberFunc func(ctx context.Context, number *big.Int) (*types.Block, error) - FilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) + BlockNumberFunc func(ctx context.Context) (uint64, error) + FilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) +} + +func (m *mockEvmClient) BlockNumber(ctx context.Context) (uint64, error) { + if m.BlockNumberFunc == nil { + return 0, errors.New("not implemented") + } + return m.BlockNumberFunc(ctx) } func (m *mockEvmClient) Send( @@ -147,4 +163,4 @@ func (m *mockEvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQue return nil, errors.New("not implemented") } return m.FilterLogsFunc(ctx, query) -} \ No newline at end of file +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 60bb67bb..a170a3db 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -9,12 +9,16 @@ import ( "log/slog" "net" "net/http" + "strings" "time" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" + preconf "github.com/primevprotocol/contracts-abi/clients/PreConfCommitmentStore" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" @@ -25,6 +29,7 @@ import ( provider_registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/provider_registry" "github.com/primevprotocol/mev-commit/pkg/debugapi" "github.com/primevprotocol/mev-commit/pkg/discovery" + "github.com/primevprotocol/mev-commit/pkg/events" "github.com/primevprotocol/mev-commit/pkg/evmclient" "github.com/primevprotocol/mev-commit/pkg/keyexchange" "github.com/primevprotocol/mev-commit/pkg/keykeeper" @@ -36,6 +41,7 @@ import ( providerapi "github.com/primevprotocol/mev-commit/pkg/rpc/provider" "github.com/primevprotocol/mev-commit/pkg/signer" "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" + "github.com/primevprotocol/mev-commit/pkg/store" "github.com/primevprotocol/mev-commit/pkg/topology" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -70,6 +76,7 @@ type Options struct { } type Node struct { + waitClose func() closers []io.Closer } @@ -181,6 +188,11 @@ func NewNode(opts *Options) (*Node, error) { debugapi.RegisterAPI(srv, topo, p2pSvc, opts.Logger.With("component", "debugapi")) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var preconfProtoClosed <-chan struct{} + if opts.PeerType != p2p.PeerTypeBootnode.String() { lis, err := net.Listen("tcp", opts.RPCAddr) if err != nil { @@ -222,6 +234,21 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "blocktrackercontract"), ) + st := store.NewStore() + + contracts, err := getContractABIs(opts) + if err != nil { + opts.Logger.Error("failed to get contract ABIs", "error", err) + return nil, err + } + + evtMgr := events.NewListener( + opts.Logger.With("component", "events"), + evmClient, + st, + contracts, + ) + switch opts.PeerType { case p2p.PeerTypeProvider.String(): providerAPI := providerapi.NewService( @@ -253,10 +280,12 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, + evtMgr, opts.Logger.With("component", "preconfirmation_protocol"), ) opts.Logger.Info("registered preconfirmation protocol") - go preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) + + preconfProtoClosed = preconfProto.Start(ctx) // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) @@ -283,9 +312,12 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, blockTracker, + evtMgr, opts.Logger.With("component", "preconfirmation_protocol"), ) - go preconfProto.StartListeningToNewL1BlockEvents(context.Background(), preconfProto.HandleNewL1BlockEvent) + + preconfProtoClosed = preconfProto.Start(ctx) + srv.RegisterMetricsCollectors(preconfProto.Metrics()...) bidderAPI := bidderapi.NewService( @@ -372,8 +404,6 @@ func NewNode(opts *Options) (*Node, error) { } gatewayMux := runtime.NewServeMux() - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() switch opts.PeerType { case p2p.PeerTypeProvider.String(): err := providerapiv1.RegisterProviderHandler(ctx, gatewayMux, grpcConn) @@ -431,10 +461,50 @@ func NewNode(opts *Options) (*Node, error) { }() nd.closers = append(nd.closers, server) + nd.waitClose = func() { + cancel() + + closeChan := make(chan struct{}) + go func() { + defer close(closeChan) + + <-preconfProtoClosed + }() + + <-closeChan + } + return nd, nil } +func getContractABIs(opts *Options) (map[common.Address]*abi.ABI, error) { + abis := make(map[common.Address]*abi.ABI) + + btABI, err := abi.JSON(strings.NewReader(blocktracker.BlocktrackerABI)) + if err != nil { + return nil, err + } + abis[common.HexToAddress(opts.BlockTrackerContract)] = &btABI + + pcABI, err := abi.JSON(strings.NewReader(preconf.PreconfcommitmentstoreABI)) + if err != nil { + return nil, err + } + abis[common.HexToAddress(opts.PreconfContract)] = &pcABI + + return abis, nil +} + func (n *Node) Close() error { + workersClosed := make(chan struct{}) + go func() { + defer close(workersClosed) + + if n.waitClose != nil { + n.waitClose() + } + }() + var err error for _, c := range n.closers { err = errors.Join(err, c.Close()) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index d18ce074..19fa1031 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -3,6 +3,7 @@ package preconfirmation import ( "context" "errors" + "fmt" "log/slog" "math/big" "sync" @@ -13,9 +14,11 @@ import ( providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" + "github.com/primevprotocol/mev-commit/pkg/events" "github.com/primevprotocol/mev-commit/pkg/p2p" encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" "github.com/primevprotocol/mev-commit/pkg/topology" + "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -41,6 +44,7 @@ type Preconfirmation struct { processer BidProcessor commitmentDA preconfcontract.Interface blockTracker blocktrackercontract.Interface + evtMgr events.EventManager logger *slog.Logger metrics *metrics } @@ -66,6 +70,7 @@ func New( processor BidProcessor, commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, + evtMgr events.EventManager, logger *slog.Logger, ) *Preconfirmation { commitmentsByBlockNumber := make(map[int64][]*EncryptedPreConfirmationWithDecrypted) @@ -79,6 +84,7 @@ func New( processer: processor, commitmentDA: commitmentDA, blockTracker: blockTracker, + evtMgr: evtMgr, logger: logger, metrics: newMetrics(), } @@ -96,6 +102,25 @@ func (p *Preconfirmation) Streams() []p2p.StreamDesc { return []p2p.StreamDesc{p.bidStream()} } +func (p *Preconfirmation) Start(ctx context.Context) <-chan struct{} { + doneChan := make(chan struct{}) + + eg, egCtx := errgroup.WithContext(ctx) + + eg.Go(func() error { + return p.subscribeNewL1Block(egCtx) + }) + + go func() { + defer close(doneChan) + if err := eg.Wait(); err != nil { + p.logger.Error("failed to start preconfirmation", "error", err) + } + }() + + return doneChan +} + // SendBid is meant to be called by the bidder to construct and send bids to the provider. // It takes the txHash, the bid amount in wei and the maximum valid block number. // It waits for preConfirmations from all providers and then returns. @@ -299,77 +324,48 @@ func (p *Preconfirmation) handleBid( return nil } -func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { - ch := make(chan blocktrackercontract.NewL1BlockEvent) +func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { + ev := events.NewEventHandler( + "NewL1Block", + func(newL1Block *blocktrackercontract.NewL1BlockEvent) error { + p.logger.Info("New L1 Block event received", "blockNumber", newL1Block.BlockNumber, "winner", newL1Block.Winner, "window", newL1Block.Window) + // todo: for provider check if winner == providerAddress, for bidder if committerAddress + for _, commitment := range p.commitmentByBlockNumber[newL1Block.BlockNumber.Int64()] { + txHash, err := p.commitmentDA.OpenCommitment( + ctx, + commitment.EncryptedPreConfirmation.CommitmentIndex, + commitment.PreConfirmation.Bid.BidAmount, + commitment.PreConfirmation.Bid.BlockNumber, + commitment.PreConfirmation.Bid.TxHash, + commitment.PreConfirmation.Bid.DecayStartTimestamp, + commitment.PreConfirmation.Bid.DecayEndTimestamp, + commitment.PreConfirmation.Bid.Signature, + commitment.PreConfirmation.Signature, + commitment.PreConfirmation.SharedSecret, + ) + if err != nil { + // todo: retry mechanism? + p.logger.Error("failed to open commitment", "error", err) + continue + } else { + p.logger.Info("opened commitment", "txHash", txHash) + } + } + delete(p.commitmentByBlockNumber, newL1Block.BlockNumber.Int64()) + return nil + }, + ) - sub, err := p.blockTracker.SubscribeNewL1Block(ctx, ch) + sub, err := p.evtMgr.Subscribe(ev) if err != nil { - p.logger.Error("Failed to subscribe to NewL1Block events", "error", err) - return + return fmt.Errorf("failed to subscribe to NewL1Block event: %w", err) } defer sub.Unsubscribe() - for { - select { - case event := <-ch: - handler(ctx, event) - case err := <-sub.Err(): - p.logger.Error("Subscription error", "error", err) - return - case <-ctx.Done(): - p.logger.Info("Subscription context cancelled") - return - } - } -} - -// func (p *Preconfirmation) StartListeningToNewL1BlockEvents(ctx context.Context, handler func(context.Context, blocktrackercontract.NewL1BlockEvent)) { -// ch := make(chan blocktrackercontract.NewL1BlockEvent) - -// pollInterval := time.Second * 10 - -// go func() { -// err := p.blockTracker.PollNewL1BlockEvents(ctx, ch, pollInterval) -// if err != nil { -// p.logger.Error("Failed to poll NewL1Block events", "error", err) -// } -// }() - -// go func() { -// for { -// select { -// case event := <-ch: -// handler(ctx, event) -// case <-ctx.Done(): -// p.logger.Info("Polling context cancelled") -// return -// } -// } -// }() -// } - -func (p *Preconfirmation) HandleNewL1BlockEvent(ctx context.Context, event blocktrackercontract.NewL1BlockEvent) { - p.logger.Info("New L1 Block event received", "blockNumber", event.BlockNumber, "winner", event.Winner, "window", event.Window) - // todo: for provider check if winner == providerAddress, for bidder if committerAddress - for _, commitment := range p.commitmentByBlockNumber[event.BlockNumber.Int64()] { - txHash, err := p.commitmentDA.OpenCommitment( - ctx, - commitment.EncryptedPreConfirmation.CommitmentIndex, - commitment.PreConfirmation.Bid.BidAmount, - commitment.PreConfirmation.Bid.BlockNumber, - commitment.PreConfirmation.Bid.TxHash, - commitment.PreConfirmation.Bid.DecayStartTimestamp, - commitment.PreConfirmation.Bid.DecayEndTimestamp, - commitment.PreConfirmation.Bid.Signature, - commitment.PreConfirmation.Signature, - commitment.PreConfirmation.SharedSecret, - ) - if err != nil { - p.logger.Error("Failed to open commitment", "error", err) - continue - } else { - p.logger.Info("Opened commitment", "txHash", txHash) - } + select { + case <-ctx.Done(): + return nil + case err := <-sub.Err(): + return fmt.Errorf("subscription error: %w", err) } - delete(p.commitmentByBlockNumber, event.BlockNumber.Int64()) } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 0bc61db7..82a1ec00 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -5,19 +5,24 @@ import ( "crypto/ecdh" "crypto/elliptic" "crypto/rand" + "errors" "io" "log/slog" "math/big" "os" + "strings" "testing" "time" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" + "github.com/primevprotocol/mev-commit/pkg/events" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" @@ -161,9 +166,33 @@ func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, ev return nil, nil } -// func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { -// return nil -// } +type testEventManager struct { + btABI *abi.ABI + handler events.EventHandler + handlerSub chan struct{} + sub *testSub +} + +type testSub struct { + errC chan error +} + +func (t *testSub) Unsubscribe() {} + +func (t *testSub) Err() <-chan error { + return t.errC +} + +func (t *testEventManager) Subscribe(evt events.EventHandler) (events.Subscription, error) { + if evt.EventName() != "NewL1Block" { + return nil, errors.New("invalid event") + } + evt.SetTopicAndContract(t.btABI.Events["NewL1Block"].ID, t.btABI) + t.handler = evt + close(t.handlerSub) + + return t.sub, nil +} func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { t.Helper() @@ -245,6 +274,16 @@ func TestPreconfBidSubmission(t *testing.T) { preConfirmationSigner: common.HexToAddress("0x2"), } + btABI, err := abi.JSON(strings.NewReader(blocktracker.BlocktrackerABI)) + if err != nil { + t.Fatal(err) + } + eventManager := &testEventManager{ + btABI: &btABI, + sub: &testSub{errC: make(chan error)}, + handlerSub: make(chan struct{}), + } + p := preconfirmation.New( client.EthAddress, topo, @@ -254,6 +293,7 @@ func TestPreconfBidSubmission(t *testing.T) { proc, &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, + eventManager, newTestLogger(t, os.Stdout), ) diff --git a/pkg/store/store.go b/pkg/store/store.go new file mode 100644 index 00000000..a93b6a44 --- /dev/null +++ b/pkg/store/store.go @@ -0,0 +1,34 @@ +package store + +import ( + "sync" +) + +type Store struct { + data map[string]int64 + mu sync.RWMutex +} + +func NewStore() *Store { + return &Store{ + data: make(map[string]int64), + } +} + +func (s *Store) LastBlock() (uint64, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + if value, exists := s.data["last_block"]; exists { + return uint64(value), nil + } + return 0, nil +} + +func (s *Store) SetLastBlock(blockNum uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.data["last_block"] = int64(blockNum) + return nil +} From cebd9828cd9d18068bd497f284a9d0fdb7fdc756 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 16 Apr 2024 21:33:59 +0200 Subject: [PATCH 55/85] changed event struct --- pkg/preconfirmation/preconfirmation.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 19fa1031..3ff26d60 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" @@ -327,7 +328,7 @@ func (p *Preconfirmation) handleBid( func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { ev := events.NewEventHandler( "NewL1Block", - func(newL1Block *blocktrackercontract.NewL1BlockEvent) error { + func(newL1Block *blocktracker.BlocktrackerNewL1Block) error { p.logger.Info("New L1 Block event received", "blockNumber", newL1Block.BlockNumber, "winner", newL1Block.Winner, "window", newL1Block.Window) // todo: for provider check if winner == providerAddress, for bidder if committerAddress for _, commitment := range p.commitmentByBlockNumber[newL1Block.BlockNumber.Int64()] { From 4944d916c688d46b9817e054e8dd68b988eb2a50 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 16 Apr 2024 21:55:07 +0200 Subject: [PATCH 56/85] fixed not started event listener --- pkg/node/node.go | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index a170a3db..7721f708 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -77,7 +77,7 @@ type Options struct { type Node struct { waitClose func() - closers []io.Closer + closers []io.Closer } func NewNode(opts *Options) (*Node, error) { @@ -192,6 +192,22 @@ func NewNode(opts *Options) (*Node, error) { defer cancel() var preconfProtoClosed <-chan struct{} + st := store.NewStore() + + contracts, err := getContractABIs(opts) + if err != nil { + opts.Logger.Error("failed to get contract ABIs", "error", err) + return nil, err + } + + evtMgr := events.NewListener( + opts.Logger.With("component", "events"), + evmClient, + st, + contracts, + ) + + evtMgrDone := evtMgr.Start(ctx) if opts.PeerType != p2p.PeerTypeBootnode.String() { lis, err := net.Listen("tcp", opts.RPCAddr) @@ -234,21 +250,6 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "blocktrackercontract"), ) - st := store.NewStore() - - contracts, err := getContractABIs(opts) - if err != nil { - opts.Logger.Error("failed to get contract ABIs", "error", err) - return nil, err - } - - evtMgr := events.NewListener( - opts.Logger.With("component", "events"), - evmClient, - st, - contracts, - ) - switch opts.PeerType { case p2p.PeerTypeProvider.String(): providerAPI := providerapi.NewService( @@ -468,6 +469,7 @@ func NewNode(opts *Options) (*Node, error) { go func() { defer close(closeChan) + <-evtMgrDone <-preconfProtoClosed }() From d7e22be39e584930afff4d6b19203f6e791e3316 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 16 Apr 2024 22:59:04 +0200 Subject: [PATCH 57/85] deleted redundant conversion --- pkg/store/store.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/store/store.go b/pkg/store/store.go index a93b6a44..3d457039 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -5,13 +5,13 @@ import ( ) type Store struct { - data map[string]int64 + data map[string]uint64 mu sync.RWMutex } func NewStore() *Store { return &Store{ - data: make(map[string]int64), + data: make(map[string]uint64), } } @@ -20,7 +20,7 @@ func (s *Store) LastBlock() (uint64, error) { defer s.mu.RUnlock() if value, exists := s.data["last_block"]; exists { - return uint64(value), nil + return value, nil } return 0, nil } @@ -29,6 +29,6 @@ func (s *Store) SetLastBlock(blockNum uint64) error { s.mu.Lock() defer s.mu.Unlock() - s.data["last_block"] = int64(blockNum) + s.data["last_block"] = blockNum return nil } From 60c9150d15c4001d80996dde0a558d4436fd0e0c Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 12:52:46 +0200 Subject: [PATCH 58/85] changed ctx creation in node --- pkg/node/node.go | 3 +++ pkg/preconfirmation/preconfirmation.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 7721f708..b79dff3e 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -404,6 +404,9 @@ func NewNode(opts *Options) (*Node, error) { return nil, errors.New("dialing of grpc server failed") } + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + gatewayMux := runtime.NewServeMux() switch opts.PeerType { case p2p.PeerTypeProvider.String(): diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 3ff26d60..a3dd36ac 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -111,7 +111,7 @@ func (p *Preconfirmation) Start(ctx context.Context) <-chan struct{} { eg.Go(func() error { return p.subscribeNewL1Block(egCtx) }) - + go func() { defer close(doneChan) if err := eg.Wait(); err != nil { From c2fd6c1f5cffad8f215d35dea658c6f7abe36db8 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 13:19:23 +0200 Subject: [PATCH 59/85] changed cancel ctx --- pkg/node/node.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index b79dff3e..7d7e8265 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -189,7 +189,6 @@ func NewNode(opts *Options) (*Node, error) { debugapi.RegisterAPI(srv, topo, p2pSvc, opts.Logger.With("component", "debugapi")) ctx, cancel := context.WithCancel(context.Background()) - defer cancel() var preconfProtoClosed <-chan struct{} st := store.NewStore() @@ -197,6 +196,7 @@ func NewNode(opts *Options) (*Node, error) { contracts, err := getContractABIs(opts) if err != nil { opts.Logger.Error("failed to get contract ABIs", "error", err) + cancel() return nil, err } @@ -213,6 +213,7 @@ func NewNode(opts *Options) (*Node, error) { lis, err := net.Listen("tcp", opts.RPCAddr) if err != nil { opts.Logger.Error("failed to listen", "error", err) + cancel() return nil, errors.Join(err, nd.Close()) } @@ -224,6 +225,7 @@ func NewNode(opts *Options) (*Node, error) { ) if err != nil { opts.Logger.Error("failed to load TLS credentials", "error", err) + cancel() return nil, fmt.Errorf("unable to load TLS credentials: %w", err) } } @@ -233,6 +235,7 @@ func NewNode(opts *Options) (*Node, error) { validator, err := protovalidate.New() if err != nil { opts.Logger.Error("failed to create proto validator", "error", err) + cancel() return nil, errors.Join(err, nd.Close()) } @@ -401,24 +404,27 @@ func NewNode(opts *Options) (*Node, error) { break } if grpcConn == nil { + cancel() return nil, errors.New("dialing of grpc server failed") } - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() + handlerCtx, handlerCancel := context.WithTimeout(context.Background(), 3*time.Second) + defer handlerCancel() gatewayMux := runtime.NewServeMux() switch opts.PeerType { case p2p.PeerTypeProvider.String(): - err := providerapiv1.RegisterProviderHandler(ctx, gatewayMux, grpcConn) + err := providerapiv1.RegisterProviderHandler(handlerCtx, gatewayMux, grpcConn) if err != nil { opts.Logger.Error("failed to register provider handler", "err", err) + cancel() return nil, errors.Join(err, nd.Close()) } case p2p.PeerTypeBidder.String(): - err := bidderapiv1.RegisterBidderHandler(ctx, gatewayMux, grpcConn) + err := bidderapiv1.RegisterBidderHandler(handlerCtx, gatewayMux, grpcConn) if err != nil { opts.Logger.Error("failed to register bidder handler", "err", err) + cancel() return nil, errors.Join(err, nd.Close()) } } From 6b357c7bc95c2d1862b453aa98898a674bc66932 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 21:57:06 +0200 Subject: [PATCH 60/85] added event listening for the commitmentIndex saving --- pkg/node/node.go | 4 + pkg/preconfirmation/preconfirmation.go | 125 +++++++++++++------- pkg/preconfirmation/preconfirmation_test.go | 2 + pkg/store/store.go | 78 +++++++++++- 4 files changed, 163 insertions(+), 46 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 7d7e8265..f9ac2bf1 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -253,6 +253,8 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "blocktrackercontract"), ) + store := store.NewStore() + switch opts.PeerType { case p2p.PeerTypeProvider.String(): providerAPI := providerapi.NewService( @@ -285,6 +287,7 @@ func NewNode(opts *Options) (*Node, error) { commitmentDA, blockTracker, evtMgr, + store, opts.Logger.With("component", "preconfirmation_protocol"), ) opts.Logger.Info("registered preconfirmation protocol") @@ -317,6 +320,7 @@ func NewNode(opts *Options) (*Node, error) { commitmentDA, blockTracker, evtMgr, + store, opts.Logger.With("component", "preconfirmation_protocol"), ) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index a3dd36ac..6ff9d264 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" + preconfcommstore "github.com/primevprotocol/contracts-abi/clients/PreConfCommitmentStore" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" @@ -18,6 +19,7 @@ import ( "github.com/primevprotocol/mev-commit/pkg/events" "github.com/primevprotocol/mev-commit/pkg/p2p" encryptor "github.com/primevprotocol/mev-commit/pkg/signer/preconfencryptor" + "github.com/primevprotocol/mev-commit/pkg/store" "github.com/primevprotocol/mev-commit/pkg/topology" "golang.org/x/sync/errgroup" "google.golang.org/grpc/codes" @@ -29,25 +31,19 @@ const ( ProtocolVersion = "1.0.0" ) -type EncryptedPreConfirmationWithDecrypted struct { - *preconfpb.EncryptedPreConfirmation - *preconfpb.PreConfirmation -} - type Preconfirmation struct { - owner common.Address - // todo: store the commitments in a database - commitmentByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted - encryptor encryptor.Encryptor - topo Topology - streamer p2p.Streamer - us BidderStore - processer BidProcessor - commitmentDA preconfcontract.Interface - blockTracker blocktrackercontract.Interface - evtMgr events.EventManager - logger *slog.Logger - metrics *metrics + owner common.Address + encryptor encryptor.Encryptor + topo Topology + streamer p2p.Streamer + us BidderStore + processer BidProcessor + commitmentDA preconfcontract.Interface + blockTracker blocktrackercontract.Interface + evtMgr events.EventManager + ecds EncrDecrCommitmentStore + logger *slog.Logger + metrics *metrics } type Topology interface { @@ -62,6 +58,13 @@ type BidProcessor interface { ProcessBid(context.Context, *preconfpb.Bid) (chan providerapiv1.BidResponse_Status, error) } +type EncrDecrCommitmentStore interface { + GetCommitmentsByBlockNumber(blockNum int64) ([]*store.EncryptedPreConfirmationWithDecrypted, error) + GetCommitmentByHash(commitmentHash string) (*store.EncryptedPreConfirmationWithDecrypted, error) + AddCommitment(commitment *store.EncryptedPreConfirmationWithDecrypted) + DeleteCommitmentByBlockNumber(blockNum int64) error +} + func New( owner common.Address, topo Topology, @@ -72,22 +75,22 @@ func New( commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, evtMgr events.EventManager, + edcs EncrDecrCommitmentStore, logger *slog.Logger, ) *Preconfirmation { - commitmentsByBlockNumber := make(map[int64][]*EncryptedPreConfirmationWithDecrypted) return &Preconfirmation{ - owner: owner, - commitmentByBlockNumber: commitmentsByBlockNumber, - topo: topo, - streamer: streamer, - encryptor: encryptor, - us: us, - processer: processor, - commitmentDA: commitmentDA, - blockTracker: blockTracker, - evtMgr: evtMgr, - logger: logger, - metrics: newMetrics(), + owner: owner, + topo: topo, + streamer: streamer, + encryptor: encryptor, + us: us, + processer: processor, + commitmentDA: commitmentDA, + blockTracker: blockTracker, + evtMgr: evtMgr, + ecds: edcs, + logger: logger, + metrics: newMetrics(), } } @@ -111,7 +114,11 @@ func (p *Preconfirmation) Start(ctx context.Context) <-chan struct{} { eg.Go(func() error { return p.subscribeNewL1Block(egCtx) }) - + + eg.Go(func() error { + return p.subscribeEncryptedCommitmentStored(egCtx) + }) + go func() { defer close(doneChan) if err := eg.Wait(); err != nil { @@ -206,13 +213,12 @@ func (p *Preconfirmation) SendBid( preConfirmation.ProviderAddress = make([]byte, len(providerAddress)) copy(preConfirmation.ProviderAddress, providerAddress[:]) - encryptedAndDecryptedPreconfirmation := &EncryptedPreConfirmationWithDecrypted{ + encryptedAndDecryptedPreconfirmation := &store.EncryptedPreConfirmationWithDecrypted{ EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, } - p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) - + p.ecds.AddCommitment(encryptedAndDecryptedPreconfirmation) logger.Info("received preconfirmation", "preConfirmation", preConfirmation) p.metrics.ReceivedPreconfsCount.Inc() @@ -300,7 +306,7 @@ func (p *Preconfirmation) handleBid( return status.Errorf(codes.Internal, "failed to constuct encrypted preconfirmation: %v", err) } p.logger.Info("sending preconfirmation", "preConfirmation", encryptedPreConfirmation) - commitmentIndex, err := p.commitmentDA.StoreEncryptedCommitment( + _, err = p.commitmentDA.StoreEncryptedCommitment( ctx, encryptedPreConfirmation.Commitment, encryptedPreConfirmation.Signature, @@ -310,14 +316,12 @@ func (p *Preconfirmation) handleBid( return status.Errorf(codes.Internal, "failed to store commitments: %v", err) } - encryptedPreConfirmation.CommitmentIndex = commitmentIndex.Bytes() - encryptedAndDecryptedPreconfirmation := &EncryptedPreConfirmationWithDecrypted{ + encryptedAndDecryptedPreconfirmation := &store.EncryptedPreConfirmationWithDecrypted{ EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, } - blockNumber := preConfirmation.Bid.BlockNumber - p.commitmentByBlockNumber[blockNumber] = append(p.commitmentByBlockNumber[blockNumber], encryptedAndDecryptedPreconfirmation) + p.ecds.AddCommitment(encryptedAndDecryptedPreconfirmation) return stream.WriteMsg(ctx, encryptedPreConfirmation) } @@ -330,8 +334,16 @@ func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { "NewL1Block", func(newL1Block *blocktracker.BlocktrackerNewL1Block) error { p.logger.Info("New L1 Block event received", "blockNumber", newL1Block.BlockNumber, "winner", newL1Block.Winner, "window", newL1Block.Window) - // todo: for provider check if winner == providerAddress, for bidder if committerAddress - for _, commitment := range p.commitmentByBlockNumber[newL1Block.BlockNumber.Int64()] { + commitments, err := p.ecds.GetCommitmentsByBlockNumber(newL1Block.BlockNumber.Int64()) + if err != nil { + p.logger.Error("failed to get commitments by block number", "error", err) + return err + } + for _, commitment := range commitments { + if common.BytesToAddress(commitment.ProviderAddress) != newL1Block.Winner { + p.logger.Info("provider address does not match the winner", "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner) + continue + } txHash, err := p.commitmentDA.OpenCommitment( ctx, commitment.EncryptedPreConfirmation.CommitmentIndex, @@ -352,7 +364,7 @@ func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { p.logger.Info("opened commitment", "txHash", txHash) } } - delete(p.commitmentByBlockNumber, newL1Block.BlockNumber.Int64()) + p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) return nil }, ) @@ -370,3 +382,30 @@ func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { return fmt.Errorf("subscription error: %w", err) } } + +func (p *Preconfirmation) subscribeEncryptedCommitmentStored(ctx context.Context) error { + ev := events.NewEventHandler( + "EncryptedCommitmentStored", + func(ec *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored) error { + commitment, err := p.ecds.GetCommitmentByHash(string(common.Bytes2Hex(ec.CommitmentDigest[:]))) + if err != nil { + return fmt.Errorf("failed to get commitment by hash: %w", err) + } + commitment.EncryptedPreConfirmation.CommitmentIndex = ec.CommitmentIndex[:] + return nil + }, + ) + + sub, err := p.evtMgr.Subscribe(ev) + if err != nil { + return fmt.Errorf("failed to subscribe to EncryptedCommitmentStored event: %w", err) + } + defer sub.Unsubscribe() + + select { + case <-ctx.Done(): + return nil + case err := <-sub.Err(): + return fmt.Errorf("encrypted commitment stored subscription error: %w", err) + } +} diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 82a1ec00..1c6e6247 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -26,6 +26,7 @@ import ( "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" "github.com/primevprotocol/mev-commit/pkg/preconfirmation" + "github.com/primevprotocol/mev-commit/pkg/store" "github.com/primevprotocol/mev-commit/pkg/topology" ) @@ -294,6 +295,7 @@ func TestPreconfBidSubmission(t *testing.T) { &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, eventManager, + store.NewStore(), newTestLogger(t, os.Stdout), ) diff --git a/pkg/store/store.go b/pkg/store/store.go index 3d457039..129633b1 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -2,16 +2,30 @@ package store import ( "sync" + + "github.com/ethereum/go-ethereum/common" + preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" ) type Store struct { - data map[string]uint64 - mu sync.RWMutex + data map[string]uint64 + commitmentsByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted + commitmentsByCommitmentHash map[string]*EncryptedPreConfirmationWithDecrypted + commitmentByBlockNumberMu sync.RWMutex + commitmentsByCommitmentHashMu sync.RWMutex + mu sync.RWMutex +} + +type EncryptedPreConfirmationWithDecrypted struct { + *preconfpb.EncryptedPreConfirmation + *preconfpb.PreConfirmation } func NewStore() *Store { return &Store{ - data: make(map[string]uint64), + data: make(map[string]uint64), + commitmentsByBlockNumber: make(map[int64][]*EncryptedPreConfirmationWithDecrypted), + commitmentsByCommitmentHash: make(map[string]*EncryptedPreConfirmationWithDecrypted), } } @@ -32,3 +46,61 @@ func (s *Store) SetLastBlock(blockNum uint64) error { s.data["last_block"] = blockNum return nil } + +func (s *Store) addCommitmentByBlockNumber(blockNum int64, commitment *EncryptedPreConfirmationWithDecrypted) { + s.commitmentByBlockNumberMu.Lock() + defer s.commitmentByBlockNumberMu.Unlock() + + s.commitmentsByBlockNumber[blockNum] = append(s.commitmentsByBlockNumber[blockNum], commitment) +} + +func (s *Store) addCommitmentByHash(hash string, commitment *EncryptedPreConfirmationWithDecrypted) { + s.commitmentsByCommitmentHashMu.Lock() + defer s.commitmentsByCommitmentHashMu.Unlock() + + s.commitmentsByCommitmentHash[hash] = commitment +} + +func (s *Store) AddCommitment(commitment *EncryptedPreConfirmationWithDecrypted) { + s.addCommitmentByBlockNumber(commitment.Bid.BlockNumber, commitment) + s.addCommitmentByHash(common.Bytes2Hex(commitment.Commitment), commitment) +} + +func (s *Store) GetCommitmentsByBlockNumber(blockNum int64) ([]*EncryptedPreConfirmationWithDecrypted, error) { + s.commitmentByBlockNumberMu.RLock() + defer s.commitmentByBlockNumberMu.RUnlock() + + if commitments, exists := s.commitmentsByBlockNumber[blockNum]; exists { + return commitments, nil + } + return nil, nil +} + +func (s *Store) GetCommitmentByHash(hash string) (*EncryptedPreConfirmationWithDecrypted, error) { + s.commitmentsByCommitmentHashMu.RLock() + defer s.commitmentsByCommitmentHashMu.RUnlock() + + if commitment, exists := s.commitmentsByCommitmentHash[hash]; exists { + return commitment, nil + } + return nil, nil +} + +func (s *Store) DeleteCommitmentByBlockNumber(blockNum int64) error { + s.commitmentByBlockNumberMu.Lock() + defer s.commitmentByBlockNumberMu.Unlock() + + for _, v := range s.commitmentsByBlockNumber[blockNum] { + s.deleteCommitmentByHash(common.Bytes2Hex(v.Commitment)) + } + delete(s.commitmentsByBlockNumber, blockNum) + return nil +} + +func (s *Store) deleteCommitmentByHash(hash string) error { + s.commitmentsByCommitmentHashMu.Lock() + defer s.commitmentsByCommitmentHashMu.Unlock() + + delete(s.commitmentsByCommitmentHash, hash) + return nil +} From e1b8f847f4cedb60f516eae900a7c527500a4377 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 22:04:19 +0200 Subject: [PATCH 61/85] fixed lint issues --- pkg/preconfirmation/preconfirmation.go | 6 +++++- pkg/store/store.go | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 6ff9d264..7c00a2d7 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -364,7 +364,11 @@ func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { p.logger.Info("opened commitment", "txHash", txHash) } } - p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) + err = p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) + if err != nil { + p.logger.Error("failed to delete commitments by block number", "error", err) + return err + } return nil }, ) diff --git a/pkg/store/store.go b/pkg/store/store.go index 129633b1..fd27cf14 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -91,7 +91,10 @@ func (s *Store) DeleteCommitmentByBlockNumber(blockNum int64) error { defer s.commitmentByBlockNumberMu.Unlock() for _, v := range s.commitmentsByBlockNumber[blockNum] { - s.deleteCommitmentByHash(common.Bytes2Hex(v.Commitment)) + err := s.deleteCommitmentByHash(common.Bytes2Hex(v.Commitment)) + if err != nil { + return err + } } delete(s.commitmentsByBlockNumber, blockNum) return nil From c325a87e5cc92bbfd7dd954e097ec25090913234 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 22:13:33 +0200 Subject: [PATCH 62/85] init commitmentDA for bidder and provider --- pkg/node/node.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index f9ac2bf1..8555a4f8 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -241,7 +241,6 @@ func NewNode(opts *Options) (*Node, error) { var ( bidProcessor preconfirmation.BidProcessor = noOpBidProcessor{} - commitmentDA preconfcontract.Interface = noOpCommitmentDA{} ) blockTrackerAddr := common.HexToAddress(opts.BlockTrackerContract) @@ -253,6 +252,14 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "blocktrackercontract"), ) + preconfContractAddr := common.HexToAddress(opts.PreconfContract) + commitmentDA := preconfcontract.New( + preconfContractAddr, + evmClient, + opts.Logger.With("component", "preconfcontract"), + ) + opts.Logger.Info("registered preconf contract") + store := store.NewStore() switch opts.PeerType { @@ -269,13 +276,6 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) opts.Logger.Info("registered provider api metrics") - preconfContractAddr := common.HexToAddress(opts.PreconfContract) - commitmentDA = preconfcontract.New( - preconfContractAddr, - evmClient, - opts.Logger.With("component", "preconfcontract"), - ) - opts.Logger.Info("registered preconf contract") preconfProto := preconfirmation.New( keyKeeper.GetAddress(), From 3126dbb7993bfa1c0829a72a85a8262f33148271 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 22:33:18 +0200 Subject: [PATCH 63/85] added more logs --- pkg/contracts/preconf/preconf.go | 20 +------------------- pkg/preconfirmation/preconfirmation.go | 7 ++++++- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index aea337c4..309e93df 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -87,25 +87,7 @@ func (p *preconfContract) StoreEncryptedCommitment( return common.Hash{}, err } - // todo: add event tracker to add commitment to avoid waiting - receipt, err := p.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return common.Hash{}, err // Updated to return common.Hash{} - } - - p.logger.Info("preconf contract storeEncryptedCommitment successful", "txnHash", txnHash) - eventTopicHash := p.preconfABI.Events["EncryptedCommitmentStored"].ID // This is the event signature hash - - for _, log := range receipt.Logs { - if len(log.Topics) > 0 && log.Topics[0] == eventTopicHash { - commitmentIndex := log.Topics[1] // Topics[0] is the event signature, Topics[1] should be the first indexed argument - p.logger.Info("Encrypted commitment stored", "commitmentIndex", commitmentIndex.Hex()) - - return commitmentIndex, nil // Return the extracted commitmentIndex - } - } - - return common.Hash{}, nil + return txnHash, nil } func (p *preconfContract) OpenCommitment( diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 7c00a2d7..c68fc3b8 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -391,10 +391,15 @@ func (p *Preconfirmation) subscribeEncryptedCommitmentStored(ctx context.Context ev := events.NewEventHandler( "EncryptedCommitmentStored", func(ec *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored) error { - commitment, err := p.ecds.GetCommitmentByHash(string(common.Bytes2Hex(ec.CommitmentDigest[:]))) + p.logger.Info("Encrypted Commitment Stored event received", "commitmentDigest", ec.CommitmentDigest, "commitmentIndex", ec.CommitmentIndex) + commitment, err := p.ecds.GetCommitmentByHash(common.Bytes2Hex(ec.CommitmentDigest[:])) if err != nil { return fmt.Errorf("failed to get commitment by hash: %w", err) } + if commitment == nil { + p.logger.Debug("commitment not found", "commitmentDigest", ec.CommitmentDigest) + return nil + } commitment.EncryptedPreConfirmation.CommitmentIndex = ec.CommitmentIndex[:] return nil }, From ded166ad2394a63a33b0125d9429467fd855323c Mon Sep 17 00:00:00 2001 From: Mikelle Date: Wed, 17 Apr 2024 22:37:59 +0200 Subject: [PATCH 64/85] deleted noopcomm --- pkg/node/node.go | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 8555a4f8..3690d768 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -414,7 +414,7 @@ func NewNode(opts *Options) (*Node, error) { handlerCtx, handlerCancel := context.WithTimeout(context.Background(), 3*time.Second) defer handlerCancel() - + gatewayMux := runtime.NewServeMux() switch opts.PeerType { case p2p.PeerTypeProvider.String(): @@ -541,32 +541,3 @@ func (noOpBidProcessor) ProcessBid( return statusC, nil } - -type noOpCommitmentDA struct{} - -func (noOpCommitmentDA) StoreEncryptedCommitment( - _ context.Context, - _ []byte, - _ []byte, -) (common.Hash, error) { - return common.Hash{}, nil -} - -func (noOpCommitmentDA) OpenCommitment( - _ context.Context, - _ []byte, - _ string, - _ int64, - _ string, - _ int64, - _ int64, - _ []byte, - _ []byte, - _ []byte, -) (common.Hash, error) { - return common.Hash{}, nil -} - -func (noOpCommitmentDA) Close() error { - return nil -} From 8d55564a527ea7e4c679501626bf93d252d984a5 Mon Sep 17 00:00:00 2001 From: Alok Date: Thu, 18 Apr 2024 20:12:37 +0530 Subject: [PATCH 65/85] fix: allowance refresh for testing --- integrationtest/real-bidder/main.go | 2 +- .../bidder_registry/bidder_registry.go | 59 ++++++++++++++++++- .../bidder_registry/bidder_registry_test.go | 12 +++- pkg/node/node.go | 1 + pkg/rpc/bidder/service.go | 28 +++++++-- pkg/rpc/bidder/service_test.go | 10 +++- 6 files changed, 99 insertions(+), 13 deletions(-) diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index 4a60a040..d16c79cb 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -124,7 +124,7 @@ func main() { wg.Add(1) go func() { - ticker := time.NewTicker(1 * time.Hour) + ticker := time.NewTicker(2 * time.Second) defer ticker.Stop() for { diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index ebe41ee1..dd4b0cf6 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -30,9 +30,12 @@ type Interface interface { GetMinAllowance(ctx context.Context) (*big.Int, error) // CheckBidderRegistred returns true if bidder is registered CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int, blocksPerWindow *big.Int) bool + // WithdrawAllowance withdraws the stake of a bidder. + WithdrawAllowance(ctx context.Context, window *big.Int) error } type bidderRegistryContract struct { + owner common.Address bidderRegistryABI abi.ABI bidderRegistryContractAddr common.Address client evmclient.Interface @@ -40,6 +43,7 @@ type bidderRegistryContract struct { } func New( + owner common.Address, bidderRegistryContractAddr common.Address, client evmclient.Interface, logger *slog.Logger, @@ -91,7 +95,7 @@ func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *bi if len(log.Topics) > 1 { bidderRegistered.Bidder = common.HexToAddress(log.Topics[1].Hex()) } - + err := r.bidderRegistryABI.UnpackIntoInterface(&bidderRegistered, "BidderRegistered", log.Data) if err != nil { r.logger.Debug("Failed to unpack event", "err", err) @@ -157,6 +161,59 @@ func (r *bidderRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil } +func (r *bidderRegistryContract) WithdrawAllowance(ctx context.Context, window *big.Int) error { + callData, err := r.bidderRegistryABI.Pack("withdrawBidderAmountFromWindow", r.owner, window) + if err != nil { + r.logger.Error("error packing call data", "error", err) + return err + } + + txnHash, err := r.client.Send(ctx, &evmclient.TxRequest{ + To: &r.bidderRegistryContractAddr, + CallData: callData, + }) + if err != nil { + return err + } + + receipt, err := r.client.WaitForReceipt(ctx, txnHash) + if err != nil { + return err + } + + if receipt.Status != types.ReceiptStatusSuccessful { + r.logger.Error( + "withdraw failed for bidder registry", + "txnHash", txnHash, + "receipt", receipt, + ) + return err + } + + var bidderWithdrawn struct { + Bidder common.Address + Amount *big.Int + Window *big.Int + } + + for _, log := range receipt.Logs { + if len(log.Topics) > 1 { + bidderWithdrawn.Bidder = common.HexToAddress(log.Topics[1].Hex()) + } + + err := r.bidderRegistryABI.UnpackIntoInterface(&bidderWithdrawn, "BidderWithdrawn", log.Data) + if err != nil { + r.logger.Debug("Failed to unpack event", "err", err) + continue + } + r.logger.Info("bidder withdrawn", "address", bidderWithdrawn.Bidder, "withdrawn", bidderWithdrawn.Amount.Uint64(), "windowNumber", bidderWithdrawn.Window.Int64()) + } + + r.logger.Info("withdraw successful for bidder registry", "txnHash", txnHash, "bidder", bidderWithdrawn.Bidder) + + return nil +} + func (r *bidderRegistryContract) CheckBidderAllowance( ctx context.Context, address common.Address, diff --git a/pkg/contracts/bidder_registry/bidder_registry_test.go b/pkg/contracts/bidder_registry/bidder_registry_test.go index 5bab50ee..dc0e54d6 100644 --- a/pkg/contracts/bidder_registry/bidder_registry_test.go +++ b/pkg/contracts/bidder_registry/bidder_registry_test.go @@ -18,6 +18,8 @@ import ( func TestBidderRegistryContract(t *testing.T) { t.Parallel() + owner := common.HexToAddress("abcd") + t.Run("PrepayAllowance", func(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") txHash := common.HexToHash("abcdef") @@ -66,6 +68,7 @@ func TestBidderRegistryContract(t *testing.T) { ) registryContract := bidder_registrycontract.New( + owner, registryContractAddr, mockClient, util.NewTestLogger(os.Stdout), @@ -106,6 +109,7 @@ func TestBidderRegistryContract(t *testing.T) { ) registryContract := bidder_registrycontract.New( + owner, registryContractAddr, mockClient, util.NewTestLogger(os.Stdout), @@ -148,6 +152,7 @@ func TestBidderRegistryContract(t *testing.T) { ) registryContract := bidder_registrycontract.New( + owner, registryContractAddr, mockClient, util.NewTestLogger(os.Stdout), @@ -174,7 +179,7 @@ func TestBidderRegistryContract(t *testing.T) { mockClient := mockevmclient.New( mockevmclient.WithCallFunc( func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - callCount++; + callCount++ if req.To.Cmp(registryContractAddr) != 0 { t.Fatalf( "expected to address to be %s, got %s", @@ -184,14 +189,15 @@ func TestBidderRegistryContract(t *testing.T) { if callCount == 1 { return new(big.Int).Div(amount, blocksPerWindow).FillBytes(make([]byte, 32)), nil - } - + } + return amount.FillBytes(make([]byte, 32)), nil }, ), ) registryContract := bidder_registrycontract.New( + owner, registryContractAddr, mockClient, util.NewTestLogger(os.Stdout), diff --git a/pkg/node/node.go b/pkg/node/node.go index 3690d768..9e1e8246 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -124,6 +124,7 @@ func NewNode(opts *Options) (*Node, error) { bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) bidderRegistry := bidder_registrycontract.New( + opts.KeySigner.GetAddress(), bidderRegistryContractAddr, evmClient, opts.Logger.With("component", "bidderregistry"), diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 4def377f..24def954 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -27,6 +27,7 @@ type Service struct { logger *slog.Logger metrics *metrics validator *protovalidate.Validator + depositedWindows map[*big.Int]struct{} } func NewService( @@ -45,6 +46,7 @@ func NewService( logger: logger, metrics: newMetrics(), validator: validator, + depositedWindows: make(map[*big.Int]struct{}), } } @@ -116,6 +118,26 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.InvalidArgument, "validating prepay request: %v", err) } + currentWindow, err := s.blockTrackerContract.GetCurrentWindow(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting current window: %v", err) + } + + if _, ok := s.depositedWindows[new(big.Int).SetUint64(currentWindow+1)]; ok { + return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", currentWindow+1) + } + + for window := range s.depositedWindows { + if window.Cmp(new(big.Int).SetUint64(currentWindow-2)) < 0 { + err := s.registryContract.WithdrawAllowance(ctx, window) + if err != nil { + return nil, status.Errorf(codes.Internal, "withdrawing allowance: %v", err) + } + s.logger.Info("withdrew allowance", "window", window) + delete(s.depositedWindows, window) + } + } + amount, success := big.NewInt(0).SetString(stake.Amount, 10) if !success { return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", stake.Amount) @@ -126,17 +148,13 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "prepaying allowance: %v", err) } - currentWindow, err := s.blockTrackerContract.GetCurrentWindow(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting current window: %v", err) - } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, new(big.Int).SetUint64(currentWindow+1)) if err != nil { return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", currentWindow+1) + s.depositedWindows[new(big.Int).SetUint64(currentWindow+1)] = struct{}{} return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil } diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 33461d6d..314498ba 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -99,11 +99,15 @@ func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address return t.allowance.Cmp(t.minAllowance) > 0 } +func (t *testRegistryContract) WithdrawAllowance(ctx context.Context, window *big.Int) error { + return nil +} + type testBlockTrackerContract struct { blockNumberToWinner map[uint64]common.Address - lastBlockNumber uint64 - lastBlockWinner common.Address - blocksPerWindow uint64 + lastBlockNumber uint64 + lastBlockWinner common.Address + blocksPerWindow uint64 } // RecordBlock records a new block and its winner. From 2fca5a16e993a56ba82103e4c597bf9a5be7b723 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 17:32:29 +0200 Subject: [PATCH 66/85] added allowance manager --- pkg/allowancemanager/allowance.go | 146 ++++++++++++++++++++ pkg/node/node.go | 34 +++-- pkg/preconfirmation/preconfirmation.go | 40 +++--- pkg/preconfirmation/preconfirmation_test.go | 14 +- pkg/store/store.go | 125 +++++++++++------ 5 files changed, 284 insertions(+), 75 deletions(-) create mode 100644 pkg/allowancemanager/allowance.go diff --git a/pkg/allowancemanager/allowance.go b/pkg/allowancemanager/allowance.go new file mode 100644 index 00000000..301e2fb9 --- /dev/null +++ b/pkg/allowancemanager/allowance.go @@ -0,0 +1,146 @@ +package allowancemanager + +import ( + "context" + "fmt" + "log/slog" + "math/big" + + "github.com/ethereum/go-ethereum/common" + bidderregistry "github.com/primevprotocol/contracts-abi/clients/BidderRegistry" + blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" + preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" + "github.com/primevprotocol/mev-commit/pkg/events" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type BidderRegistry interface { + CheckBidderAllowance(context.Context, common.Address, *big.Int, *big.Int) bool + GetMinAllowance(ctx context.Context) (*big.Int, error) +} + +type Store interface { + GetBalance(bidder common.Address, windowNumber *big.Int) (*big.Int, error) + SetBalance(bidder common.Address, windowNumber *big.Int, balance *big.Int) error +} + +type AllowanceManager struct { + bidderRegistry BidderRegistry + blockTracker blocktrackercontract.Interface + commitmentDA preconfcontract.Interface + store Store + evtMgr events.EventManager + blocksPerWindow *big.Int // todo: move to the store + minAllowance *big.Int // todo: move to the store + logger *slog.Logger +} + +func NewAllowanceManager( + br BidderRegistry, + blockTracker blocktrackercontract.Interface, + commitmentDA preconfcontract.Interface, + store Store, + evtMgr events.EventManager, + logger *slog.Logger, +) *AllowanceManager { + return &AllowanceManager{ + bidderRegistry: br, + blockTracker: blockTracker, + commitmentDA: commitmentDA, + store: store, + evtMgr: evtMgr, + logger: logger, + } +} + +func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { + doneChan := make(chan struct{}) + + eg, egCtx := errgroup.WithContext(ctx) + + eg.Go(func() error { + return a.subscribeBidderRegistered(egCtx) + }) + + go func() { + defer close(doneChan) + if err := eg.Wait(); err != nil { + a.logger.Error("error in AllowanceManager", "error", err) + } + }() + + return doneChan +} + +func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Address, window *big.Int) error { + if a.blocksPerWindow == nil { + blocksPerWindow, err := a.blockTracker.GetBlocksPerWindow(ctx) + if err != nil { + a.logger.Error("getting blocks per window", "error", err) + return status.Errorf(codes.Internal, "failed to get blocks per window: %v", err) + } + a.blocksPerWindow = new(big.Int).SetUint64(blocksPerWindow) + } + + if a.minAllowance == nil { + minAllowance, err := a.bidderRegistry.GetMinAllowance(ctx) + if err != nil { + a.logger.Error("getting min allowance", "error", err) + return status.Errorf(codes.Internal, "failed to get min allowance: %v", err) + + } + a.minAllowance = minAllowance + } + + balance, err := a.store.GetBalance(address, window) + if err != nil { + a.logger.Error("getting balance", "error", err) + return status.Errorf(codes.Internal, "failed to get balance: %v", err) + } + + a.logger.Info("checking bidder allowance", + "stake", balance.Uint64(), + "blocksPerWindow", a.blocksPerWindow, + "minStake", a.minAllowance.Uint64(), + "window", window.Uint64(), + "address", address.Hex(), + ) + + isEnoughAllowance := (balance.Div(balance, a.blocksPerWindow)).Cmp(a.minAllowance) >= 0 + + if !isEnoughAllowance { + a.logger.Error("bidder does not have enough allowance", "ethAddress", address) + return status.Errorf(codes.FailedPrecondition, "bidder not allowed") + } + + return nil +} + +func (a *AllowanceManager) subscribeBidderRegistered(ctx context.Context) error { + ev := events.NewEventHandler( + "BidderRegistered", + func(bidderReg *bidderregistry.BidderregistryBidderRegistered) error { + // todo: do we need to check if commiter is connected to this bidder? + err := a.store.SetBalance(bidderReg.Bidder, bidderReg.WindowNumber, bidderReg.PrepaidAmount) + if err != nil { + return err + } + return nil + }, + ) + + sub, err := a.evtMgr.Subscribe(ev) + if err != nil { + return fmt.Errorf("failed to subscribe to BidderRegistered event: %w", err) + } + defer sub.Unsubscribe() + + select { + case <-ctx.Done(): + return nil + case err := <-sub.Err(): + return fmt.Errorf("error in BidderRegistered event subscription: %w", err) + } +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 9e1e8246..fd2d2736 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "log/slog" + "math/big" "net" "net/http" "strings" @@ -22,6 +23,7 @@ import ( bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" + "github.com/primevprotocol/mev-commit/pkg/allowancemanager" "github.com/primevprotocol/mev-commit/pkg/apiserver" bidder_registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/bidder_registry" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" @@ -241,7 +243,8 @@ func NewNode(opts *Options) (*Node, error) { } var ( - bidProcessor preconfirmation.BidProcessor = noOpBidProcessor{} + bidProcessor preconfirmation.BidProcessor = noOpBidProcessor{} + allowanceMgr preconfirmation.AllowanceManager = noOpAllowanceManager{} ) blockTrackerAddr := common.HexToAddress(opts.BlockTrackerContract) @@ -273,17 +276,22 @@ func NewNode(opts *Options) (*Node, error) { validator, ) providerapiv1.RegisterProviderServer(grpcServer, providerAPI) - opts.Logger.Info("registered provider api") bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) - opts.Logger.Info("registered provider api metrics") - + allowanceMgr = allowancemanager.NewAllowanceManager(bidderRegistry, + blockTracker, + commitmentDA, + store, + evtMgr, + opts.Logger.With("component", "allowancemanager"), + ) + allowanceMgr.Start(ctx) preconfProto := preconfirmation.New( keyKeeper.GetAddress(), topo, p2pSvc, preconfEncryptor, - bidderRegistry, + allowanceMgr, bidProcessor, commitmentDA, blockTracker, @@ -291,13 +299,11 @@ func NewNode(opts *Options) (*Node, error) { store, opts.Logger.With("component", "preconfirmation_protocol"), ) - opts.Logger.Info("registered preconfirmation protocol") preconfProtoClosed = preconfProto.Start(ctx) // Only register handler for provider p2pSvc.AddStreamHandlers(preconfProto.Streams()...) - opts.Logger.Info("registered stream handlers") keyexchange := keyexchange.New( topo, p2pSvc, @@ -305,10 +311,8 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "keyexchange_protocol"), signer.New(), ) - opts.Logger.Info("registered keyexchange protocol") p2pSvc.AddStreamHandlers(keyexchange.Streams()...) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) - opts.Logger.Info("registered metrics collectors") case p2p.PeerTypeBidder.String(): preconfProto := preconfirmation.New( @@ -316,7 +320,7 @@ func NewNode(opts *Options) (*Node, error) { topo, p2pSvc, preconfEncryptor, - bidderRegistry, + allowanceMgr, bidProcessor, commitmentDA, blockTracker, @@ -542,3 +546,13 @@ func (noOpBidProcessor) ProcessBid( return statusC, nil } + +type noOpAllowanceManager struct{} + +func (noOpAllowanceManager) Start(_ context.Context) <-chan struct{} { + return nil +} + +func (noOpAllowanceManager) CheckAllowance(_ context.Context, _ common.Address, _ *big.Int) error { + return nil +} diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index c68fc3b8..fb3cc6ae 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -28,7 +28,7 @@ import ( const ( ProtocolName = "preconfirmation" - ProtocolVersion = "1.0.0" + ProtocolVersion = "3.0.0" ) type Preconfirmation struct { @@ -36,7 +36,7 @@ type Preconfirmation struct { encryptor encryptor.Encryptor topo Topology streamer p2p.Streamer - us BidderStore + allowanceMgr AllowanceManager processer BidProcessor commitmentDA preconfcontract.Interface blockTracker blocktrackercontract.Interface @@ -50,10 +50,6 @@ type Topology interface { GetPeers(topology.Query) []p2p.Peer } -type BidderStore interface { - CheckBidderAllowance(context.Context, common.Address, *big.Int, *big.Int) bool -} - type BidProcessor interface { ProcessBid(context.Context, *preconfpb.Bid) (chan providerapiv1.BidResponse_Status, error) } @@ -65,12 +61,18 @@ type EncrDecrCommitmentStore interface { DeleteCommitmentByBlockNumber(blockNum int64) error } +type AllowanceManager interface { + Start(ctx context.Context) <-chan struct{} + CheckAllowance(ctx context.Context, ethAddress common.Address, window *big.Int) error +} + func New( owner common.Address, topo Topology, streamer p2p.Streamer, encryptor encryptor.Encryptor, - us BidderStore, + // us BidderStore, + allowanceMgr AllowanceManager, processor BidProcessor, commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, @@ -79,11 +81,12 @@ func New( logger *slog.Logger, ) *Preconfirmation { return &Preconfirmation{ - owner: owner, - topo: topo, - streamer: streamer, - encryptor: encryptor, - us: us, + owner: owner, + topo: topo, + streamer: streamer, + encryptor: encryptor, + // us: us, + allowanceMgr: allowanceMgr, processer: processor, commitmentDA: commitmentDA, blockTracker: blockTracker, @@ -268,23 +271,18 @@ func (p *Preconfirmation) handleBid( return err } + // todo: move to the event listening to allowance manager window, err := p.blockTracker.GetCurrentWindow(ctx) if err != nil { p.logger.Error("getting window", "error", err) return status.Errorf(codes.Internal, "failed to get window: %v", err) } - blocksPerWindow, err := p.blockTracker.GetBlocksPerWindow(ctx) + err = p.allowanceMgr.CheckAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window)) if err != nil { - p.logger.Error("getting blocks per window", "error", err) - return status.Errorf(codes.Internal, "failed to get blocks per window: %v", err) - } - - if !p.us.CheckBidderAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window), new(big.Int).SetUint64(blocksPerWindow)) { - p.logger.Error("bidder does not have enough allowance", "ethAddress", ethAddress) - return status.Errorf(codes.FailedPrecondition, "bidder not allowed") + p.logger.Error("checking allowance", "error", err) + return err } - // try to enqueue for 5 seconds ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 1c6e6247..5bda0bed 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -204,6 +204,16 @@ func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { return slog.New(testLogger) } +type testAllowanceManager struct{} + +func (t *testAllowanceManager) Start(ctx context.Context) <-chan struct{} { + return nil +} + +func (t *testAllowanceManager) CheckAllowance(ctx context.Context, address common.Address, window *big.Int) error { + return nil +} + func TestPreconfBidSubmission(t *testing.T) { t.Parallel() @@ -261,7 +271,6 @@ func TestPreconfBidSubmission(t *testing.T) { ) topo := &testTopo{server} - us := &testBidderStore{} proc := &testProcessor{ status: providerapiv1.BidResponse_STATUS_ACCEPTED, } @@ -285,12 +294,13 @@ func TestPreconfBidSubmission(t *testing.T) { handlerSub: make(chan struct{}), } + allowanceMgr := &testAllowanceManager{} p := preconfirmation.New( client.EthAddress, topo, svc, signer, - us, + allowanceMgr, proc, &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, diff --git a/pkg/store/store.go b/pkg/store/store.go index fd27cf14..0e663967 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -1,6 +1,7 @@ package store import ( + "math/big" "sync" "github.com/ethereum/go-ethereum/common" @@ -8,12 +9,21 @@ import ( ) type Store struct { - data map[string]uint64 + *BlockStore + *CommitmentsStore + *BidderBalancesStore +} + +type BlockStore struct { + data map[string]uint64 + mu sync.RWMutex +} + +type CommitmentsStore struct { commitmentsByBlockNumber map[int64][]*EncryptedPreConfirmationWithDecrypted commitmentsByCommitmentHash map[string]*EncryptedPreConfirmationWithDecrypted commitmentByBlockNumberMu sync.RWMutex commitmentsByCommitmentHashMu sync.RWMutex - mu sync.RWMutex } type EncryptedPreConfirmationWithDecrypted struct { @@ -23,87 +33,118 @@ type EncryptedPreConfirmationWithDecrypted struct { func NewStore() *Store { return &Store{ - data: make(map[string]uint64), - commitmentsByBlockNumber: make(map[int64][]*EncryptedPreConfirmationWithDecrypted), - commitmentsByCommitmentHash: make(map[string]*EncryptedPreConfirmationWithDecrypted), + BlockStore: &BlockStore{ + data: make(map[string]uint64), + }, + CommitmentsStore: &CommitmentsStore{ + commitmentsByBlockNumber: make(map[int64][]*EncryptedPreConfirmationWithDecrypted), + commitmentsByCommitmentHash: make(map[string]*EncryptedPreConfirmationWithDecrypted), + }, } } -func (s *Store) LastBlock() (uint64, error) { - s.mu.RLock() - defer s.mu.RUnlock() +func (bs *BlockStore) LastBlock() (uint64, error) { + bs.mu.RLock() + defer bs.mu.RUnlock() - if value, exists := s.data["last_block"]; exists { + if value, exists := bs.data["last_block"]; exists { return value, nil } return 0, nil } -func (s *Store) SetLastBlock(blockNum uint64) error { - s.mu.Lock() - defer s.mu.Unlock() +func (bs *BlockStore) SetLastBlock(blockNum uint64) error { + bs.mu.Lock() + defer bs.mu.Unlock() - s.data["last_block"] = blockNum + bs.data["last_block"] = blockNum return nil } -func (s *Store) addCommitmentByBlockNumber(blockNum int64, commitment *EncryptedPreConfirmationWithDecrypted) { - s.commitmentByBlockNumberMu.Lock() - defer s.commitmentByBlockNumberMu.Unlock() +func (cs *CommitmentsStore) addCommitmentByBlockNumber(blockNum int64, commitment *EncryptedPreConfirmationWithDecrypted) { + cs.commitmentByBlockNumberMu.Lock() + defer cs.commitmentByBlockNumberMu.Unlock() - s.commitmentsByBlockNumber[blockNum] = append(s.commitmentsByBlockNumber[blockNum], commitment) + cs.commitmentsByBlockNumber[blockNum] = append(cs.commitmentsByBlockNumber[blockNum], commitment) } -func (s *Store) addCommitmentByHash(hash string, commitment *EncryptedPreConfirmationWithDecrypted) { - s.commitmentsByCommitmentHashMu.Lock() - defer s.commitmentsByCommitmentHashMu.Unlock() +func (cs *CommitmentsStore) addCommitmentByHash(hash string, commitment *EncryptedPreConfirmationWithDecrypted) { + cs.commitmentsByCommitmentHashMu.Lock() + defer cs.commitmentsByCommitmentHashMu.Unlock() - s.commitmentsByCommitmentHash[hash] = commitment + cs.commitmentsByCommitmentHash[hash] = commitment } -func (s *Store) AddCommitment(commitment *EncryptedPreConfirmationWithDecrypted) { - s.addCommitmentByBlockNumber(commitment.Bid.BlockNumber, commitment) - s.addCommitmentByHash(common.Bytes2Hex(commitment.Commitment), commitment) +func (cs *CommitmentsStore) AddCommitment(commitment *EncryptedPreConfirmationWithDecrypted) { + cs.addCommitmentByBlockNumber(commitment.Bid.BlockNumber, commitment) + cs.addCommitmentByHash(common.Bytes2Hex(commitment.Commitment), commitment) } -func (s *Store) GetCommitmentsByBlockNumber(blockNum int64) ([]*EncryptedPreConfirmationWithDecrypted, error) { - s.commitmentByBlockNumberMu.RLock() - defer s.commitmentByBlockNumberMu.RUnlock() +func (cs *CommitmentsStore) GetCommitmentsByBlockNumber(blockNum int64) ([]*EncryptedPreConfirmationWithDecrypted, error) { + cs.commitmentByBlockNumberMu.RLock() + defer cs.commitmentByBlockNumberMu.RUnlock() - if commitments, exists := s.commitmentsByBlockNumber[blockNum]; exists { + if commitments, exists := cs.commitmentsByBlockNumber[blockNum]; exists { return commitments, nil } return nil, nil } -func (s *Store) GetCommitmentByHash(hash string) (*EncryptedPreConfirmationWithDecrypted, error) { - s.commitmentsByCommitmentHashMu.RLock() - defer s.commitmentsByCommitmentHashMu.RUnlock() +func (cs *CommitmentsStore) GetCommitmentByHash(hash string) (*EncryptedPreConfirmationWithDecrypted, error) { + cs.commitmentsByCommitmentHashMu.RLock() + defer cs.commitmentsByCommitmentHashMu.RUnlock() - if commitment, exists := s.commitmentsByCommitmentHash[hash]; exists { + if commitment, exists := cs.commitmentsByCommitmentHash[hash]; exists { return commitment, nil } return nil, nil } -func (s *Store) DeleteCommitmentByBlockNumber(blockNum int64) error { - s.commitmentByBlockNumberMu.Lock() - defer s.commitmentByBlockNumberMu.Unlock() +func (cs *CommitmentsStore) DeleteCommitmentByBlockNumber(blockNum int64) error { + cs.commitmentByBlockNumberMu.Lock() + defer cs.commitmentByBlockNumberMu.Unlock() - for _, v := range s.commitmentsByBlockNumber[blockNum] { - err := s.deleteCommitmentByHash(common.Bytes2Hex(v.Commitment)) + for _, v := range cs.commitmentsByBlockNumber[blockNum] { + err := cs.deleteCommitmentByHash(common.Bytes2Hex(v.Commitment)) if err != nil { return err } } - delete(s.commitmentsByBlockNumber, blockNum) + delete(cs.commitmentsByBlockNumber, blockNum) + return nil +} + +func (cs *CommitmentsStore) deleteCommitmentByHash(hash string) error { + cs.commitmentsByCommitmentHashMu.Lock() + defer cs.commitmentsByCommitmentHashMu.Unlock() + + delete(cs.commitmentsByCommitmentHash, hash) return nil } -func (s *Store) deleteCommitmentByHash(hash string) error { - s.commitmentsByCommitmentHashMu.Lock() - defer s.commitmentsByCommitmentHashMu.Unlock() +type BidderBalancesStore struct { + balances map[string]*big.Int + mu sync.RWMutex +} - delete(s.commitmentsByCommitmentHash, hash) +func (bbs *BidderBalancesStore) SetBalance(bidder common.Address, windowNumber *big.Int, prepaidAmount *big.Int) error { + bbs.mu.Lock() + defer bbs.mu.Unlock() + bssKey := getBBSKey(bidder, windowNumber) + bbs.balances[bssKey] = prepaidAmount return nil } + +func (bbs *BidderBalancesStore) GetBalance(bidder common.Address, windowNumber *big.Int) (*big.Int, error) { + bbs.mu.RLock() + defer bbs.mu.RUnlock() + bssKey := getBBSKey(bidder, windowNumber) + if balance, exists := bbs.balances[bssKey]; exists { + return balance, nil + } + return nil, nil +} + +func getBBSKey(bidder common.Address, windowNumber *big.Int) string { + return bidder.String() + windowNumber.String() +} \ No newline at end of file From 49f4e9270d4253856c51e24680c7fff7cb98c455 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 17:55:10 +0200 Subject: [PATCH 67/85] fixed lint --- pkg/preconfirmation/preconfirmation_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 5bda0bed..0afe86b6 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -38,12 +38,6 @@ func (t *testTopo) GetPeers(q topology.Query) []p2p.Peer { return []p2p.Peer{t.peer} } -type testBidderStore struct{} - -func (t *testBidderStore) CheckBidderAllowance(_ context.Context, _ common.Address, _ *big.Int, _ *big.Int) bool { - return true -} - type testEncryptor struct { bidHash []byte encryptedBid *preconfpb.EncryptedBid From 8ac8f4b181c6338614ca6d480716fe3ecda9033a Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 18:16:28 +0200 Subject: [PATCH 68/85] added missed store init --- pkg/store/store.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/store/store.go b/pkg/store/store.go index 0e663967..839255ba 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -40,6 +40,9 @@ func NewStore() *Store { commitmentsByBlockNumber: make(map[int64][]*EncryptedPreConfirmationWithDecrypted), commitmentsByCommitmentHash: make(map[string]*EncryptedPreConfirmationWithDecrypted), }, + BidderBalancesStore: &BidderBalancesStore{ + balances: make(map[string]*big.Int), + }, } } From 29be10544b533a7e8945c05a9e50219c7f59527e Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 18:47:11 +0200 Subject: [PATCH 69/85] fixed npe --- pkg/allowancemanager/allowance.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/allowancemanager/allowance.go b/pkg/allowancemanager/allowance.go index 301e2fb9..152d2519 100644 --- a/pkg/allowancemanager/allowance.go +++ b/pkg/allowancemanager/allowance.go @@ -100,6 +100,11 @@ func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Ad return status.Errorf(codes.Internal, "failed to get balance: %v", err) } + if balance == nil { + a.logger.Error("bidder balance not found", "address", address.Hex(), "window", window) + return status.Errorf(codes.FailedPrecondition, "balance not found") + } + a.logger.Info("checking bidder allowance", "stake", balance.Uint64(), "blocksPerWindow", a.blocksPerWindow, @@ -107,7 +112,7 @@ func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Ad "window", window.Uint64(), "address", address.Hex(), ) - + isEnoughAllowance := (balance.Div(balance, a.blocksPerWindow)).Cmp(a.minAllowance) >= 0 if !isEnoughAllowance { From 854d3d57625ef6f8fea7ef89d5a6b9cc23615580 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 19:25:21 +0200 Subject: [PATCH 70/85] fixed missing api --- pkg/node/node.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/node/node.go b/pkg/node/node.go index fd2d2736..5b0bdf5a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + bidderregistry "github.com/primevprotocol/contracts-abi/clients/BidderRegistry" blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" preconf "github.com/primevprotocol/contracts-abi/clients/PreConfCommitmentStore" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" @@ -512,6 +513,12 @@ func getContractABIs(opts *Options) (map[common.Address]*abi.ABI, error) { } abis[common.HexToAddress(opts.PreconfContract)] = &pcABI + brABI, err := abi.JSON(strings.NewReader(bidderregistry.BidderregistryABI)) + if err != nil { + return nil, err + } + abis[common.HexToAddress(opts.BidderRegistryContract)] = &brABI + return abis, nil } From 1d79dceb599dc3420c8f773c3d1b2aabf4fbbf0e Mon Sep 17 00:00:00 2001 From: Mikelle Date: Thu, 18 Apr 2024 21:22:45 +0200 Subject: [PATCH 71/85] added owner set up to bidder struct --- go.mod | 2 +- go.sum | 2 ++ pkg/contracts/bidder_registry/bidder_registry.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 101e3c32..6804852b 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad + github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8 github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index e000a57e..1ade3f53 100644 --- a/go.sum +++ b/go.sum @@ -346,6 +346,8 @@ github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a h1: github.com/primevprotocol/contracts-abi v0.2.4-0.20240401131709-dcd3b451314a/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad h1:Gvv4EwVerh4gpBBT4uU7gMHhuSGwFnXDZUQxsxWQ0ls= github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8 h1:XGHghC8zN/3neOpP7TWndrtgcLI1Vu2vU0PQFCQSjrM= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index dd4b0cf6..5d3d1035 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -49,6 +49,7 @@ func New( logger *slog.Logger, ) Interface { return &bidderRegistryContract{ + owner: owner, bidderRegistryABI: bidderRegistryABI(), bidderRegistryContractAddr: bidderRegistryContractAddr, client: client, From 6d0a594a7a8db6ce4a0d5a34685ba9c3f4991248 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 19 Apr 2024 18:33:02 +0200 Subject: [PATCH 72/85] updated prepay function --- go.mod | 2 +- go.sum | 2 + .../bidder_registry/bidder_registry.go | 8 +- .../bidder_registry/bidder_registry_test.go | 6 +- pkg/contracts/block_tracker/block_tracker.go | 154 ------------------ pkg/preconfirmation/preconfirmation_test.go | 14 -- pkg/rpc/bidder/service.go | 12 +- pkg/rpc/bidder/service_test.go | 26 +-- 8 files changed, 18 insertions(+), 206 deletions(-) diff --git a/go.mod b/go.mod index 6804852b..a092a297 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8 + github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60 github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index 1ade3f53..516afc55 100644 --- a/go.sum +++ b/go.sum @@ -348,6 +348,8 @@ github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad h1: github.com/primevprotocol/contracts-abi v0.2.4-0.20240410153636-21ff37a788ad/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8 h1:XGHghC8zN/3neOpP7TWndrtgcLI1Vu2vU0PQFCQSjrM= github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60 h1:FEYkczFrI/CwTZRm0wARuWshpn185BEw4uFAKxlqQBg= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 5d3d1035..2eacd1cf 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -22,8 +22,8 @@ var bidderRegistryABI = func() abi.ABI { } type Interface interface { - // PrepayAllowance registers a bidder with the bidder_registry contract. - PrepayAllowance(ctx context.Context, amount *big.Int) error + // PrepayAllowanceForSpecificWindow registers a bidder with the bidder_registry contract for a specific window. + PrepayAllowanceForSpecificWindow(ctx context.Context, window *big.Int, amount *big.Int) error // GetAllowance returns the stake of a bidder. GetAllowance(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) // GetMinAllowance returns the minimum stake required to register as a bidder. @@ -57,8 +57,8 @@ func New( } } -func (r *bidderRegistryContract) PrepayAllowance(ctx context.Context, amount *big.Int) error { - callData, err := r.bidderRegistryABI.Pack("prepay") +func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, window *big.Int, amount *big.Int) error { + callData, err := r.bidderRegistryABI.Pack("prepayAllowanceForSpecificWindow", window) if err != nil { r.logger.Error("error packing call data", "error", err) return err diff --git a/pkg/contracts/bidder_registry/bidder_registry_test.go b/pkg/contracts/bidder_registry/bidder_registry_test.go index dc0e54d6..70518bad 100644 --- a/pkg/contracts/bidder_registry/bidder_registry_test.go +++ b/pkg/contracts/bidder_registry/bidder_registry_test.go @@ -24,8 +24,9 @@ func TestBidderRegistryContract(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") txHash := common.HexToHash("abcdef") amount := big.NewInt(1000000000000000000) + window := big.NewInt(1) - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("prepay") + expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("prepayAllowanceForSpecificWindow", window) if err != nil { t.Fatal(err) } @@ -73,8 +74,7 @@ func TestBidderRegistryContract(t *testing.T) { mockClient, util.NewTestLogger(os.Stdout), ) - - err = registryContract.PrepayAllowance(context.Background(), amount) + err = registryContract.PrepayAllowanceForSpecificWindow(context.Background(), big.NewInt(1), amount) if err != nil { t.Fatal(err) } diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 2c0adf61..16ff3e4f 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -7,10 +7,8 @@ import ( "math/big" "strings" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" "github.com/primevprotocol/mev-commit/pkg/evmclient" ) @@ -24,24 +22,16 @@ var blockTrackerABI = func() abi.ABI { }() type Interface interface { - // RecordL1Block records a new L1 block and its winner. - RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error // GetLastL1BlockNumber returns the number of the last L1 block recorded. GetLastL1BlockNumber(ctx context.Context) (uint64, error) // GetLastL1BlockWinner returns the winner of the last L1 block recorded. GetLastL1BlockWinner(ctx context.Context) (common.Address, error) // GetBlocksPerWindow returns the number of blocks per window. GetBlocksPerWindow(ctx context.Context) (uint64, error) - // SetBlocksPerWindow sets the number of blocks per window. - SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error // GetCurrentWindow returns the current window number. GetCurrentWindow(ctx context.Context) (uint64, error) // GetBlockWinner returns the winner of a specific block. GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) - // SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. - SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) - // PollNewL1BlockEvents polls for NewL1Block events and sends them to the event channel. - // PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error } type blockTrackerContract struct { @@ -73,36 +63,6 @@ func New( } } -// RecordL1Block records a new L1 block and its winner. -func (btc *blockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { - callData, err := btc.blockTrackerABI.Pack("recordL1Block", new(big.Int).SetUint64(blockNumber), winner) - if err != nil { - btc.logger.Error("error packing call data for recordL1Block", "error", err) - return err - } - - txnHash, err := btc.client.Send(ctx, &evmclient.TxRequest{ - To: &btc.blockTrackerContractAddr, - CallData: callData, - }) - if err != nil { - return err - } - - receipt, err := btc.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return err - } - - if receipt.Status != types.ReceiptStatusSuccessful { - btc.logger.Error("recordL1Block transaction failed", "txnHash", txnHash, "receipt", receipt) - return err - } - - btc.logger.Info("recordL1Block transaction successful", "txnHash", txnHash) - return nil -} - // GetLastL1BlockNumber returns the number of the last L1 block recorded. func (btc *blockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { callData, err := btc.blockTrackerABI.Pack("getLastL1BlockNumber") @@ -193,35 +153,6 @@ func (btc *blockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64 return blocksPerWindow.Uint64(), nil } -// SetBlocksPerWindow sets the number of blocks per window. -func (btc *blockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { - callData, err := btc.blockTrackerABI.Pack("setBlocksPerWindow", new(big.Int).SetUint64(blocksPerWindow)) - if err != nil { - btc.logger.Error("error packing call data for setBlocksPerWindow", "error", err) - return err - } - - txnHash, err := btc.client.Send(ctx, &evmclient.TxRequest{ - To: &btc.blockTrackerContractAddr, - CallData: callData, - }) - if err != nil { - return err - } - - receipt, err := btc.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return err - } - - if receipt.Status != types.ReceiptStatusSuccessful { - btc.logger.Error("setBlocksPerWindow transaction failed", "txnHash", txnHash, "receipt", receipt) - return fmt.Errorf("transaction failed with hash: %s", txnHash.Hex()) - } - - return nil -} - // GetCurrentWindow returns the current window number. func (btc *blockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { callData, err := btc.blockTrackerABI.Pack("getCurrentWindow") @@ -281,88 +212,3 @@ func (btc *blockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber return winnerAddress, nil } - -// SubscribeNewL1Block subscribes to the NewL1Block events emitted by the contract. -func (btc *blockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- NewL1BlockEvent) (ethereum.Subscription, error) { - query := ethereum.FilterQuery{ - Addresses: []common.Address{btc.blockTrackerContractAddr}, - Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, - } - - logsCh := make(chan types.Log) - sub, err := btc.wsClient.SubscribeFilterLogs(ctx, query, logsCh) - if err != nil { - return nil, err - } - - go func() { - for { - select { - case log := <-logsCh: - event := NewL1BlockEvent{} - err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) - if err != nil { - btc.logger.Error("error unpacking NewL1Block event", "error", err) - continue - } - event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) - event.Winner = common.HexToAddress(log.Topics[2].Hex()) - event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) - eventCh <- event - case <-ctx.Done(): - sub.Unsubscribe() - return - } - } - }() - - return sub, nil -} - -// func (btc *blockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- NewL1BlockEvent, pollInterval time.Duration) error { -// ticker := time.NewTicker(pollInterval) -// defer ticker.Stop() - -// startBlock := uint64(0) // todo: take this variable from config - -// for { -// select { -// case <-ticker.C: -// // Update the query to search for events from startBlock to the latest block -// query := ethereum.FilterQuery{ -// FromBlock: big.NewInt(int64(startBlock)), -// Addresses: []common.Address{btc.blockTrackerContractAddr}, -// Topics: [][]common.Hash{{blockTrackerABI.Events["NewL1Block"].ID}}, -// } - -// logs, err := btc.client.FilterLogs(ctx, query) -// if err != nil { -// btc.logger.Error("error filtering NewL1Block events", "error", err) -// continue -// } - -// for _, log := range logs { -// event := NewL1BlockEvent{} -// err := blockTrackerABI.UnpackIntoInterface(&event, "NewL1Block", log.Data) -// if err != nil { -// btc.logger.Error("error unpacking NewL1Block event", "error", err) -// continue -// } -// event.BlockNumber = new(big.Int).SetBytes(log.Topics[1].Bytes()) -// event.Winner = common.HexToAddress(log.Topics[2].Hex()) -// event.Window = new(big.Int).SetBytes(log.Topics[3].Bytes()) - -// eventCh <- event -// } - -// // Update startBlock for the next query to start from the latest checked block -// if len(logs) > 0 { -// lastLog := logs[len(logs)-1] -// startBlock = lastLog.BlockNumber + 1 -// } - -// case <-ctx.Done(): -// return ctx.Err() -// } -// } -// } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 0afe86b6..5ec0b55e 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -121,14 +121,6 @@ type testBlockTrackerContract struct { blocksPerWindow uint64 } -// RecordBlock records a new block and its winner. -func (btc *testBlockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { - btc.lastBlockNumber = blockNumber - btc.lastBlockWinner = winner - btc.blockNumberToWinner[blockNumber] = winner - return nil -} - func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { return btc.blockNumberToWinner[blockNumber], nil } @@ -146,12 +138,6 @@ func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) ( return btc.lastBlockNumber, nil } -// SetBlocksPerWindow sets the number of blocks per window. -func (btc *testBlockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { - btc.blocksPerWindow = blocksPerWindow - return nil -} - // GetBlocksPerWindow returns the number of blocks per window. func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { return btc.blocksPerWindow, nil diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 24def954..9701b5f3 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -123,7 +123,9 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "getting current window: %v", err) } - if _, ok := s.depositedWindows[new(big.Int).SetUint64(currentWindow+1)]; ok { + nextWindow := new(big.Int).SetUint64(currentWindow + 1) + + if _, ok := s.depositedWindows[nextWindow]; ok { return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", currentWindow+1) } @@ -143,18 +145,18 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", stake.Amount) } - err = s.registryContract.PrepayAllowance(ctx, amount) + err = s.registryContract.PrepayAllowanceForSpecificWindow(ctx, amount, nextWindow) if err != nil { return nil, status.Errorf(codes.Internal, "prepaying allowance: %v", err) } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, new(big.Int).SetUint64(currentWindow+1)) + stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, nextWindow) if err != nil { return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } - s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", currentWindow+1) - s.depositedWindows[new(big.Int).SetUint64(currentWindow+1)] = struct{}{} + s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", nextWindow) + s.depositedWindows[nextWindow] = struct{}{} return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil } diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 314498ba..70446972 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -12,11 +12,9 @@ import ( "testing" "github.com/bufbuild/protovalidate-go" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" - blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" bidderapi "github.com/primevprotocol/mev-commit/pkg/rpc/bidder" "github.com/primevprotocol/mev-commit/pkg/util" "google.golang.org/grpc" @@ -82,7 +80,7 @@ type testRegistryContract struct { minAllowance *big.Int } -func (t *testRegistryContract) PrepayAllowance(ctx context.Context, amount *big.Int) error { +func (t *testRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, amount *big.Int, window *big.Int) error { t.allowance = amount return nil } @@ -110,14 +108,6 @@ type testBlockTrackerContract struct { blocksPerWindow uint64 } -// RecordBlock records a new block and its winner. -func (btc *testBlockTrackerContract) RecordL1Block(ctx context.Context, blockNumber uint64, winner common.Address) error { - btc.lastBlockNumber = blockNumber - btc.lastBlockWinner = winner - btc.blockNumberToWinner[blockNumber] = winner - return nil -} - func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { return btc.blockNumberToWinner[blockNumber], nil } @@ -135,25 +125,11 @@ func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) ( return btc.lastBlockNumber, nil } -// SetBlocksPerWindow sets the number of blocks per window. -func (btc *testBlockTrackerContract) SetBlocksPerWindow(ctx context.Context, blocksPerWindow uint64) error { - btc.blocksPerWindow = blocksPerWindow - return nil -} - // GetBlocksPerWindow returns the number of blocks per window. func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { return btc.blocksPerWindow, nil } -func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent) (ethereum.Subscription, error) { - return nil, nil -} - -// func (btc *testBlockTrackerContract) PollNewL1BlockEvents(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent, pollInterval time.Duration) error { -// return nil -// } - func startServer(t *testing.T) bidderapiv1.BidderClient { lis := bufconn.Listen(bufferSize) From 702caa041c4ae4f77d9e11b61c07362c076df090 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 19 Apr 2024 20:01:42 +0200 Subject: [PATCH 73/85] updated bidder service to allow to prepay for specific windows --- gen/go/bidderapi/v1/bidderapi.pb.go | 582 ++++++++++-------- gen/go/bidderapi/v1/bidderapi.pb.gw.go | 18 + .../bidderapi/v1/bidderapi.swagger.yaml | 10 + pkg/rpc/bidder/service.go | 34 +- rpc/bidderapi/v1/bidderapi.proto | 15 +- 5 files changed, 373 insertions(+), 286 deletions(-) diff --git a/gen/go/bidderapi/v1/bidderapi.pb.go b/gen/go/bidderapi/v1/bidderapi.pb.go index 65119795..ecf88c07 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.go @@ -29,7 +29,8 @@ type PrepayRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,2,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` } func (x *PrepayRequest) Reset() { @@ -71,12 +72,20 @@ func (x *PrepayRequest) GetAmount() string { return "" } +func (x *PrepayRequest) GetWindowNumber() *wrapperspb.UInt64Value { + if x != nil { + return x.WindowNumber + } + return nil +} + type PrepayResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,2,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` } func (x *PrepayResponse) Reset() { @@ -118,6 +127,13 @@ func (x *PrepayResponse) GetAmount() string { return "" } +func (x *PrepayResponse) GetWindowNumber() *wrapperspb.UInt64Value { + if x != nil { + return x.WindowNumber + } + return nil +} + type EmptyMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -415,7 +431,7 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa0, 0x02, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xca, 0x04, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x7a, 0x92, 0x41, 0x2e, 0x32, 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, @@ -425,263 +441,287 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x18, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, - 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x7a, - 0x92, 0x41, 0x77, 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, - 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x9e, 0x01, 0x0a, 0x0e, 0x50, - 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x74, 0x92, 0x41, 0x71, 0x0a, 0x4b, 0x2a, 0x0f, 0x50, 0x72, - 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, - 0x65, 0x74, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x22, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x9e, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, - 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xdb, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, - 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, - 0x65, 0x64, 0x2e, 0xba, 0x48, 0x70, 0xba, 0x01, 0x6d, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, - 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x26, - 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, - 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, - 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, - 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, - 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, - 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, - 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, - 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, - 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, - 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, - 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, - 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, - 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, - 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, - 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, - 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, - 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, - 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, - 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, - 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, - 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, - 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, - 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, - 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, - 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, + 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x92, + 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, + 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, + 0x64, 0xba, 0x01, 0x61, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x3a, 0x8e, 0x01, 0x92, 0x41, 0x8a, 0x01, 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, + 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x35, 0x7b, + 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, + 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, + 0x20, 0x31, 0x20, 0x7d, 0x22, 0xf7, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x40, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x3a, 0x8a, 0x01, 0x92, 0x41, 0x86, 0x01, 0x0a, 0x4b, 0x2a, 0x0f, 0x50, 0x72, 0x65, 0x70, + 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, + 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, + 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x37, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x22, 0x20, 0x7d, 0x22, 0x0e, + 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, + 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, + 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x64, 0xba, 0x01, 0x61, 0x0a, 0x0c, 0x77, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, + 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, + 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, + 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, + 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, + 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, + 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, + 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, + 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, + 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, + 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, + 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, + 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, + 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, + 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, + 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, - 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, - 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, - 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, - 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, + 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, - 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, - 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, - 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, - 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, - 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, - 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, - 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, - 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, - 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, - 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, - 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, - 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, - 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, - 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, - 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, - 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, - 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, - 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, - 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, - 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, - 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, + 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, + 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, + 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, + 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, + 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, + 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, + 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, + 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, + 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, + 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, + 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, + 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, + 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, + 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, + 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, + 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, + 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, + 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, + 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, + 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, + 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, - 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, - 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, - 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, - 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, - 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, - 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, - 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, - 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, - 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, - 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, - 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, - 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, - 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, - 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, - 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, - 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, - 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, - 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, - 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, - 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, - 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, - 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, - 0x69, 0x6e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, - 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, - 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, - 0x7a, 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, - 0x5d, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, - 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, + 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, + 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, + 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, + 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, + 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, + 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, + 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, + 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, + 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, + 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, 0x7a, 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x5d, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, + 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, + 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, + 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, - 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, - 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, - 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, - 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, - 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, + 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, + 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, + 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, + 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -707,20 +747,22 @@ var file_bidderapi_v1_bidderapi_proto_goTypes = []interface{}{ (*wrapperspb.UInt64Value)(nil), // 6: google.protobuf.UInt64Value } var file_bidderapi_v1_bidderapi_proto_depIdxs = []int32{ - 6, // 0: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value - 4, // 1: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid - 0, // 2: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest - 3, // 3: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest - 2, // 4: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage - 5, // 5: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment - 1, // 6: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 7: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 8: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse - 5, // [5:9] is the sub-list for method output_type - 1, // [1:5] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 6, // 0: bidderapi.v1.PrepayRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 1: bidderapi.v1.PrepayResponse.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 2: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 4, // 3: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid + 0, // 4: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest + 3, // 5: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest + 2, // 6: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage + 5, // 7: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment + 1, // 8: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 9: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 10: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse + 7, // [7:11] is the sub-list for method output_type + 3, // [3:7] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_bidderapi_v1_bidderapi_proto_init() } diff --git a/gen/go/bidderapi/v1/bidderapi.pb.gw.go b/gen/go/bidderapi/v1/bidderapi.pb.gw.go index dda15497..b41775cb 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.gw.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.gw.go @@ -52,6 +52,10 @@ func request_Bidder_SendBid_0(ctx context.Context, marshaler runtime.Marshaler, } +var ( + filter_Bidder_PrepayAllowance_0 = &utilities.DoubleArray{Encoding: map[string]int{"amount": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PrepayRequest var metadata runtime.ServerMetadata @@ -73,6 +77,13 @@ func request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runtime.Mar return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "amount", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_PrepayAllowance_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.PrepayAllowance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -99,6 +110,13 @@ func local_request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runti return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "amount", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_PrepayAllowance_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.PrepayAllowance(ctx, &protoReq) return msg, metadata, err diff --git a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml index f3cbaa9f..8596767f 100644 --- a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml +++ b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml @@ -92,6 +92,12 @@ paths: in: path required: true type: string + - name: windowNumber + description: Optional window number for querying allowances. If not specified, the current block number is used. + in: query + required: false + type: string + format: uint64 definitions: bidderapiv1Bid: type: object @@ -192,8 +198,12 @@ definitions: type: object example: amount: "1000000000000000000" + windowNumber: "1" properties: amount: type: string + windowNumber: + type: string + format: uint64 description: Get prepaid allowance for bidder in the bidder registry. title: Prepay response diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 9701b5f3..46e15c45 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -16,6 +16,7 @@ import ( blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/wrapperspb" ) type Service struct { @@ -111,9 +112,9 @@ func (s *Service) SendBid( func (s *Service) PrepayAllowance( ctx context.Context, - stake *bidderapiv1.PrepayRequest, + r *bidderapiv1.PrepayRequest, ) (*bidderapiv1.PrepayResponse, error) { - err := s.validator.Validate(stake) + err := s.validator.Validate(r) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "validating prepay request: %v", err) } @@ -123,14 +124,20 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "getting current window: %v", err) } - nextWindow := new(big.Int).SetUint64(currentWindow + 1) + var windowToDeposit *big.Int + if r.WindowNumber == nil { + // adding +2 as oracle working 2 windows behind the current window + windowToDeposit = new(big.Int).SetUint64(currentWindow + 2) + } else { + windowToDeposit = new(big.Int).SetUint64(r.WindowNumber.Value) + } - if _, ok := s.depositedWindows[nextWindow]; ok { + if _, ok := s.depositedWindows[windowToDeposit]; ok { return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", currentWindow+1) } for window := range s.depositedWindows { - if window.Cmp(new(big.Int).SetUint64(currentWindow-2)) < 0 { + if window.Cmp(new(big.Int).SetUint64(currentWindow)) < 0 { err := s.registryContract.WithdrawAllowance(ctx, window) if err != nil { return nil, status.Errorf(codes.Internal, "withdrawing allowance: %v", err) @@ -140,25 +147,25 @@ func (s *Service) PrepayAllowance( } } - amount, success := big.NewInt(0).SetString(stake.Amount, 10) + amount, success := big.NewInt(0).SetString(r.Amount, 10) if !success { - return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", stake.Amount) + return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", r.Amount) } - err = s.registryContract.PrepayAllowanceForSpecificWindow(ctx, amount, nextWindow) + err = s.registryContract.PrepayAllowanceForSpecificWindow(ctx, amount, windowToDeposit) if err != nil { return nil, status.Errorf(codes.Internal, "prepaying allowance: %v", err) } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, nextWindow) + stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, windowToDeposit) if err != nil { return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) } - s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", nextWindow) - s.depositedWindows[nextWindow] = struct{}{} + s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", windowToDeposit) + s.depositedWindows[windowToDeposit] = struct{}{} - return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil + return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String(), WindowNumber: wrapperspb.UInt64(windowToDeposit.Uint64())}, nil } func (s *Service) GetAllowance( @@ -174,7 +181,8 @@ func (s *Service) GetAllowance( if err != nil { return nil, status.Errorf(codes.Internal, "getting current window: %v", err) } - window++ + // as oracle working 2 windows behind the current window, we add + 2 here + window += 2 } else { window = r.WindowNumber.Value } diff --git a/rpc/bidderapi/v1/bidderapi.proto b/rpc/bidderapi/v1/bidderapi.proto index fa553a11..eabe0c5d 100644 --- a/rpc/bidderapi/v1/bidderapi.proto +++ b/rpc/bidderapi/v1/bidderapi.proto @@ -57,7 +57,7 @@ message PrepayRequest { description: "Prepayment for bids to be issued by the bidder in wei." required: ["amount"] } - example: "{\"amount\": \"1000000000000000000\" }" + example: "{\"amount\": \"1000000000000000000\", \"windowNumber\": 1 }" }; string amount = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "Amount of ETH to be prepaid in wei." @@ -67,6 +67,14 @@ message PrepayRequest { message: "amount must be a valid integer.", expression: "this.matches('^[0-9]+$')" }]; + google.protobuf.UInt64Value windowNumber = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Optional window number for querying allowances. If not specified, the current block number is used." + }, (buf.validate.field).cel = { + id: "windowNumber", + message: "windowNumber must be a positive integer if specified.", + expression: "this == null || (this > 0)" + }]; }; message PrepayResponse { @@ -75,9 +83,10 @@ message PrepayResponse { title: "Prepay response" description: "Get prepaid allowance for bidder in the bidder registry." } - example: "{\"amount\": \"1000000000000000000\" }" + example: "{\"amount\": \"1000000000000000000\", \"windowNumber\": \"1\" }" }; string amount = 1; + google.protobuf.UInt64Value windowNumber = 2; }; message EmptyMessage {}; @@ -89,7 +98,7 @@ message GetAllowanceRequest { }, (buf.validate.field).cel = { id: "windowNumber", message: "windowNumber must be a positive integer if specified.", - expression: "this.value == null || (this.value > 0)" + expression: "this == null || (this > 0)" }]; } From 33d8755e3652156d02a3930fea9317ea87881948 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 19 Apr 2024 20:47:37 +0200 Subject: [PATCH 74/85] changed checkAllowance behavior --- pkg/allowancemanager/allowance.go | 40 ++++++++++++++++++--- pkg/node/node.go | 5 ++- pkg/preconfirmation/preconfirmation.go | 13 ++----- pkg/preconfirmation/preconfirmation_test.go | 3 +- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/pkg/allowancemanager/allowance.go b/pkg/allowancemanager/allowance.go index 152d2519..56403681 100644 --- a/pkg/allowancemanager/allowance.go +++ b/pkg/allowancemanager/allowance.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" bidderregistry "github.com/primevprotocol/contracts-abi/clients/BidderRegistry" + blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" preconfcontract "github.com/primevprotocol/mev-commit/pkg/contracts/preconf" "github.com/primevprotocol/mev-commit/pkg/events" @@ -34,6 +35,7 @@ type AllowanceManager struct { evtMgr events.EventManager blocksPerWindow *big.Int // todo: move to the store minAllowance *big.Int // todo: move to the store + currentWindow *big.Int // todo: move to the store logger *slog.Logger } @@ -64,6 +66,10 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { return a.subscribeBidderRegistered(egCtx) }) + eg.Go(func() error { + return a.subscribeNewWindow(egCtx) + }) + go func() { defer close(doneChan) if err := eg.Wait(); err != nil { @@ -74,7 +80,7 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { return doneChan } -func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Address, window *big.Int) error { +func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Address) error { if a.blocksPerWindow == nil { blocksPerWindow, err := a.blockTracker.GetBlocksPerWindow(ctx) if err != nil { @@ -94,14 +100,17 @@ func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Ad a.minAllowance = minAllowance } - balance, err := a.store.GetBalance(address, window) + // adding 2 to the current window, bcs oracle is 2 windows behind + windowToCheck := new(big.Int).Add(a.currentWindow, big.NewInt(2)) + + balance, err := a.store.GetBalance(address, windowToCheck) if err != nil { a.logger.Error("getting balance", "error", err) return status.Errorf(codes.Internal, "failed to get balance: %v", err) } if balance == nil { - a.logger.Error("bidder balance not found", "address", address.Hex(), "window", window) + a.logger.Error("bidder balance not found", "address", address.Hex(), "window", windowToCheck) return status.Errorf(codes.FailedPrecondition, "balance not found") } @@ -109,7 +118,7 @@ func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Ad "stake", balance.Uint64(), "blocksPerWindow", a.blocksPerWindow, "minStake", a.minAllowance.Uint64(), - "window", window.Uint64(), + "window", windowToCheck.Uint64(), "address", address.Hex(), ) @@ -149,3 +158,26 @@ func (a *AllowanceManager) subscribeBidderRegistered(ctx context.Context) error return fmt.Errorf("error in BidderRegistered event subscription: %w", err) } } + +func (a *AllowanceManager) subscribeNewWindow(ctx context.Context) error { + ev := events.NewEventHandler( + "NewWindow", + func(window *blocktracker.BlocktrackerNewWindow) error { + a.currentWindow = window.Window + return nil + }, + ) + + sub, err := a.evtMgr.Subscribe(ev) + if err != nil { + return fmt.Errorf("failed to subscribe to NewWindow event: %w", err) + } + defer sub.Unsubscribe() + + select { + case <-ctx.Done(): + return nil + case err := <-sub.Err(): + return fmt.Errorf("error in NewWindow event subscription: %w", err) + } +} diff --git a/pkg/node/node.go b/pkg/node/node.go index 5b0bdf5a..b0a7ddec 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "log/slog" - "math/big" "net" "net/http" "strings" @@ -518,7 +517,7 @@ func getContractABIs(opts *Options) (map[common.Address]*abi.ABI, error) { return nil, err } abis[common.HexToAddress(opts.BidderRegistryContract)] = &brABI - + return abis, nil } @@ -560,6 +559,6 @@ func (noOpAllowanceManager) Start(_ context.Context) <-chan struct{} { return nil } -func (noOpAllowanceManager) CheckAllowance(_ context.Context, _ common.Address, _ *big.Int) error { +func (noOpAllowanceManager) CheckAllowance(_ context.Context, _ common.Address) error { return nil } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index fb3cc6ae..95639d29 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "log/slog" - "math/big" "sync" "time" @@ -63,7 +62,7 @@ type EncrDecrCommitmentStore interface { type AllowanceManager interface { Start(ctx context.Context) <-chan struct{} - CheckAllowance(ctx context.Context, ethAddress common.Address, window *big.Int) error + CheckAllowance(ctx context.Context, ethAddress common.Address) error } func New( @@ -71,7 +70,6 @@ func New( topo Topology, streamer p2p.Streamer, encryptor encryptor.Encryptor, - // us BidderStore, allowanceMgr AllowanceManager, processor BidProcessor, commitmentDA preconfcontract.Interface, @@ -271,14 +269,7 @@ func (p *Preconfirmation) handleBid( return err } - // todo: move to the event listening to allowance manager - window, err := p.blockTracker.GetCurrentWindow(ctx) - if err != nil { - p.logger.Error("getting window", "error", err) - return status.Errorf(codes.Internal, "failed to get window: %v", err) - } - - err = p.allowanceMgr.CheckAllowance(ctx, *ethAddress, new(big.Int).SetUint64(window)) + err = p.allowanceMgr.CheckAllowance(ctx, *ethAddress) if err != nil { p.logger.Error("checking allowance", "error", err) return err diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 5ec0b55e..86713361 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -8,7 +8,6 @@ import ( "errors" "io" "log/slog" - "math/big" "os" "strings" "testing" @@ -190,7 +189,7 @@ func (t *testAllowanceManager) Start(ctx context.Context) <-chan struct{} { return nil } -func (t *testAllowanceManager) CheckAllowance(ctx context.Context, address common.Address, window *big.Int) error { +func (t *testAllowanceManager) CheckAllowance(ctx context.Context, address common.Address) error { return nil } From ccea487ff61e5cd9891c86323fc92ebc5d4d28ba Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 19 Apr 2024 21:56:27 +0200 Subject: [PATCH 75/85] deleted redundant methods from block winner --- pkg/contracts/block_tracker/block_tracker.go | 96 -------------------- pkg/preconfirmation/preconfirmation_test.go | 12 --- pkg/rpc/bidder/service_test.go | 13 --- 3 files changed, 121 deletions(-) diff --git a/pkg/contracts/block_tracker/block_tracker.go b/pkg/contracts/block_tracker/block_tracker.go index 16ff3e4f..0d38d633 100644 --- a/pkg/contracts/block_tracker/block_tracker.go +++ b/pkg/contracts/block_tracker/block_tracker.go @@ -22,16 +22,10 @@ var blockTrackerABI = func() abi.ABI { }() type Interface interface { - // GetLastL1BlockNumber returns the number of the last L1 block recorded. - GetLastL1BlockNumber(ctx context.Context) (uint64, error) - // GetLastL1BlockWinner returns the winner of the last L1 block recorded. - GetLastL1BlockWinner(ctx context.Context) (common.Address, error) // GetBlocksPerWindow returns the number of blocks per window. GetBlocksPerWindow(ctx context.Context) (uint64, error) // GetCurrentWindow returns the current window number. GetCurrentWindow(ctx context.Context) (uint64, error) - // GetBlockWinner returns the winner of a specific block. - GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) } type blockTrackerContract struct { @@ -63,66 +57,6 @@ func New( } } -// GetLastL1BlockNumber returns the number of the last L1 block recorded. -func (btc *blockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { - callData, err := btc.blockTrackerABI.Pack("getLastL1BlockNumber") - if err != nil { - btc.logger.Error("error packing call data for getLastL1BlockNumber", "error", err) - return 0, err - } - - result, err := btc.client.Call(ctx, &evmclient.TxRequest{ - To: &btc.blockTrackerContractAddr, - CallData: callData, - }) - if err != nil { - return 0, err - } - - results, err := btc.blockTrackerABI.Unpack("getLastL1BlockNumber", result) - if err != nil { - btc.logger.Error("error unpacking result for getLastL1BlockNumber", "error", err) - return 0, err - } - - lastBlockNumber, ok := results[0].(*big.Int) - if !ok { - return 0, fmt.Errorf("invalid result type") - } - - return lastBlockNumber.Uint64(), nil -} - -// GetLastL1BlockWinner returns the winner of the last L1 block recorded. -func (btc *blockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { - callData, err := btc.blockTrackerABI.Pack("getLastL1BlockWinner") - if err != nil { - btc.logger.Error("error packing call data for getLastL1BlockWinner", "error", err) - return common.Address{}, err - } - - result, err := btc.client.Call(ctx, &evmclient.TxRequest{ - To: &btc.blockTrackerContractAddr, - CallData: callData, - }) - if err != nil { - return common.Address{}, err - } - - results, err := btc.blockTrackerABI.Unpack("getLastL1BlockWinner", result) - if err != nil { - btc.logger.Error("error unpacking result for getLastL1BlockWinner", "error", err) - return common.Address{}, err - } - - winnerAddress, ok := results[0].(common.Address) - if !ok { - return common.Address{}, fmt.Errorf("invalid result type") - } - - return winnerAddress, nil -} - // GetBlocksPerWindow returns the number of blocks per window. func (btc *blockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { callData, err := btc.blockTrackerABI.Pack("getBlocksPerWindow") @@ -182,33 +116,3 @@ func (btc *blockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, return currentWindow.Uint64(), nil } - -// GetBlockWinner returns the winner of a specific block. -func (btc *blockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { - callData, err := btc.blockTrackerABI.Pack("getBlockWinner", new(big.Int).SetUint64(blockNumber)) - if err != nil { - btc.logger.Error("error packing call data for getBlockWinner", "error", err) - return common.Address{}, err - } - - result, err := btc.client.Call(ctx, &evmclient.TxRequest{ - To: &btc.blockTrackerContractAddr, - CallData: callData, - }) - if err != nil { - return common.Address{}, err - } - - results, err := btc.blockTrackerABI.Unpack("getBlockWinner", result) - if err != nil { - btc.logger.Error("error unpacking result for getBlockWinner", "error", err) - return common.Address{}, err - } - - winnerAddress, ok := results[0].(common.Address) - if !ok { - return common.Address{}, fmt.Errorf("invalid result type") - } - - return winnerAddress, nil -} diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 86713361..c85c48d1 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -120,23 +120,11 @@ type testBlockTrackerContract struct { blocksPerWindow uint64 } -func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { - return btc.blockNumberToWinner[blockNumber], nil -} - // GetCurrentWindow returns the current window number. func (btc *testBlockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { return btc.lastBlockNumber / btc.blocksPerWindow, nil } -func (btc *testBlockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { - return btc.lastBlockWinner, nil -} - -func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { - return btc.lastBlockNumber, nil -} - // GetBlocksPerWindow returns the number of blocks per window. func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { return btc.blocksPerWindow, nil diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index 70446972..b9cd89c7 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -104,27 +104,14 @@ func (t *testRegistryContract) WithdrawAllowance(ctx context.Context, window *bi type testBlockTrackerContract struct { blockNumberToWinner map[uint64]common.Address lastBlockNumber uint64 - lastBlockWinner common.Address blocksPerWindow uint64 } -func (btc *testBlockTrackerContract) GetBlockWinner(ctx context.Context, blockNumber uint64) (common.Address, error) { - return btc.blockNumberToWinner[blockNumber], nil -} - // GetCurrentWindow returns the current window number. func (btc *testBlockTrackerContract) GetCurrentWindow(ctx context.Context) (uint64, error) { return btc.lastBlockNumber / btc.blocksPerWindow, nil } -func (btc *testBlockTrackerContract) GetLastL1BlockWinner(ctx context.Context) (common.Address, error) { - return btc.lastBlockWinner, nil -} - -func (btc *testBlockTrackerContract) GetLastL1BlockNumber(ctx context.Context) (uint64, error) { - return btc.lastBlockNumber, nil -} - // GetBlocksPerWindow returns the number of blocks per window. func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (uint64, error) { return btc.blocksPerWindow, nil From 478dae69f6267c109fe0f4aada692e33272eb0fc Mon Sep 17 00:00:00 2001 From: Mikelle Date: Fri, 19 Apr 2024 21:58:45 +0200 Subject: [PATCH 76/85] fixed lint --- pkg/preconfirmation/preconfirmation_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index c85c48d1..90f3b9fa 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -116,7 +116,6 @@ func (t *testCommitmentDA) Close() error { type testBlockTrackerContract struct { blockNumberToWinner map[uint64]common.Address lastBlockNumber uint64 - lastBlockWinner common.Address blocksPerWindow uint64 } From 0459afd25b61642e8da27c347a8e37bbe4abf0c5 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Sun, 21 Apr 2024 22:31:53 +0200 Subject: [PATCH 77/85] updated according to remarks --- pkg/allowancemanager/allowance.go | 142 ++++++------- pkg/events/events.go | 8 +- pkg/events/events_test.go | 13 +- pkg/node/node.go | 21 +- pkg/preconfirmation/preconfirmation.go | 214 +++++++++++--------- pkg/preconfirmation/preconfirmation_test.go | 20 +- pkg/store/store.go | 74 ++++++- 7 files changed, 312 insertions(+), 180 deletions(-) diff --git a/pkg/allowancemanager/allowance.go b/pkg/allowancemanager/allowance.go index 56403681..2036e118 100644 --- a/pkg/allowancemanager/allowance.go +++ b/pkg/allowancemanager/allowance.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "math/big" + "sync/atomic" "github.com/ethereum/go-ethereum/common" bidderregistry "github.com/primevprotocol/contracts-abi/clients/BidderRegistry" @@ -25,6 +26,8 @@ type BidderRegistry interface { type Store interface { GetBalance(bidder common.Address, windowNumber *big.Int) (*big.Int, error) SetBalance(bidder common.Address, windowNumber *big.Int, balance *big.Int) error + DeductAndCheckBalanceForBlock(bidder common.Address, defaultAmount, bidAmount *big.Int, blockNumber int64) (*big.Int, error) + RefundBalanceForBlock(bidder common.Address, amount *big.Int, blockNumber int64) error } type AllowanceManager struct { @@ -33,9 +36,9 @@ type AllowanceManager struct { commitmentDA preconfcontract.Interface store Store evtMgr events.EventManager - blocksPerWindow *big.Int // todo: move to the store - minAllowance *big.Int // todo: move to the store - currentWindow *big.Int // todo: move to the store + blocksPerWindow atomic.Uint64 // todo: move to the store + minAllowance atomic.Int64 // todo: move to the store + currentWindow atomic.Int64 // todo: move to the store logger *slog.Logger } @@ -63,11 +66,42 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { eg, egCtx := errgroup.WithContext(ctx) eg.Go(func() error { - return a.subscribeBidderRegistered(egCtx) - }) + ev1 := events.NewEventHandler( + "NewWindow", + func(window *blocktracker.BlocktrackerNewWindow) error { + a.currentWindow.Store(window.Window.Int64()) + return nil + }, + ) + + sub1, err := a.evtMgr.Subscribe(ev1) + if err != nil { + return fmt.Errorf("failed to subscribe to NewWindow event: %w", err) + } + defer sub1.Unsubscribe() - eg.Go(func() error { - return a.subscribeNewWindow(egCtx) + ev2 := events.NewEventHandler( + "BidderRegistered", + func(bidderReg *bidderregistry.BidderregistryBidderRegistered) error { + // todo: do we need to check if commiter is connected to this bidder? + return a.store.SetBalance(bidderReg.Bidder, bidderReg.WindowNumber, bidderReg.PrepaidAmount) + }, + ) + + sub2, err := a.evtMgr.Subscribe(ev2) + if err != nil { + return fmt.Errorf("failed to subscribe to BidderRegistered event: %w", err) + } + defer sub2.Unsubscribe() + + select { + case <-egCtx.Done(): + return nil + case err := <-sub1.Err(): + return fmt.Errorf("error in NewWindow event subscription: %w", err) + case err := <-sub2.Err(): + return fmt.Errorf("error in BidderRegistered event subscription: %w", err) + } }) go func() { @@ -80,104 +114,76 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { return doneChan } -func (a *AllowanceManager) CheckAllowance(ctx context.Context, address common.Address) error { - if a.blocksPerWindow == nil { +func (a *AllowanceManager) CheckAndDeductAllowance(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { + if a.blocksPerWindow.Load() == 0 { blocksPerWindow, err := a.blockTracker.GetBlocksPerWindow(ctx) if err != nil { a.logger.Error("getting blocks per window", "error", err) - return status.Errorf(codes.Internal, "failed to get blocks per window: %v", err) + return nil, status.Errorf(codes.Internal, "failed to get blocks per window: %v", err) } - a.blocksPerWindow = new(big.Int).SetUint64(blocksPerWindow) + a.blocksPerWindow.Store(blocksPerWindow) } - if a.minAllowance == nil { + if a.minAllowance.Load() == 0 { minAllowance, err := a.bidderRegistry.GetMinAllowance(ctx) if err != nil { a.logger.Error("getting min allowance", "error", err) - return status.Errorf(codes.Internal, "failed to get min allowance: %v", err) + return nil, status.Errorf(codes.Internal, "failed to get min allowance: %v", err) } - a.minAllowance = minAllowance + a.minAllowance.Store(minAllowance.Int64()) + } + + bidAmount, ok := new(big.Int).SetString(bidAmountStr, 10) + if !ok { + a.logger.Error("parsing bid amount", "amount", bidAmountStr) + return nil, status.Errorf(codes.InvalidArgument, "failed to parse bid amount") } // adding 2 to the current window, bcs oracle is 2 windows behind - windowToCheck := new(big.Int).Add(a.currentWindow, big.NewInt(2)) + windowToCheck := big.NewInt(a.currentWindow.Load() + 2) balance, err := a.store.GetBalance(address, windowToCheck) if err != nil { a.logger.Error("getting balance", "error", err) - return status.Errorf(codes.Internal, "failed to get balance: %v", err) + return nil, status.Errorf(codes.Internal, "failed to get balance: %v", err) } if balance == nil { a.logger.Error("bidder balance not found", "address", address.Hex(), "window", windowToCheck) - return status.Errorf(codes.FailedPrecondition, "balance not found") + return nil, status.Errorf(codes.FailedPrecondition, "balance not found") } a.logger.Info("checking bidder allowance", "stake", balance.Uint64(), - "blocksPerWindow", a.blocksPerWindow, - "minStake", a.minAllowance.Uint64(), + "blocksPerWindow", a.blocksPerWindow.Load(), + "minStake", a.minAllowance.Load(), "window", windowToCheck.Uint64(), "address", address.Hex(), ) - isEnoughAllowance := (balance.Div(balance, a.blocksPerWindow)).Cmp(a.minAllowance) >= 0 + blocksPerWindow := new(big.Int).SetUint64(a.blocksPerWindow.Load()) + minAllowance := big.NewInt(a.minAllowance.Load()) + + // todo: make sense to do division only once, when bidder deposit funds, + // not everytime, when checking allowance + effectiveStake := new(big.Int).Div(new(big.Int).Set(balance), blocksPerWindow) + + isEnoughAllowance := effectiveStake.Cmp(minAllowance) >= 0 if !isEnoughAllowance { a.logger.Error("bidder does not have enough allowance", "ethAddress", address) - return status.Errorf(codes.FailedPrecondition, "bidder not allowed") + return nil, status.Errorf(codes.FailedPrecondition, "bidder not allowed") } - return nil -} - -func (a *AllowanceManager) subscribeBidderRegistered(ctx context.Context) error { - ev := events.NewEventHandler( - "BidderRegistered", - func(bidderReg *bidderregistry.BidderregistryBidderRegistered) error { - // todo: do we need to check if commiter is connected to this bidder? - err := a.store.SetBalance(bidderReg.Bidder, bidderReg.WindowNumber, bidderReg.PrepaidAmount) - if err != nil { - return err - } - return nil - }, - ) - - sub, err := a.evtMgr.Subscribe(ev) + deductedBalance, err := a.store.DeductAndCheckBalanceForBlock(address, effectiveStake, bidAmount, blockNumber) if err != nil { - return fmt.Errorf("failed to subscribe to BidderRegistered event: %w", err) - } - defer sub.Unsubscribe() - - select { - case <-ctx.Done(): - return nil - case err := <-sub.Err(): - return fmt.Errorf("error in BidderRegistered event subscription: %w", err) + a.logger.Error("deducting balance", "error", err) + return nil, status.Errorf(codes.FailedPrecondition, "failed to deduct balance: %v", err) } + return deductedBalance, nil } -func (a *AllowanceManager) subscribeNewWindow(ctx context.Context) error { - ev := events.NewEventHandler( - "NewWindow", - func(window *blocktracker.BlocktrackerNewWindow) error { - a.currentWindow = window.Window - return nil - }, - ) - - sub, err := a.evtMgr.Subscribe(ev) - if err != nil { - return fmt.Errorf("failed to subscribe to NewWindow event: %w", err) - } - defer sub.Unsubscribe() - - select { - case <-ctx.Done(): - return nil - case err := <-sub.Err(): - return fmt.Errorf("error in NewWindow event subscription: %w", err) - } +func (a *AllowanceManager) RefundAllowance(address common.Address, deductedAmount *big.Int, blockNumber int64) error { + return a.store.RefundBalanceForBlock(address, deductedAmount, blockNumber) } diff --git a/pkg/events/events.go b/pkg/events/events.go index 9823e4f3..67d9b9ac 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -199,10 +199,14 @@ func (l *Listener) publishLogEvent(ctx context.Context, log types.Log) { l.subMu.RLock() defer l.subMu.RUnlock() + wg := sync.WaitGroup{} events := l.subscribers[log.Topics[0]] for _, event := range events { ev := event + wg.Add(1) go func() { + defer wg.Done() + if err := ev.event.Handle(log); err != nil { l.logger.Error("failed to handle log", "error", err) select { @@ -212,6 +216,8 @@ func (l *Listener) publishLogEvent(ctx context.Context, log types.Log) { } }() } + + wg.Wait() } func (l *Listener) Start(ctx context.Context) <-chan struct{} { @@ -272,7 +278,7 @@ func (l *Listener) Start(ctx context.Context) <-chan struct{} { l.logger.Error("failed to set last block", "error", err) return } - l.logger.Info("processed logs", "from", lastBlock+1, "to", blockNumber, "count", len(logs)) + l.logger.Debug("processed logs", "from", lastBlock+1, "to", blockNumber, "count", len(logs)) lastBlock = blockNumber } } diff --git a/pkg/events/events_test.go b/pkg/events/events_test.go index 5f884ded..bdf27e3d 100644 --- a/pkg/events/events_test.go +++ b/pkg/events/events_test.go @@ -211,8 +211,17 @@ func TestEventManager(t *testing.T) { t.Fatal("timed out waiting for handler to be triggered") } - if b, err := store.LastBlock(); err != nil || b != 2 { - t.Fatalf("expected block number 1, got %d", store.blockNumber) + start := time.Now() + for { + if b, err := store.LastBlock(); err != nil { + t.Fatal(err) + } else if b == 2 { + break + } + if time.Since(start) > 5*time.Second { + t.Fatal("timed out waiting for block number to be updated") + } + time.Sleep(100 * time.Millisecond) } cancel() diff --git a/pkg/node/node.go b/pkg/node/node.go index b0a7ddec..b9256b61 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "log/slog" + "math/big" "net" "net/http" "strings" @@ -194,7 +195,12 @@ func NewNode(opts *Options) (*Node, error) { ctx, cancel := context.WithCancel(context.Background()) var preconfProtoClosed <-chan struct{} - st := store.NewStore() + st, err := store.NewStore() + if err != nil { + opts.Logger.Error("failed to create store", "error", err) + cancel() + return nil, err + } contracts, err := getContractABIs(opts) if err != nil { @@ -264,7 +270,12 @@ func NewNode(opts *Options) (*Node, error) { ) opts.Logger.Info("registered preconf contract") - store := store.NewStore() + store, err := store.NewStore() + if err != nil { + opts.Logger.Error("failed to create store", "error", err) + cancel() + return nil, err + } switch opts.PeerType { case p2p.PeerTypeProvider.String(): @@ -559,6 +570,10 @@ func (noOpAllowanceManager) Start(_ context.Context) <-chan struct{} { return nil } -func (noOpAllowanceManager) CheckAllowance(_ context.Context, _ common.Address) error { +func (noOpAllowanceManager) CheckAndDeductAllowance(_ context.Context, _ common.Address, _ string, _ int64) (*big.Int, error) { + return big.NewInt(0), nil +} + +func (noOpAllowanceManager) RefundAllowance(_ common.Address, _ *big.Int, _ int64) error { return nil } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 95639d29..96410678 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log/slog" + "math/big" "sync" "time" @@ -41,6 +42,8 @@ type Preconfirmation struct { blockTracker blocktrackercontract.Interface evtMgr events.EventManager ecds EncrDecrCommitmentStore + newL1Blocks chan *blocktracker.BlocktrackerNewL1Block + enryptedCmts chan *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored logger *slog.Logger metrics *metrics } @@ -58,11 +61,13 @@ type EncrDecrCommitmentStore interface { GetCommitmentByHash(commitmentHash string) (*store.EncryptedPreConfirmationWithDecrypted, error) AddCommitment(commitment *store.EncryptedPreConfirmationWithDecrypted) DeleteCommitmentByBlockNumber(blockNum int64) error + SetCommitmentIndexByCommitmentDigest(commitmentDigest, commitmentIndex [32]byte) error } type AllowanceManager interface { Start(ctx context.Context) <-chan struct{} - CheckAllowance(ctx context.Context, ethAddress common.Address) error + CheckAndDeductAllowance(ctx context.Context, ethAddress common.Address, bidAmount string, blockNumber int64) (*big.Int, error) + RefundAllowance(ethAddress common.Address, amount *big.Int, blockNumber int64) error } func New( @@ -79,17 +84,18 @@ func New( logger *slog.Logger, ) *Preconfirmation { return &Preconfirmation{ - owner: owner, - topo: topo, - streamer: streamer, - encryptor: encryptor, - // us: us, + owner: owner, + topo: topo, + streamer: streamer, + encryptor: encryptor, allowanceMgr: allowanceMgr, processer: processor, commitmentDA: commitmentDA, blockTracker: blockTracker, evtMgr: evtMgr, ecds: edcs, + newL1Blocks: make(chan *blocktracker.BlocktrackerNewL1Block), + enryptedCmts: make(chan *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored), logger: logger, metrics: newMetrics(), } @@ -113,11 +119,66 @@ func (p *Preconfirmation) Start(ctx context.Context) <-chan struct{} { eg, egCtx := errgroup.WithContext(ctx) eg.Go(func() error { - return p.subscribeNewL1Block(egCtx) + ev1 := events.NewEventHandler( + "NewL1Block", + func(newL1Block *blocktracker.BlocktrackerNewL1Block) error { + select { + case <-egCtx.Done(): + return nil + case p.newL1Blocks <- newL1Block: + return nil + } + }, + ) + + sub1, err := p.evtMgr.Subscribe(ev1) + if err != nil { + return fmt.Errorf("failed to subscribe to NewL1Block event: %w", err) + } + defer sub1.Unsubscribe() + + ev2 := events.NewEventHandler( + "EncryptedCommitmentStored", + func(ec *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored) error { + select { + case <-egCtx.Done(): + return nil + case p.enryptedCmts <- ec: + return nil + } + }, + ) + sub2, err := p.evtMgr.Subscribe(ev2) + if err != nil { + return fmt.Errorf("failed to subscribe to EncryptedCommitmentStored event: %w", err) + } + defer sub2.Unsubscribe() + + select { + case <-egCtx.Done(): + return nil + case err := <-sub1.Err(): + return fmt.Errorf("NewL1Block subscription error: %w", err) + case err := <-sub2.Err(): + return fmt.Errorf("EncryptedCommitmentStored subscription error: %w", err) + } }) eg.Go(func() error { - return p.subscribeEncryptedCommitmentStored(egCtx) + for { + select { + case <-egCtx.Done(): + return nil + case newL1Block := <-p.newL1Blocks: + if err := p.handleNewL1Block(egCtx, newL1Block); err != nil { + return err + } + case ec := <-p.enryptedCmts: + if err := p.handleEncryptedCommitmentStored(egCtx, ec); err != nil { + return err + } + } + } }) go func() { @@ -269,11 +330,24 @@ func (p *Preconfirmation) handleBid( return err } - err = p.allowanceMgr.CheckAllowance(ctx, *ethAddress) + deductedAmount, err := p.allowanceMgr.CheckAndDeductAllowance(ctx, *ethAddress, bid.BidAmount, bid.BlockNumber) if err != nil { p.logger.Error("checking allowance", "error", err) return err } + + // Setup defer for possible refund + successful := false + defer func() { + if !successful { + // Refund the deducted amount if the bid process did not succeed + refundErr := p.allowanceMgr.RefundAllowance(*ethAddress, deductedAmount, bid.BlockNumber) + if refundErr != nil { + p.logger.Error("refunding allowance", "error", refundErr) + } + } + }() + // try to enqueue for 5 seconds ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() @@ -312,98 +386,56 @@ func (p *Preconfirmation) handleBid( p.ecds.AddCommitment(encryptedAndDecryptedPreconfirmation) + // If we reach here, the bid was successful + successful = true + return stream.WriteMsg(ctx, encryptedPreConfirmation) } } return nil } -func (p *Preconfirmation) subscribeNewL1Block(ctx context.Context) error { - ev := events.NewEventHandler( - "NewL1Block", - func(newL1Block *blocktracker.BlocktrackerNewL1Block) error { - p.logger.Info("New L1 Block event received", "blockNumber", newL1Block.BlockNumber, "winner", newL1Block.Winner, "window", newL1Block.Window) - commitments, err := p.ecds.GetCommitmentsByBlockNumber(newL1Block.BlockNumber.Int64()) - if err != nil { - p.logger.Error("failed to get commitments by block number", "error", err) - return err - } - for _, commitment := range commitments { - if common.BytesToAddress(commitment.ProviderAddress) != newL1Block.Winner { - p.logger.Info("provider address does not match the winner", "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner) - continue - } - txHash, err := p.commitmentDA.OpenCommitment( - ctx, - commitment.EncryptedPreConfirmation.CommitmentIndex, - commitment.PreConfirmation.Bid.BidAmount, - commitment.PreConfirmation.Bid.BlockNumber, - commitment.PreConfirmation.Bid.TxHash, - commitment.PreConfirmation.Bid.DecayStartTimestamp, - commitment.PreConfirmation.Bid.DecayEndTimestamp, - commitment.PreConfirmation.Bid.Signature, - commitment.PreConfirmation.Signature, - commitment.PreConfirmation.SharedSecret, - ) - if err != nil { - // todo: retry mechanism? - p.logger.Error("failed to open commitment", "error", err) - continue - } else { - p.logger.Info("opened commitment", "txHash", txHash) - } - } - err = p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) - if err != nil { - p.logger.Error("failed to delete commitments by block number", "error", err) - return err - } - return nil - }, - ) - - sub, err := p.evtMgr.Subscribe(ev) +func (p *Preconfirmation) handleNewL1Block(ctx context.Context, newL1Block *blocktracker.BlocktrackerNewL1Block) error { + p.logger.Info("New L1 Block event received", "blockNumber", newL1Block.BlockNumber, "winner", newL1Block.Winner, "window", newL1Block.Window) + commitments, err := p.ecds.GetCommitmentsByBlockNumber(newL1Block.BlockNumber.Int64()) if err != nil { - return fmt.Errorf("failed to subscribe to NewL1Block event: %w", err) + p.logger.Error("failed to get commitments by block number", "error", err) + return err } - defer sub.Unsubscribe() - - select { - case <-ctx.Done(): - return nil - case err := <-sub.Err(): - return fmt.Errorf("subscription error: %w", err) + for _, commitment := range commitments { + if common.BytesToAddress(commitment.ProviderAddress) != newL1Block.Winner { + p.logger.Info("provider address does not match the winner", "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner) + continue + } + txHash, err := p.commitmentDA.OpenCommitment( + ctx, + commitment.EncryptedPreConfirmation.CommitmentIndex, + commitment.PreConfirmation.Bid.BidAmount, + commitment.PreConfirmation.Bid.BlockNumber, + commitment.PreConfirmation.Bid.TxHash, + commitment.PreConfirmation.Bid.DecayStartTimestamp, + commitment.PreConfirmation.Bid.DecayEndTimestamp, + commitment.PreConfirmation.Bid.Signature, + commitment.PreConfirmation.Signature, + commitment.PreConfirmation.SharedSecret, + ) + if err != nil { + // todo: retry mechanism? + p.logger.Error("failed to open commitment", "error", err) + continue + } else { + p.logger.Info("opened commitment", "txHash", txHash) + } } -} - -func (p *Preconfirmation) subscribeEncryptedCommitmentStored(ctx context.Context) error { - ev := events.NewEventHandler( - "EncryptedCommitmentStored", - func(ec *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored) error { - p.logger.Info("Encrypted Commitment Stored event received", "commitmentDigest", ec.CommitmentDigest, "commitmentIndex", ec.CommitmentIndex) - commitment, err := p.ecds.GetCommitmentByHash(common.Bytes2Hex(ec.CommitmentDigest[:])) - if err != nil { - return fmt.Errorf("failed to get commitment by hash: %w", err) - } - if commitment == nil { - p.logger.Debug("commitment not found", "commitmentDigest", ec.CommitmentDigest) - return nil - } - commitment.EncryptedPreConfirmation.CommitmentIndex = ec.CommitmentIndex[:] - return nil - }, - ) - - sub, err := p.evtMgr.Subscribe(ev) + err = p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) if err != nil { - return fmt.Errorf("failed to subscribe to EncryptedCommitmentStored event: %w", err) + p.logger.Error("failed to delete commitments by block number", "error", err) + return err } - defer sub.Unsubscribe() + return nil +} - select { - case <-ctx.Done(): - return nil - case err := <-sub.Err(): - return fmt.Errorf("encrypted commitment stored subscription error: %w", err) - } +func (p *Preconfirmation) handleEncryptedCommitmentStored(ctx context.Context, ec *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored) error { + p.logger.Info("Encrypted Commitment Stored event received", "commitmentDigest", ec.CommitmentDigest, "commitmentIndex", ec.CommitmentIndex) + return p.ecds.SetCommitmentIndexByCommitmentDigest(ec.CommitmentDigest, ec.CommitmentIndex) } diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index 90f3b9fa..d6b08b18 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -8,19 +8,18 @@ import ( "errors" "io" "log/slog" + "math/big" "os" "strings" "testing" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/ecies" blocktracker "github.com/primevprotocol/contracts-abi/clients/BlockTracker" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" - blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" "github.com/primevprotocol/mev-commit/pkg/events" "github.com/primevprotocol/mev-commit/pkg/p2p" p2ptest "github.com/primevprotocol/mev-commit/pkg/p2p/testing" @@ -129,10 +128,6 @@ func (btc *testBlockTrackerContract) GetBlocksPerWindow(ctx context.Context) (ui return btc.blocksPerWindow, nil } -func (btc *testBlockTrackerContract) SubscribeNewL1Block(ctx context.Context, eventCh chan<- blocktrackercontract.NewL1BlockEvent) (ethereum.Subscription, error) { - return nil, nil -} - type testEventManager struct { btABI *abi.ABI handler events.EventHandler @@ -176,7 +171,11 @@ func (t *testAllowanceManager) Start(ctx context.Context) <-chan struct{} { return nil } -func (t *testAllowanceManager) CheckAllowance(ctx context.Context, address common.Address) error { +func (t *testAllowanceManager) CheckAndDeductAllowance(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { + return big.NewInt(0), nil +} + +func (t *testAllowanceManager) RefundAllowance(address common.Address, deductedAmount *big.Int, blockNumber int64) error { return nil } @@ -259,7 +258,10 @@ func TestPreconfBidSubmission(t *testing.T) { sub: &testSub{errC: make(chan error)}, handlerSub: make(chan struct{}), } - + store, err := store.NewStore() + if err != nil { + t.Fatal(err) + } allowanceMgr := &testAllowanceManager{} p := preconfirmation.New( client.EthAddress, @@ -271,7 +273,7 @@ func TestPreconfBidSubmission(t *testing.T) { &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, eventManager, - store.NewStore(), + store, newTestLogger(t, os.Stdout), ) diff --git a/pkg/store/store.go b/pkg/store/store.go index 839255ba..c96a33ec 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -1,10 +1,12 @@ package store import ( + "fmt" "math/big" "sync" "github.com/ethereum/go-ethereum/common" + lru "github.com/hashicorp/golang-lru/v2" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" ) @@ -31,7 +33,11 @@ type EncryptedPreConfirmationWithDecrypted struct { *preconfpb.PreConfirmation } -func NewStore() *Store { +func NewStore() (*Store, error) { + balancesByBlockCache, err := lru.New[string, *big.Int](1024) + if err != nil { + return nil, fmt.Errorf("failed to create balancesByBlockCache: %w", err) + } return &Store{ BlockStore: &BlockStore{ data: make(map[string]uint64), @@ -41,9 +47,10 @@ func NewStore() *Store { commitmentsByCommitmentHash: make(map[string]*EncryptedPreConfirmationWithDecrypted), }, BidderBalancesStore: &BidderBalancesStore{ - balances: make(map[string]*big.Int), + balances: make(map[string]*big.Int), + balancesByBlock: balancesByBlockCache, }, - } + }, nil } func (bs *BlockStore) LastBlock() (uint64, error) { @@ -125,9 +132,25 @@ func (cs *CommitmentsStore) deleteCommitmentByHash(hash string) error { return nil } +func (cs *CommitmentsStore) SetCommitmentIndexByCommitmentDigest(cDigest, cIndex [32]byte) error { + // when we will have db, this will be UPDATE query, instead of inmemory update + commitment, err := cs.GetCommitmentByHash(common.Bytes2Hex(cDigest[:])) + if err != nil { + return fmt.Errorf("failed to get commitment by hash: %w", err) + } + if commitment == nil { + // commitment could be not found in case this commitment is from another bidder/provider + // so no need to return error in this case + return nil + } + commitment.EncryptedPreConfirmation.CommitmentIndex = cIndex[:] + return nil +} + type BidderBalancesStore struct { - balances map[string]*big.Int - mu sync.RWMutex + balances map[string]*big.Int + balancesByBlock *lru.Cache[string, *big.Int] + mu sync.RWMutex } func (bbs *BidderBalancesStore) SetBalance(bidder common.Address, windowNumber *big.Int, prepaidAmount *big.Int) error { @@ -150,4 +173,43 @@ func (bbs *BidderBalancesStore) GetBalance(bidder common.Address, windowNumber * func getBBSKey(bidder common.Address, windowNumber *big.Int) string { return bidder.String() + windowNumber.String() -} \ No newline at end of file +} + +func (bbs *BidderBalancesStore) DeductAndCheckBalanceForBlock(bidder common.Address, defaultAmount, bidAmount *big.Int, blockNumber int64) (*big.Int, error) { + key := getBBSforBlockKey(bidder, blockNumber) + if currentBalance, ok := bbs.balancesByBlock.Get(key); ok { + if currentBalance.Cmp(bidAmount) >= 0 { + newBalance := new(big.Int).Sub(currentBalance, bidAmount) + bbs.balancesByBlock.Add(key, newBalance) + return newBalance, nil + } + return nil, fmt.Errorf("insufficient funds") + } + + // If no balance found, set balance to defaultAmount - bidAmount + if defaultAmount.Cmp(bidAmount) >= 0 { + newBalance := new(big.Int).Sub(defaultAmount, bidAmount) + bbs.balancesByBlock.Add(key, newBalance) + return newBalance, nil + } + return nil, fmt.Errorf("default amount is less than bid amount, cannot deduct") +} + + +func (bbs *BidderBalancesStore) RefundBalanceForBlock(bidder common.Address, amount *big.Int, blockNumber int64) error { + key := getBBSforBlockKey(bidder, blockNumber) + if currentBalance, ok := bbs.balancesByBlock.Get(key); ok { + // If a balance exists, simply add the amount back + updatedBalance := new(big.Int).Add(currentBalance, amount) + bbs.balancesByBlock.Add(key, updatedBalance) + return nil + } + + // If no balance found (which should be unusual for a refund), initialize to the refund amount + bbs.balancesByBlock.Add(key, amount) + return nil +} + +func getBBSforBlockKey(bidder common.Address, blockNumber int64) string { + return bidder.String() + fmt.Sprint(blockNumber) +} From e6ad656ba7c587832f7809646ae36f6f8b50dc67 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 22 Apr 2024 01:20:14 +0200 Subject: [PATCH 78/85] fixed order in prepay allowance request --- pkg/contracts/bidder_registry/bidder_registry.go | 4 ++-- pkg/contracts/bidder_registry/bidder_registry_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index 2eacd1cf..aa60e737 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -23,7 +23,7 @@ var bidderRegistryABI = func() abi.ABI { type Interface interface { // PrepayAllowanceForSpecificWindow registers a bidder with the bidder_registry contract for a specific window. - PrepayAllowanceForSpecificWindow(ctx context.Context, window *big.Int, amount *big.Int) error + PrepayAllowanceForSpecificWindow(ctx context.Context, amount, window *big.Int) error // GetAllowance returns the stake of a bidder. GetAllowance(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) // GetMinAllowance returns the minimum stake required to register as a bidder. @@ -57,7 +57,7 @@ func New( } } -func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, window *big.Int, amount *big.Int) error { +func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, amount, window *big.Int) error { callData, err := r.bidderRegistryABI.Pack("prepayAllowanceForSpecificWindow", window) if err != nil { r.logger.Error("error packing call data", "error", err) diff --git a/pkg/contracts/bidder_registry/bidder_registry_test.go b/pkg/contracts/bidder_registry/bidder_registry_test.go index 70518bad..a4cef71f 100644 --- a/pkg/contracts/bidder_registry/bidder_registry_test.go +++ b/pkg/contracts/bidder_registry/bidder_registry_test.go @@ -74,7 +74,7 @@ func TestBidderRegistryContract(t *testing.T) { mockClient, util.NewTestLogger(os.Stdout), ) - err = registryContract.PrepayAllowanceForSpecificWindow(context.Background(), big.NewInt(1), amount) + err = registryContract.PrepayAllowanceForSpecificWindow(context.Background(), amount, big.NewInt(1)) if err != nil { t.Fatal(err) } From 300aaf6f565a6a7917ef067fb201b66691ca39ce Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 22 Apr 2024 01:39:04 +0200 Subject: [PATCH 79/85] fixed log --- pkg/contracts/bidder_registry/bidder_registry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index aa60e737..d47ceeeb 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -102,7 +102,7 @@ func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Co r.logger.Debug("Failed to unpack event", "err", err) continue } - r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "prepaidAmount", bidderRegistered.PrepaidAmount.Uint64(), "windowNumber", bidderRegistered.WindowNumber.Int64()) + r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "prepaidAmount", bidderRegistered.PrepaidAmount.String(), "windowNumber", bidderRegistered.WindowNumber.Int64()) } r.logger.Info("prepay successful for bidder registry", "txnHash", txnHash, "bidder", bidderRegistered.Bidder) From a1866d70574260d7cadb06b9237056724a6f272c Mon Sep 17 00:00:00 2001 From: Alok Date: Mon, 22 Apr 2024 18:35:19 +0530 Subject: [PATCH 80/85] fix: real-bidder test --- integrationtest/real-bidder/main.go | 70 ++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index d16c79cb..41a1c7a8 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -136,25 +136,71 @@ func main() { } }() + type blockWithTxns struct { + blockNum int64 + txns []string + } + + newBlockChan := make(chan blockWithTxns, 1) + wg.Add(1) go func(logger *slog.Logger) { defer wg.Done() + + currentBlkNum := int64(0) for { block, blkNum, err := RetreivedBlock(rpcClient) if err != nil || len(block) == 0 { logger.Error("failed to get block", "err", err) - } else { - throtle := time.Duration(12000*time.Millisecond) / time.Duration(len(block)) - logger.Info("thortling set", "throtle", throtle.String()) - bundle := 1 - for j := 0; j < len(block); j += bundle { - bundle := rand.Intn(10) - err = sendBid(bidderClient, logger, rpcClient, block[j:j+bundle], int64(blkNum), (time.Now().UnixMilli())-10000, (time.Now().UnixMilli())) - if err != nil { - logger.Error("failed to send bid", "err", err) - } - time.Sleep(throtle) - } + } + + if currentBlkNum == blkNum { + time.Sleep(1 * time.Second) + continue + } + + currentBlkNum = blkNum + newBlockChan <- blockWithTxns{ + blockNum: blkNum, + txns: block, + } + } + }(logger) + + wg.Add(1) + go func(logger *slog.Logger) { + defer wg.Done() + ticker := time.NewTicker(200 * time.Millisecond) + currentBlock := blockWithTxns{} + for { + select { + case block := <-newBlockChan: + currentBlock = block + case <-ticker.C: + } + + if len(currentBlock.txns) == 0 { + continue + } + + bundleLen := rand.Intn(10) + bundleStart := rand.Intn(len(currentBlock.txns)) + bundleEnd := bundleStart + bundleLen + if bundleEnd > len(currentBlock.txns) { + bundleEnd = len(currentBlock.txns) - 1 + } + + err = sendBid( + bidderClient, + logger, + rpcClient, + currentBlock.txns[bundleStart:bundleEnd], + currentBlock.blockNum, + time.Now().UnixMilli(), + (time.Now().UnixMilli())+10000, + ) + if err != nil { + logger.Error("failed to send bid", "err", err) } } }(logger) From 7198a7a2295976f8e12c0c434e6849c68ce18ad9 Mon Sep 17 00:00:00 2001 From: Alok Date: Mon, 22 Apr 2024 19:04:40 +0530 Subject: [PATCH 81/85] fix: real-bidder test --- integrationtest/real-bidder/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index 41a1c7a8..4913b7be 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -82,7 +82,7 @@ func main() { )) registry := prometheus.NewRegistry() - registry.MustRegister(receivedPreconfs, sentBids) + registry.MustRegister(receivedPreconfs, sentBids, sendBidDuration) router := http.NewServeMux() router.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) @@ -197,7 +197,7 @@ func main() { currentBlock.txns[bundleStart:bundleEnd], currentBlock.blockNum, time.Now().UnixMilli(), - (time.Now().UnixMilli())+10000, + (time.Now().UnixMilli())+15000, ) if err != nil { logger.Error("failed to send bid", "err", err) From f523fb7a1013e352c6d0ad7da6b3ec723ee0edc0 Mon Sep 17 00:00:00 2001 From: Alok Date: Mon, 22 Apr 2024 20:26:47 +0530 Subject: [PATCH 82/85] chore: test adjustment --- integrationtest/real-bidder/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index 4913b7be..95ce1e0a 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -196,8 +196,8 @@ func main() { rpcClient, currentBlock.txns[bundleStart:bundleEnd], currentBlock.blockNum, - time.Now().UnixMilli(), - (time.Now().UnixMilli())+15000, + (time.Now().UnixMilli())-10000, + (time.Now().UnixMilli())+10000, ) if err != nil { logger.Error("failed to send bid", "err", err) From 51f50405efffee45d5bdff411405b2657679973f Mon Sep 17 00:00:00 2001 From: Mikelle Date: Mon, 22 Apr 2024 19:34:20 +0200 Subject: [PATCH 83/85] added simple logs and get rid of wait receipt --- pkg/contracts/preconf/preconf.go | 7 +----- pkg/preconfirmation/preconfirmation.go | 33 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/pkg/contracts/preconf/preconf.go b/pkg/contracts/preconf/preconf.go index 309e93df..42d7d5b6 100644 --- a/pkg/contracts/preconf/preconf.go +++ b/pkg/contracts/preconf/preconf.go @@ -136,12 +136,7 @@ func (p *preconfContract) OpenCommitment( return common.Hash{}, err } - receipt, err := p.client.WaitForReceipt(ctx, txHash) - if err != nil { - return common.Hash{}, err - } - - p.logger.Info("preconf contract openCommitment successful", "txHash", txHash, "receiptStatus", receipt.Status) + p.logger.Info("preconf contract openCommitment successful", "txHash", txHash.String()) return txHash, nil } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 96410678..984c42a8 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -203,12 +203,14 @@ func (p *Preconfirmation) SendBid( decayStartTimestamp int64, decayEndTimestamp int64, ) (chan *preconfpb.PreConfirmation, error) { + startTime := time.Now() bid, encryptedBid, err := p.encryptor.ConstructEncryptedBid(txHash, bidAmt, blockNumber, decayStartTimestamp, decayEndTimestamp) if err != nil { p.logger.Error("constructing encrypted bid", "error", err, "txHash", txHash) return nil, err } - p.logger.Info("constructed encrypted bid", "encryptedBid", encryptedBid) + duration := time.Since(startTime) + p.logger.Info("constructed encrypted bid", "encryptedBid", encryptedBid, "duration", duration) providers := p.topo.GetPeers(topology.Query{Type: p2p.PeerTypeProvider}) if len(providers) == 0 { @@ -259,11 +261,14 @@ func (p *Preconfirmation) SendBid( _ = providerStream.Close() // Process preConfirmation as a bidder + verifyStartTime := time.Now() sharedSecretKey, providerAddress, err := p.encryptor.VerifyEncryptedPreConfirmation(provider.Keys.NIKEPublicKey, bid.Digest, encryptedPreConfirmation) if err != nil { logger.Error("verifying provider signature", "error", err) return } + verifyDuration := time.Since(verifyStartTime) + logger.Info("verified encrypted preconfirmation", "duration", verifyDuration) preConfirmation := &preconfpb.PreConfirmation{ Bid: bid, @@ -337,16 +342,16 @@ func (p *Preconfirmation) handleBid( } // Setup defer for possible refund - successful := false - defer func() { - if !successful { - // Refund the deducted amount if the bid process did not succeed - refundErr := p.allowanceMgr.RefundAllowance(*ethAddress, deductedAmount, bid.BlockNumber) - if refundErr != nil { - p.logger.Error("refunding allowance", "error", refundErr) - } - } - }() + successful := false + defer func() { + if !successful { + // Refund the deducted amount if the bid process did not succeed + refundErr := p.allowanceMgr.RefundAllowance(*ethAddress, deductedAmount, bid.BlockNumber) + if refundErr != nil { + p.logger.Error("refunding allowance", "error", refundErr) + } + } + }() // try to enqueue for 5 seconds ctx, cancel := context.WithTimeout(ctx, 5*time.Second) @@ -407,6 +412,7 @@ func (p *Preconfirmation) handleNewL1Block(ctx context.Context, newL1Block *bloc p.logger.Info("provider address does not match the winner", "providerAddress", commitment.ProviderAddress, "winner", newL1Block.Winner) continue } + startTime := time.Now() txHash, err := p.commitmentDA.OpenCommitment( ctx, commitment.EncryptedPreConfirmation.CommitmentIndex, @@ -423,10 +429,11 @@ func (p *Preconfirmation) handleNewL1Block(ctx context.Context, newL1Block *bloc // todo: retry mechanism? p.logger.Error("failed to open commitment", "error", err) continue - } else { - p.logger.Info("opened commitment", "txHash", txHash) } + duration := time.Since(startTime) + p.logger.Info("opened commitment", "txHash", txHash, "duration", duration) } + err = p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) if err != nil { p.logger.Error("failed to delete commitments by block number", "error", err) From e4a8cc2c64416f9560e7bed87c5c4473629720f8 Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 23 Apr 2024 18:14:07 +0200 Subject: [PATCH 84/85] added block number as a arg for prepay allowance --- gen/go/bidderapi/v1/bidderapi.pb.go | 572 +++++++++--------- .../bidderapi/v1/bidderapi.swagger.yaml | 6 + pkg/rpc/bidder/service.go | 30 +- rpc/bidderapi/v1/bidderapi.proto | 8 + 4 files changed, 335 insertions(+), 281 deletions(-) diff --git a/gen/go/bidderapi/v1/bidderapi.pb.go b/gen/go/bidderapi/v1/bidderapi.pb.go index ecf88c07..62ad6c80 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.go @@ -31,6 +31,7 @@ type PrepayRequest struct { Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,2,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` + BlockNumber *wrapperspb.UInt64Value `protobuf:"bytes,3,opt,name=blockNumber,proto3" json:"blockNumber,omitempty"` } func (x *PrepayRequest) Reset() { @@ -79,6 +80,13 @@ func (x *PrepayRequest) GetWindowNumber() *wrapperspb.UInt64Value { return nil } +func (x *PrepayRequest) GetBlockNumber() *wrapperspb.UInt64Value { + if x != nil { + return x.BlockNumber + } + return nil +} + type PrepayResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -431,7 +439,7 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xca, 0x04, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x06, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x7a, 0x92, 0x41, 0x2e, 0x32, 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, @@ -459,269 +467,286 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x3a, 0x8e, 0x01, 0x92, 0x41, 0x8a, 0x01, 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, - 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, - 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, - 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, - 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, - 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x35, 0x7b, - 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, - 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, - 0x20, 0x31, 0x20, 0x7d, 0x22, 0xf7, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x40, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x3a, 0x8a, 0x01, 0x92, 0x41, 0x86, 0x01, 0x0a, 0x4b, 0x2a, 0x0f, 0x50, 0x72, 0x65, 0x70, - 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, - 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, - 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x37, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, - 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x22, 0x20, 0x7d, 0x22, 0x0e, - 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, - 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, - 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, - 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, - 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x64, 0xba, 0x01, 0x61, 0x0a, 0x0c, 0x77, 0x69, - 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, - 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, - 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, - 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, - 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, - 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, - 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, - 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, - 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, - 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, - 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, - 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, - 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x62, 0x65, 0x72, 0x12, 0x93, 0x02, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, + 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xd2, 0x01, 0x92, 0x41, 0x6a, 0x32, 0x68, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, + 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x20, 0x49, 0x66, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, + 0x6c, 0x61, 0x74, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x62, 0x61, 0x73, 0x65, + 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0xba, 0x48, 0x62, 0xba, 0x01, 0x5f, 0x0a, 0x0b, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x34, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, + 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, + 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0b, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x8e, 0x01, 0x92, 0x41, 0x8a, 0x01, + 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x32, 0x35, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, + 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x20, 0x7d, 0x22, 0xf7, 0x01, 0x0a, 0x0e, 0x50, + 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, + 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x8a, 0x01, 0x92, 0x41, 0x86, 0x01, 0x0a, 0x4b, + 0x2a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x37, 0x7b, 0x22, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, + 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, + 0x31, 0x22, 0x20, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x02, 0x0a, + 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, + 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x64, 0xba, + 0x01, 0x61, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, + 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, + 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, + 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, + 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, + 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, + 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, + 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, + 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, + 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, + 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, + 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, + 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, + 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, + 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, + 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, + 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, + 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, - 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, - 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, - 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, - 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, - 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, + 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, + 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, + 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, + 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, + 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, + 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, + 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, + 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, + 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, + 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, - 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, - 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, - 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, - 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, - 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, - 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, - 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, - 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, - 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, - 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, - 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, - 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, - 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, - 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, - 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, - 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, - 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, - 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, - 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, - 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, - 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, - 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, + 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, + 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, + 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, + 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, + 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, + 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, + 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, + 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, + 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, + 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, + 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, + 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, + 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, + 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, + 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, - 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, - 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, - 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, - 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, - 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, - 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, - 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, + 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, + 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, + 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, + 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, + 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, + 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, - 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, - 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, - 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, - 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, - 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, - 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, - 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, - 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, - 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, - 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, - 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, - 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, - 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, - 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, - 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, - 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, - 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, 0x7a, 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x5d, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, - 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, - 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, - 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, - 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, - 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, + 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, + 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, + 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, + 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, + 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, + 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, + 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, + 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, + 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, + 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, + 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, + 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x41, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, 0x7a, 0x12, 0x78, + 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x5d, 0x0a, 0x1b, + 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, + 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, + 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, + 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, + 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, + 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, + 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -748,21 +773,22 @@ var file_bidderapi_v1_bidderapi_proto_goTypes = []interface{}{ } var file_bidderapi_v1_bidderapi_proto_depIdxs = []int32{ 6, // 0: bidderapi.v1.PrepayRequest.windowNumber:type_name -> google.protobuf.UInt64Value - 6, // 1: bidderapi.v1.PrepayResponse.windowNumber:type_name -> google.protobuf.UInt64Value - 6, // 2: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value - 4, // 3: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid - 0, // 4: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest - 3, // 5: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest - 2, // 6: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage - 5, // 7: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment - 1, // 8: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 9: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 10: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse - 7, // [7:11] is the sub-list for method output_type - 3, // [3:7] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 6, // 1: bidderapi.v1.PrepayRequest.blockNumber:type_name -> google.protobuf.UInt64Value + 6, // 2: bidderapi.v1.PrepayResponse.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 3: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 4, // 4: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid + 0, // 5: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest + 3, // 6: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest + 2, // 7: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage + 5, // 8: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment + 1, // 9: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 10: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 11: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse + 8, // [8:12] is the sub-list for method output_type + 4, // [4:8] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_bidderapi_v1_bidderapi_proto_init() } diff --git a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml index 8596767f..3d2e0a87 100644 --- a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml +++ b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml @@ -98,6 +98,12 @@ paths: required: false type: string format: uint64 + - name: blockNumber + description: Optional block number for querying allowance. If specified, calculate window based on this block number. + in: query + required: false + type: string + format: uint64 definitions: bidderapiv1Bid: type: object diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 46e15c45..85e31dc6 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -3,6 +3,7 @@ package bidderapi import ( "context" "encoding/hex" + "fmt" "log/slog" "math/big" "strings" @@ -124,16 +125,12 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.Internal, "getting current window: %v", err) } - var windowToDeposit *big.Int - if r.WindowNumber == nil { - // adding +2 as oracle working 2 windows behind the current window - windowToDeposit = new(big.Int).SetUint64(currentWindow + 2) - } else { - windowToDeposit = new(big.Int).SetUint64(r.WindowNumber.Value) + windowToDeposit, err := s.calculateWindowToDeposit(ctx, r, currentWindow) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "calculating window to deposit: %v", err) } - if _, ok := s.depositedWindows[windowToDeposit]; ok { - return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", currentWindow+1) + return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", windowToDeposit.Int64()) } for window := range s.depositedWindows { @@ -168,6 +165,23 @@ func (s *Service) PrepayAllowance( return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String(), WindowNumber: wrapperspb.UInt64(windowToDeposit.Uint64())}, nil } +func (s *Service) calculateWindowToDeposit(ctx context.Context, r *bidderapiv1.PrepayRequest, currentWindow uint64) (*big.Int, error) { + if r.WindowNumber != nil { + // Directly use the specified window number if available. + return new(big.Int).SetUint64(r.WindowNumber.Value), nil + } else if r.BlockNumber != nil { + // Calculate the window based on the block number. + blocksPerWindow, err := s.blockTrackerContract.GetBlocksPerWindow(ctx) + if err != nil { + return nil, fmt.Errorf("getting window for block: %w", err) + } + return new(big.Int).SetUint64((r.BlockNumber.Value-1)/blocksPerWindow + 1), nil + } + // Default to two windows ahead of the current window if no specific block or window is given. + // This is for the case where the oracle works 2 windows behind the current window. + return new(big.Int).SetUint64(currentWindow + 2), nil +} + func (s *Service) GetAllowance( ctx context.Context, r *bidderapiv1.GetAllowanceRequest, diff --git a/rpc/bidderapi/v1/bidderapi.proto b/rpc/bidderapi/v1/bidderapi.proto index eabe0c5d..de7bb20d 100644 --- a/rpc/bidderapi/v1/bidderapi.proto +++ b/rpc/bidderapi/v1/bidderapi.proto @@ -75,6 +75,14 @@ message PrepayRequest { message: "windowNumber must be a positive integer if specified.", expression: "this == null || (this > 0)" }]; + google.protobuf.UInt64Value blockNumber = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Optional block number for querying allowance. If specified, calculate window based on this block number." + }, (buf.validate.field).cel = { + id: "blockNumber", + message: "blockNumber must be a positive integer if specified.", + expression: "this == null || (this > 0)" + }]; }; message PrepayResponse { From a865180f613191d9228b5d516c5e061fab0c821b Mon Sep 17 00:00:00 2001 From: Mikelle Date: Tue, 23 Apr 2024 20:16:37 +0200 Subject: [PATCH 85/85] updated naming, allowance -> deposit and prepay -> deposit --- gen/go/bidderapi/v1/bidderapi.pb.go | 662 +++++++++--------- gen/go/bidderapi/v1/bidderapi.pb.gw.go | 104 +-- gen/go/bidderapi/v1/bidderapi_grpc.pb.go | 114 +-- .../bidderapi/v1/bidderapi.swagger.yaml | 78 +-- go.mod | 2 +- go.sum | 2 + integrationtest/bidder/main.go | 36 +- integrationtest/real-bidder/main.go | 36 +- .../bidder_registry/bidder_registry.go | 54 +- .../bidder_registry/bidder_registry_test.go | 20 +- .../deposit.go} | 52 +- pkg/events/events_test.go | 32 +- pkg/node/node.go | 22 +- pkg/preconfirmation/preconfirmation.go | 22 +- pkg/preconfirmation/preconfirmation_test.go | 12 +- pkg/rpc/bidder/service.go | 52 +- pkg/rpc/bidder/service_test.go | 58 +- pkg/store/store.go | 4 +- rpc/bidderapi/v1/bidderapi.proto | 46 +- 19 files changed, 704 insertions(+), 704 deletions(-) rename pkg/{allowancemanager/allowance.go => depositmanager/deposit.go} (77%) diff --git a/gen/go/bidderapi/v1/bidderapi.pb.go b/gen/go/bidderapi/v1/bidderapi.pb.go index 62ad6c80..fb283ba9 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.go @@ -24,7 +24,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type PrepayRequest struct { +type DepositRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -34,8 +34,8 @@ type PrepayRequest struct { BlockNumber *wrapperspb.UInt64Value `protobuf:"bytes,3,opt,name=blockNumber,proto3" json:"blockNumber,omitempty"` } -func (x *PrepayRequest) Reset() { - *x = PrepayRequest{} +func (x *DepositRequest) Reset() { + *x = DepositRequest{} if protoimpl.UnsafeEnabled { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -43,13 +43,13 @@ func (x *PrepayRequest) Reset() { } } -func (x *PrepayRequest) String() string { +func (x *DepositRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PrepayRequest) ProtoMessage() {} +func (*DepositRequest) ProtoMessage() {} -func (x *PrepayRequest) ProtoReflect() protoreflect.Message { +func (x *DepositRequest) ProtoReflect() protoreflect.Message { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -61,33 +61,33 @@ func (x *PrepayRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PrepayRequest.ProtoReflect.Descriptor instead. -func (*PrepayRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use DepositRequest.ProtoReflect.Descriptor instead. +func (*DepositRequest) Descriptor() ([]byte, []int) { return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{0} } -func (x *PrepayRequest) GetAmount() string { +func (x *DepositRequest) GetAmount() string { if x != nil { return x.Amount } return "" } -func (x *PrepayRequest) GetWindowNumber() *wrapperspb.UInt64Value { +func (x *DepositRequest) GetWindowNumber() *wrapperspb.UInt64Value { if x != nil { return x.WindowNumber } return nil } -func (x *PrepayRequest) GetBlockNumber() *wrapperspb.UInt64Value { +func (x *DepositRequest) GetBlockNumber() *wrapperspb.UInt64Value { if x != nil { return x.BlockNumber } return nil } -type PrepayResponse struct { +type DepositResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -96,8 +96,8 @@ type PrepayResponse struct { WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,2,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` } -func (x *PrepayResponse) Reset() { - *x = PrepayResponse{} +func (x *DepositResponse) Reset() { + *x = DepositResponse{} if protoimpl.UnsafeEnabled { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -105,13 +105,13 @@ func (x *PrepayResponse) Reset() { } } -func (x *PrepayResponse) String() string { +func (x *DepositResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PrepayResponse) ProtoMessage() {} +func (*DepositResponse) ProtoMessage() {} -func (x *PrepayResponse) ProtoReflect() protoreflect.Message { +func (x *DepositResponse) ProtoReflect() protoreflect.Message { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -123,19 +123,19 @@ func (x *PrepayResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PrepayResponse.ProtoReflect.Descriptor instead. -func (*PrepayResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use DepositResponse.ProtoReflect.Descriptor instead. +func (*DepositResponse) Descriptor() ([]byte, []int) { return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{1} } -func (x *PrepayResponse) GetAmount() string { +func (x *DepositResponse) GetAmount() string { if x != nil { return x.Amount } return "" } -func (x *PrepayResponse) GetWindowNumber() *wrapperspb.UInt64Value { +func (x *DepositResponse) GetWindowNumber() *wrapperspb.UInt64Value { if x != nil { return x.WindowNumber } @@ -180,7 +180,7 @@ func (*EmptyMessage) Descriptor() ([]byte, []int) { return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{2} } -type GetAllowanceRequest struct { +type GetDepositRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -188,8 +188,8 @@ type GetAllowanceRequest struct { WindowNumber *wrapperspb.UInt64Value `protobuf:"bytes,1,opt,name=windowNumber,proto3" json:"windowNumber,omitempty"` } -func (x *GetAllowanceRequest) Reset() { - *x = GetAllowanceRequest{} +func (x *GetDepositRequest) Reset() { + *x = GetDepositRequest{} if protoimpl.UnsafeEnabled { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -197,13 +197,13 @@ func (x *GetAllowanceRequest) Reset() { } } -func (x *GetAllowanceRequest) String() string { +func (x *GetDepositRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetAllowanceRequest) ProtoMessage() {} +func (*GetDepositRequest) ProtoMessage() {} -func (x *GetAllowanceRequest) ProtoReflect() protoreflect.Message { +func (x *GetDepositRequest) ProtoReflect() protoreflect.Message { mi := &file_bidderapi_v1_bidderapi_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -215,12 +215,12 @@ func (x *GetAllowanceRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetAllowanceRequest.ProtoReflect.Descriptor instead. -func (*GetAllowanceRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use GetDepositRequest.ProtoReflect.Descriptor instead. +func (*GetDepositRequest) Descriptor() ([]byte, []int) { return file_bidderapi_v1_bidderapi_proto_rawDescGZIP(), []int{3} } -func (x *GetAllowanceRequest) GetWindowNumber() *wrapperspb.UInt64Value { +func (x *GetDepositRequest) GetWindowNumber() *wrapperspb.UInt64Value { if x != nil { return x.WindowNumber } @@ -439,24 +439,24 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe0, 0x06, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x70, - 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x01, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x7a, 0x92, 0x41, 0x2e, 0x32, - 0x23, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, - 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x20, - 0x77, 0x65, 0x69, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x46, - 0xba, 0x01, 0x43, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x18, 0x74, 0x68, - 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, - 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x92, - 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdc, 0x06, 0x0a, 0x0e, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x94, 0x01, 0x0a, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x7c, 0x92, 0x41, 0x30, + 0x32, 0x25, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, + 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x65, 0x64, 0x20, + 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, + 0xba, 0x48, 0x46, 0xba, 0x01, 0x43, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, + 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, + 0x18, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, + 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x8f, 0x02, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, + 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xcc, 0x01, 0x92, 0x41, 0x62, 0x32, 0x60, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, + 0x67, 0x20, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, @@ -467,286 +467,284 @@ var file_bidderapi_v1_bidderapi_proto_rawDesc = []byte{ 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x12, 0x93, 0x02, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x91, 0x02, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, - 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xd2, 0x01, 0x92, 0x41, 0x6a, 0x32, 0x68, 0x4f, + 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0xd0, 0x01, 0x92, 0x41, 0x68, 0x32, 0x66, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, - 0x67, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x20, 0x49, 0x66, 0x20, - 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, - 0x6c, 0x61, 0x74, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x62, 0x61, 0x73, 0x65, - 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0xba, 0x48, 0x62, 0xba, 0x01, 0x5f, 0x0a, 0x0b, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x34, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, - 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, - 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, - 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, - 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0b, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x8e, 0x01, 0x92, 0x41, 0x8a, 0x01, - 0x0a, 0x51, 0x2a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x32, 0x36, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x32, 0x35, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, - 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, - 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x20, 0x7d, 0x22, 0xf7, 0x01, 0x0a, 0x0e, 0x50, - 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x8a, 0x01, 0x92, 0x41, 0x86, 0x01, 0x0a, 0x4b, - 0x2a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0x38, 0x47, 0x65, 0x74, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x37, 0x7b, 0x22, 0x61, + 0x67, 0x20, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x73, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, + 0x74, 0x65, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x2e, 0xba, 0x48, 0x62, 0xba, 0x01, 0x5f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x34, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x8c, 0x01, 0x92, 0x41, 0x88, 0x01, 0x0a, 0x4f, + 0x2a, 0x0f, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x32, 0x33, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, + 0x69, 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, + 0x6e, 0x20, 0x77, 0x65, 0x69, 0x2e, 0xd2, 0x01, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x32, + 0x35, 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x22, 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0x3a, 0x20, 0x31, 0x20, 0x7d, 0x22, 0xee, 0x01, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, + 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x3a, 0x80, 0x01, 0x92, 0x41, 0x7d, 0x0a, 0x42, 0x2a, 0x10, 0x44, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x2e, + 0x47, 0x65, 0x74, 0x20, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x32, 0x37, + 0x7b, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, + 0x2c, 0x20, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, + 0x3a, 0x20, 0x22, 0x31, 0x22, 0x20, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa6, 0x02, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x44, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x90, 0x02, + 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x42, 0xcd, 0x01, 0x92, 0x41, 0x63, 0x32, 0x61, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x64, 0xba, 0x01, + 0x61, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, + 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, + 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, 0x92, + 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, + 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, 0x01, + 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, 0x74, + 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, 0x28, + 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, + 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, + 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, + 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, + 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x20, + 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, 0x01, + 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, 0x73, + 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x5d, + 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, + 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0xb9, + 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, + 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, + 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, + 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, 0x2d, + 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, 0x5a, + 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, + 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, 0x01, + 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, + 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, + 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, + 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, 0x79, + 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x6d, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, + 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, + 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, 0xc4, + 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, + 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, 0x33, + 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, 0x61, + 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, 0x32, + 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, 0x32, + 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, + 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, + 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, + 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, + 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, 0x22, - 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x22, - 0x31, 0x22, 0x20, 0x7d, 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0xaa, 0x02, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, - 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x92, 0x02, 0x0a, - 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x42, 0xcf, 0x01, 0x92, 0x41, 0x65, 0x32, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, - 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2e, 0xba, 0x48, 0x64, 0xba, - 0x01, 0x61, 0x0a, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x35, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, - 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x73, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x1a, 0x1a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, - 0x20, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, - 0x20, 0x30, 0x29, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x22, 0xa2, 0x0b, 0x0a, 0x03, 0x42, 0x69, 0x64, 0x12, 0xa3, 0x02, 0x0a, 0x09, 0x74, 0x78, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x85, 0x02, - 0x92, 0x41, 0x78, 0x32, 0x64, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, - 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, - 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, - 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x86, 0x01, 0xba, - 0x01, 0x82, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x36, - 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, - 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x68, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x2e, 0x1a, 0x3d, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x61, 0x6c, 0x6c, - 0x28, 0x72, 0x2c, 0x20, 0x72, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, - 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, - 0x27, 0x29, 0x29, 0x20, 0x26, 0x26, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, - 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, - 0xed, 0x01, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0xd4, 0x01, 0x92, 0x41, 0x76, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, + 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, + 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, 0x0a, + 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, + 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x06, 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0x2b, 0xba, 0x48, 0x58, 0xba, - 0x01, 0x55, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x2a, 0x74, 0x68, 0x69, - 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x30, 0x2d, 0x39, - 0x5d, 0x2b, 0x24, 0x27, 0x29, 0x20, 0x26, 0x26, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, - 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0xb9, 0x01, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x95, 0x01, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, - 0x78, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, - 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, - 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x69, 0x6e, 0x2e, 0xba, 0x48, 0x48, 0xba, 0x01, 0x45, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x25, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, - 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x0b, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0xc2, 0x01, 0x0a, 0x15, - 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x8d, 0x01, 0x92, 0x41, - 0x2d, 0x32, 0x2b, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, - 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, 0x48, - 0x5a, 0xba, 0x01, 0x57, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, - 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x13, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0xb8, 0x01, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x87, - 0x01, 0x92, 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, - 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, - 0x20, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0xba, - 0x48, 0x56, 0xba, 0x01, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2c, 0x64, 0x65, 0x63, 0x61, - 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, - 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, - 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x2e, 0x1a, 0x0e, 0x75, 0x69, 0x6e, 0x74, 0x28, 0x74, - 0x68, 0x69, 0x73, 0x29, 0x20, 0x3e, 0x20, 0x30, 0x52, 0x11, 0x64, 0x65, 0x63, 0x61, 0x79, 0x45, - 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3a, 0xc8, 0x02, 0x92, 0x41, - 0xc4, 0x02, 0x0a, 0x71, 0x2a, 0x0b, 0x42, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x32, 0x40, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x69, 0x64, 0x20, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, - 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6e, 0x6f, - 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0xd2, 0x01, - 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0xd2, 0x01, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0xce, 0x01, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, - 0x65, 0x73, 0x22, 0x3a, 0x20, 0x5b, 0x22, 0x66, 0x65, 0x34, 0x63, 0x62, 0x34, 0x37, 0x64, 0x62, - 0x33, 0x36, 0x33, 0x30, 0x35, 0x35, 0x31, 0x62, 0x65, 0x65, 0x64, 0x66, 0x62, 0x64, 0x30, 0x32, - 0x61, 0x37, 0x31, 0x65, 0x63, 0x63, 0x36, 0x39, 0x66, 0x64, 0x35, 0x39, 0x37, 0x35, 0x38, 0x65, - 0x32, 0x62, 0x61, 0x36, 0x39, 0x39, 0x36, 0x30, 0x36, 0x65, 0x32, 0x64, 0x35, 0x63, 0x37, 0x34, - 0x32, 0x38, 0x34, 0x66, 0x66, 0x61, 0x37, 0x22, 0x2c, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, - 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, - 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, - 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, - 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x5d, 0x2c, 0x20, 0x22, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x2c, 0x20, - 0x22, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x20, 0x31, - 0x32, 0x33, 0x34, 0x35, 0x36, 0x7d, 0x22, 0xf7, 0x09, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, + 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x6d, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, + 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x2e, + 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, 0x0a, + 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, 0x32, + 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, 0x32, + 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, + 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, + 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, + 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, 0x01, + 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, 0x41, + 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, + 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x88, + 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, - 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, - 0x36, 0x34, 0x7d, 0x52, 0x08, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x8f, 0x01, - 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x70, 0x92, 0x41, 0x6d, 0x32, 0x6b, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x45, 0x54, 0x48, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, - 0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x61, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x52, 0x09, 0x62, 0x69, 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x6d, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x4a, 0x92, 0x41, 0x47, 0x32, 0x45, 0x4d, 0x61, 0x78, 0x20, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, - 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, - 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, - 0x2e, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x7b, - 0x0a, 0x13, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, - 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0x92, 0x41, 0x48, - 0x32, 0x46, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, - 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, - 0x65, 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x7d, 0x0a, 0x16, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x47, 0x92, 0x41, 0x44, - 0x32, 0x42, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, - 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, - 0x62, 0x69, 0x64, 0x2e, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, - 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, 0x92, 0x41, 0x32, 0x32, 0x30, 0x48, 0x65, 0x78, 0x20, - 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, - 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x10, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x9e, - 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6b, 0x92, - 0x41, 0x68, 0x32, 0x66, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x13, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, - 0x88, 0x01, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x5d, 0x92, 0x41, 0x5a, 0x32, - 0x58, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, - 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, - 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, - 0x61, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, - 0x41, 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, - 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, - 0x6e, 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, - 0x65, 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, - 0x65, 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, - 0x65, 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, - 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, - 0x12, 0x70, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, - 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x2f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x79, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x7d, 0x12, 0x71, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, - 0x63, 0x65, 0x12, 0x21, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, - 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x42, 0xb6, 0x02, 0x92, 0x41, 0x7a, 0x12, 0x78, - 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x5d, 0x0a, 0x1b, - 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, - 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, 0x68, 0x74, 0x74, - 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, - 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, - 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, - 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x69, - 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x69, 0x64, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, - 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x64, 0x0a, 0x15, 0x64, 0x65, 0x63, + 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x42, 0x30, 0x92, 0x41, 0x2d, 0x32, 0x2b, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, + 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x5e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x42, 0x2e, 0x92, 0x41, + 0x2b, 0x32, 0x29, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x61, 0x74, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x20, 0x65, 0x6e, + 0x64, 0x73, 0x20, 0x64, 0x65, 0x63, 0x61, 0x79, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x11, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x32, + 0xa8, 0x03, 0x0a, 0x06, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x07, 0x53, 0x65, + 0x6e, 0x64, 0x42, 0x69, 0x64, 0x12, 0x11, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x1a, 0x18, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, + 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x62, 0x69, 0x64, 0x30, 0x01, 0x12, + 0x6b, 0x0a, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x1c, 0x2e, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, + 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x64, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, 0x12, 0x6c, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x1f, 0x2e, 0x62, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, + 0x65, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x6e, 0x0a, 0x0d, 0x47, 0x65, + 0x74, 0x4d, 0x69, 0x6e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x1a, 0x2e, 0x62, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, + 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x6d, + 0x69, 0x6e, 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x42, 0xb6, 0x02, 0x92, 0x41, 0x7a, + 0x12, 0x78, 0x0a, 0x0a, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x5d, + 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x3e, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, + 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, + 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, + 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x42, 0x69, + 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, + 0x76, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x62, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, + 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0c, 0x42, 0x69, 0x64, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x42, 0x69, 0x64, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x42, 0x69, 0x64, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x0d, 0x42, 0x69, 0x64, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -763,27 +761,27 @@ func file_bidderapi_v1_bidderapi_proto_rawDescGZIP() []byte { var file_bidderapi_v1_bidderapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_bidderapi_v1_bidderapi_proto_goTypes = []interface{}{ - (*PrepayRequest)(nil), // 0: bidderapi.v1.PrepayRequest - (*PrepayResponse)(nil), // 1: bidderapi.v1.PrepayResponse + (*DepositRequest)(nil), // 0: bidderapi.v1.DepositRequest + (*DepositResponse)(nil), // 1: bidderapi.v1.DepositResponse (*EmptyMessage)(nil), // 2: bidderapi.v1.EmptyMessage - (*GetAllowanceRequest)(nil), // 3: bidderapi.v1.GetAllowanceRequest + (*GetDepositRequest)(nil), // 3: bidderapi.v1.GetDepositRequest (*Bid)(nil), // 4: bidderapi.v1.Bid (*Commitment)(nil), // 5: bidderapi.v1.Commitment (*wrapperspb.UInt64Value)(nil), // 6: google.protobuf.UInt64Value } var file_bidderapi_v1_bidderapi_proto_depIdxs = []int32{ - 6, // 0: bidderapi.v1.PrepayRequest.windowNumber:type_name -> google.protobuf.UInt64Value - 6, // 1: bidderapi.v1.PrepayRequest.blockNumber:type_name -> google.protobuf.UInt64Value - 6, // 2: bidderapi.v1.PrepayResponse.windowNumber:type_name -> google.protobuf.UInt64Value - 6, // 3: bidderapi.v1.GetAllowanceRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 0: bidderapi.v1.DepositRequest.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 1: bidderapi.v1.DepositRequest.blockNumber:type_name -> google.protobuf.UInt64Value + 6, // 2: bidderapi.v1.DepositResponse.windowNumber:type_name -> google.protobuf.UInt64Value + 6, // 3: bidderapi.v1.GetDepositRequest.windowNumber:type_name -> google.protobuf.UInt64Value 4, // 4: bidderapi.v1.Bidder.SendBid:input_type -> bidderapi.v1.Bid - 0, // 5: bidderapi.v1.Bidder.PrepayAllowance:input_type -> bidderapi.v1.PrepayRequest - 3, // 6: bidderapi.v1.Bidder.GetAllowance:input_type -> bidderapi.v1.GetAllowanceRequest - 2, // 7: bidderapi.v1.Bidder.GetMinAllowance:input_type -> bidderapi.v1.EmptyMessage + 0, // 5: bidderapi.v1.Bidder.Deposit:input_type -> bidderapi.v1.DepositRequest + 3, // 6: bidderapi.v1.Bidder.GetDeposit:input_type -> bidderapi.v1.GetDepositRequest + 2, // 7: bidderapi.v1.Bidder.GetMinDeposit:input_type -> bidderapi.v1.EmptyMessage 5, // 8: bidderapi.v1.Bidder.SendBid:output_type -> bidderapi.v1.Commitment - 1, // 9: bidderapi.v1.Bidder.PrepayAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 10: bidderapi.v1.Bidder.GetAllowance:output_type -> bidderapi.v1.PrepayResponse - 1, // 11: bidderapi.v1.Bidder.GetMinAllowance:output_type -> bidderapi.v1.PrepayResponse + 1, // 9: bidderapi.v1.Bidder.Deposit:output_type -> bidderapi.v1.DepositResponse + 1, // 10: bidderapi.v1.Bidder.GetDeposit:output_type -> bidderapi.v1.DepositResponse + 1, // 11: bidderapi.v1.Bidder.GetMinDeposit:output_type -> bidderapi.v1.DepositResponse 8, // [8:12] is the sub-list for method output_type 4, // [4:8] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name @@ -798,7 +796,7 @@ func file_bidderapi_v1_bidderapi_proto_init() { } if !protoimpl.UnsafeEnabled { file_bidderapi_v1_bidderapi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrepayRequest); i { + switch v := v.(*DepositRequest); i { case 0: return &v.state case 1: @@ -810,7 +808,7 @@ func file_bidderapi_v1_bidderapi_proto_init() { } } file_bidderapi_v1_bidderapi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrepayResponse); i { + switch v := v.(*DepositResponse); i { case 0: return &v.state case 1: @@ -834,7 +832,7 @@ func file_bidderapi_v1_bidderapi_proto_init() { } } file_bidderapi_v1_bidderapi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetAllowanceRequest); i { + switch v := v.(*GetDepositRequest); i { case 0: return &v.state case 1: diff --git a/gen/go/bidderapi/v1/bidderapi.pb.gw.go b/gen/go/bidderapi/v1/bidderapi.pb.gw.go index b41775cb..c9b33cd2 100644 --- a/gen/go/bidderapi/v1/bidderapi.pb.gw.go +++ b/gen/go/bidderapi/v1/bidderapi.pb.gw.go @@ -53,11 +53,11 @@ func request_Bidder_SendBid_0(ctx context.Context, marshaler runtime.Marshaler, } var ( - filter_Bidder_PrepayAllowance_0 = &utilities.DoubleArray{Encoding: map[string]int{"amount": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} + filter_Bidder_Deposit_0 = &utilities.DoubleArray{Encoding: map[string]int{"amount": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} ) -func request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq PrepayRequest +func request_Bidder_Deposit_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DepositRequest var metadata runtime.ServerMetadata var ( @@ -80,17 +80,17 @@ func request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runtime.Mar if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_PrepayAllowance_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_Deposit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.PrepayAllowance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.Deposit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq PrepayRequest +func local_request_Bidder_Deposit_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DepositRequest var metadata runtime.ServerMetadata var ( @@ -113,65 +113,65 @@ func local_request_Bidder_PrepayAllowance_0(ctx context.Context, marshaler runti if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_PrepayAllowance_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_Deposit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.PrepayAllowance(ctx, &protoReq) + msg, err := server.Deposit(ctx, &protoReq) return msg, metadata, err } var ( - filter_Bidder_GetAllowance_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_Bidder_GetDeposit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_Bidder_GetAllowance_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetAllowanceRequest +func request_Bidder_GetDeposit_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDepositRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetAllowance_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetDeposit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetAllowance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetDeposit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Bidder_GetAllowance_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq GetAllowanceRequest +func local_request_Bidder_GetDeposit_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetDepositRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetAllowance_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Bidder_GetDeposit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetAllowance(ctx, &protoReq) + msg, err := server.GetDeposit(ctx, &protoReq) return msg, metadata, err } -func request_Bidder_GetMinAllowance_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func request_Bidder_GetMinDeposit_0(ctx context.Context, marshaler runtime.Marshaler, client BidderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq EmptyMessage var metadata runtime.ServerMetadata - msg, err := client.GetMinAllowance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetMinDeposit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Bidder_GetMinAllowance_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { +func local_request_Bidder_GetMinDeposit_0(ctx context.Context, marshaler runtime.Marshaler, server BidderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq EmptyMessage var metadata runtime.ServerMetadata - msg, err := server.GetMinAllowance(ctx, &protoReq) + msg, err := server.GetMinDeposit(ctx, &protoReq) return msg, metadata, err } @@ -189,7 +189,7 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser return }) - mux.Handle("POST", pattern_Bidder_PrepayAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Bidder_Deposit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -197,12 +197,12 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/PrepayAllowance", runtime.WithHTTPPathPattern("/v1/bidder/prepay/{amount}")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/Deposit", runtime.WithHTTPPathPattern("/v1/bidder/deposit/{amount}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Bidder_PrepayAllowance_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Bidder_Deposit_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 { @@ -210,11 +210,11 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser return } - forward_Bidder_PrepayAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_Deposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Bidder_GetAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Bidder_GetDeposit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -222,12 +222,12 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetAllowance", runtime.WithHTTPPathPattern("/v1/bidder/get_allowance")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetDeposit", runtime.WithHTTPPathPattern("/v1/bidder/get_deposit")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Bidder_GetAllowance_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Bidder_GetDeposit_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 { @@ -235,11 +235,11 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser return } - forward_Bidder_GetAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_GetDeposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Bidder_GetMinAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Bidder_GetMinDeposit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -247,12 +247,12 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetMinAllowance", runtime.WithHTTPPathPattern("/v1/bidder/get_min_allowance")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetMinDeposit", runtime.WithHTTPPathPattern("/v1/bidder/get_min_deposit")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Bidder_GetMinAllowance_0(annotatedContext, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Bidder_GetMinDeposit_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 { @@ -260,7 +260,7 @@ func RegisterBidderHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser return } - forward_Bidder_GetMinAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_GetMinDeposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -327,69 +327,69 @@ func RegisterBidderHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli }) - mux.Handle("POST", pattern_Bidder_PrepayAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Bidder_Deposit_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, "/bidderapi.v1.Bidder/PrepayAllowance", runtime.WithHTTPPathPattern("/v1/bidder/prepay/{amount}")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/bidderapi.v1.Bidder/Deposit", runtime.WithHTTPPathPattern("/v1/bidder/deposit/{amount}")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Bidder_PrepayAllowance_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Bidder_Deposit_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Bidder_PrepayAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_Deposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Bidder_GetAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Bidder_GetDeposit_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, "/bidderapi.v1.Bidder/GetAllowance", runtime.WithHTTPPathPattern("/v1/bidder/get_allowance")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetDeposit", runtime.WithHTTPPathPattern("/v1/bidder/get_deposit")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Bidder_GetAllowance_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Bidder_GetDeposit_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Bidder_GetAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_GetDeposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Bidder_GetMinAllowance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Bidder_GetMinDeposit_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, "/bidderapi.v1.Bidder/GetMinAllowance", runtime.WithHTTPPathPattern("/v1/bidder/get_min_allowance")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/bidderapi.v1.Bidder/GetMinDeposit", runtime.WithHTTPPathPattern("/v1/bidder/get_min_deposit")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Bidder_GetMinAllowance_0(annotatedContext, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Bidder_GetMinDeposit_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } - forward_Bidder_GetMinAllowance_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Bidder_GetMinDeposit_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -399,19 +399,19 @@ func RegisterBidderHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli var ( pattern_Bidder_SendBid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "bidder", "bid"}, "")) - pattern_Bidder_PrepayAllowance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "bidder", "prepay", "amount"}, "")) + pattern_Bidder_Deposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "bidder", "deposit", "amount"}, "")) - pattern_Bidder_GetAllowance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "bidder", "get_allowance"}, "")) + pattern_Bidder_GetDeposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "bidder", "get_deposit"}, "")) - pattern_Bidder_GetMinAllowance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "bidder", "get_min_allowance"}, "")) + pattern_Bidder_GetMinDeposit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "bidder", "get_min_deposit"}, "")) ) var ( forward_Bidder_SendBid_0 = runtime.ForwardResponseStream - forward_Bidder_PrepayAllowance_0 = runtime.ForwardResponseMessage + forward_Bidder_Deposit_0 = runtime.ForwardResponseMessage - forward_Bidder_GetAllowance_0 = runtime.ForwardResponseMessage + forward_Bidder_GetDeposit_0 = runtime.ForwardResponseMessage - forward_Bidder_GetMinAllowance_0 = runtime.ForwardResponseMessage + forward_Bidder_GetMinDeposit_0 = runtime.ForwardResponseMessage ) diff --git a/gen/go/bidderapi/v1/bidderapi_grpc.pb.go b/gen/go/bidderapi/v1/bidderapi_grpc.pb.go index 62b5586b..e6972471 100644 --- a/gen/go/bidderapi/v1/bidderapi_grpc.pb.go +++ b/gen/go/bidderapi/v1/bidderapi_grpc.pb.go @@ -19,10 +19,10 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Bidder_SendBid_FullMethodName = "/bidderapi.v1.Bidder/SendBid" - Bidder_PrepayAllowance_FullMethodName = "/bidderapi.v1.Bidder/PrepayAllowance" - Bidder_GetAllowance_FullMethodName = "/bidderapi.v1.Bidder/GetAllowance" - Bidder_GetMinAllowance_FullMethodName = "/bidderapi.v1.Bidder/GetMinAllowance" + Bidder_SendBid_FullMethodName = "/bidderapi.v1.Bidder/SendBid" + Bidder_Deposit_FullMethodName = "/bidderapi.v1.Bidder/Deposit" + Bidder_GetDeposit_FullMethodName = "/bidderapi.v1.Bidder/GetDeposit" + Bidder_GetMinDeposit_FullMethodName = "/bidderapi.v1.Bidder/GetMinDeposit" ) // BidderClient is the client API for Bidder service. @@ -33,18 +33,18 @@ type BidderClient interface { // // Send a bid to the bidder mev-commit node. SendBid(ctx context.Context, in *Bid, opts ...grpc.CallOption) (Bidder_SendBidClient, error) - // PrepayAllowance + // Deposit // - // PrepayAllowance is called by the bidder node to add prepaid allowance in the bidder registry. - PrepayAllowance(ctx context.Context, in *PrepayRequest, opts ...grpc.CallOption) (*PrepayResponse, error) - // GetAllowance + // Deposit is called by the bidder node to add deposit in the bidder registry. + Deposit(ctx context.Context, in *DepositRequest, opts ...grpc.CallOption) (*DepositResponse, error) + // GetDeposit // - // GetAllowance is called by the bidder to get its allowance in the bidder registry. - GetAllowance(ctx context.Context, in *GetAllowanceRequest, opts ...grpc.CallOption) (*PrepayResponse, error) - // GetMinAllowance + // GetDeposit is called by the bidder to get its deposit in the bidder registry. + GetDeposit(ctx context.Context, in *GetDepositRequest, opts ...grpc.CallOption) (*DepositResponse, error) + // GetMinDeposit // - // GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. - GetMinAllowance(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PrepayResponse, error) + // GetMinDeposit is called by the bidder to get the minimum deposit required in the bidder registry to make bids. + GetMinDeposit(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*DepositResponse, error) } type bidderClient struct { @@ -87,27 +87,27 @@ func (x *bidderSendBidClient) Recv() (*Commitment, error) { return m, nil } -func (c *bidderClient) PrepayAllowance(ctx context.Context, in *PrepayRequest, opts ...grpc.CallOption) (*PrepayResponse, error) { - out := new(PrepayResponse) - err := c.cc.Invoke(ctx, Bidder_PrepayAllowance_FullMethodName, in, out, opts...) +func (c *bidderClient) Deposit(ctx context.Context, in *DepositRequest, opts ...grpc.CallOption) (*DepositResponse, error) { + out := new(DepositResponse) + err := c.cc.Invoke(ctx, Bidder_Deposit_FullMethodName, in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *bidderClient) GetAllowance(ctx context.Context, in *GetAllowanceRequest, opts ...grpc.CallOption) (*PrepayResponse, error) { - out := new(PrepayResponse) - err := c.cc.Invoke(ctx, Bidder_GetAllowance_FullMethodName, in, out, opts...) +func (c *bidderClient) GetDeposit(ctx context.Context, in *GetDepositRequest, opts ...grpc.CallOption) (*DepositResponse, error) { + out := new(DepositResponse) + err := c.cc.Invoke(ctx, Bidder_GetDeposit_FullMethodName, in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *bidderClient) GetMinAllowance(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PrepayResponse, error) { - out := new(PrepayResponse) - err := c.cc.Invoke(ctx, Bidder_GetMinAllowance_FullMethodName, in, out, opts...) +func (c *bidderClient) GetMinDeposit(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*DepositResponse, error) { + out := new(DepositResponse) + err := c.cc.Invoke(ctx, Bidder_GetMinDeposit_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -122,18 +122,18 @@ type BidderServer interface { // // Send a bid to the bidder mev-commit node. SendBid(*Bid, Bidder_SendBidServer) error - // PrepayAllowance + // Deposit // - // PrepayAllowance is called by the bidder node to add prepaid allowance in the bidder registry. - PrepayAllowance(context.Context, *PrepayRequest) (*PrepayResponse, error) - // GetAllowance + // Deposit is called by the bidder node to add deposit in the bidder registry. + Deposit(context.Context, *DepositRequest) (*DepositResponse, error) + // GetDeposit // - // GetAllowance is called by the bidder to get its allowance in the bidder registry. - GetAllowance(context.Context, *GetAllowanceRequest) (*PrepayResponse, error) - // GetMinAllowance + // GetDeposit is called by the bidder to get its deposit in the bidder registry. + GetDeposit(context.Context, *GetDepositRequest) (*DepositResponse, error) + // GetMinDeposit // - // GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. - GetMinAllowance(context.Context, *EmptyMessage) (*PrepayResponse, error) + // GetMinDeposit is called by the bidder to get the minimum deposit required in the bidder registry to make bids. + GetMinDeposit(context.Context, *EmptyMessage) (*DepositResponse, error) mustEmbedUnimplementedBidderServer() } @@ -144,14 +144,14 @@ type UnimplementedBidderServer struct { func (UnimplementedBidderServer) SendBid(*Bid, Bidder_SendBidServer) error { return status.Errorf(codes.Unimplemented, "method SendBid not implemented") } -func (UnimplementedBidderServer) PrepayAllowance(context.Context, *PrepayRequest) (*PrepayResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method PrepayAllowance not implemented") +func (UnimplementedBidderServer) Deposit(context.Context, *DepositRequest) (*DepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Deposit not implemented") } -func (UnimplementedBidderServer) GetAllowance(context.Context, *GetAllowanceRequest) (*PrepayResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetAllowance not implemented") +func (UnimplementedBidderServer) GetDeposit(context.Context, *GetDepositRequest) (*DepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDeposit not implemented") } -func (UnimplementedBidderServer) GetMinAllowance(context.Context, *EmptyMessage) (*PrepayResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetMinAllowance not implemented") +func (UnimplementedBidderServer) GetMinDeposit(context.Context, *EmptyMessage) (*DepositResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMinDeposit not implemented") } func (UnimplementedBidderServer) mustEmbedUnimplementedBidderServer() {} @@ -187,56 +187,56 @@ func (x *bidderSendBidServer) Send(m *Commitment) error { return x.ServerStream.SendMsg(m) } -func _Bidder_PrepayAllowance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PrepayRequest) +func _Bidder_Deposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DepositRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(BidderServer).PrepayAllowance(ctx, in) + return srv.(BidderServer).Deposit(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bidder_PrepayAllowance_FullMethodName, + FullMethod: Bidder_Deposit_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BidderServer).PrepayAllowance(ctx, req.(*PrepayRequest)) + return srv.(BidderServer).Deposit(ctx, req.(*DepositRequest)) } return interceptor(ctx, in, info, handler) } -func _Bidder_GetAllowance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetAllowanceRequest) +func _Bidder_GetDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetDepositRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(BidderServer).GetAllowance(ctx, in) + return srv.(BidderServer).GetDeposit(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bidder_GetAllowance_FullMethodName, + FullMethod: Bidder_GetDeposit_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BidderServer).GetAllowance(ctx, req.(*GetAllowanceRequest)) + return srv.(BidderServer).GetDeposit(ctx, req.(*GetDepositRequest)) } return interceptor(ctx, in, info, handler) } -func _Bidder_GetMinAllowance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Bidder_GetMinDeposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(EmptyMessage) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(BidderServer).GetMinAllowance(ctx, in) + return srv.(BidderServer).GetMinDeposit(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bidder_GetMinAllowance_FullMethodName, + FullMethod: Bidder_GetMinDeposit_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BidderServer).GetMinAllowance(ctx, req.(*EmptyMessage)) + return srv.(BidderServer).GetMinDeposit(ctx, req.(*EmptyMessage)) } return interceptor(ctx, in, info, handler) } @@ -249,16 +249,16 @@ var Bidder_ServiceDesc = grpc.ServiceDesc{ HandlerType: (*BidderServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "PrepayAllowance", - Handler: _Bidder_PrepayAllowance_Handler, + MethodName: "Deposit", + Handler: _Bidder_Deposit_Handler, }, { - MethodName: "GetAllowance", - Handler: _Bidder_GetAllowance_Handler, + MethodName: "GetDeposit", + Handler: _Bidder_GetDeposit_Handler, }, { - MethodName: "GetMinAllowance", - Handler: _Bidder_GetMinAllowance_Handler, + MethodName: "GetMinDeposit", + Handler: _Bidder_GetMinDeposit_Handler, }, }, Streams: []grpc.StreamDesc{ diff --git a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml index 3d2e0a87..a58adcec 100644 --- a/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml +++ b/gen/openapi/bidderapi/v1/bidderapi.swagger.yaml @@ -37,73 +37,73 @@ paths: required: true schema: $ref: '#/definitions/bidderapiv1Bid' - /v1/bidder/get_allowance: - get: - summary: GetAllowance - description: GetAllowance is called by the bidder to get its allowance in the bidder registry. - operationId: Bidder_GetAllowance + /v1/bidder/deposit/{amount}: + post: + summary: Deposit + description: Deposit is called by the bidder node to add deposit in the bidder registry. + operationId: Bidder_Deposit responses: "200": description: A successful response. schema: - $ref: '#/definitions/v1PrepayResponse' + $ref: '#/definitions/v1DepositResponse' default: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' parameters: + - name: amount + description: Amount of ETH to be deposited in wei. + in: path + required: true + type: string - name: windowNumber - description: Optional window number for querying allowances. If not specified, the current block number is used. + description: Optional window number for querying deposit. If not specified, the current block number is used. in: query required: false type: string format: uint64 - /v1/bidder/get_min_allowance: + - name: blockNumber + description: Optional block number for querying deposit. If specified, calculate window based on this block number. + in: query + required: false + type: string + format: uint64 + /v1/bidder/get_deposit: get: - summary: GetMinAllowance - description: GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. - operationId: Bidder_GetMinAllowance + summary: GetDeposit + description: GetDeposit is called by the bidder to get its deposit in the bidder registry. + operationId: Bidder_GetDeposit responses: "200": description: A successful response. schema: - $ref: '#/definitions/v1PrepayResponse' + $ref: '#/definitions/v1DepositResponse' default: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' - /v1/bidder/prepay/{amount}: - post: - summary: PrepayAllowance - description: PrepayAllowance is called by the bidder node to add prepaid allowance in the bidder registry. - operationId: Bidder_PrepayAllowance + parameters: + - name: windowNumber + description: Optional window number for querying deposits. If not specified, the current block number is used. + in: query + required: false + type: string + format: uint64 + /v1/bidder/get_min_deposit: + get: + summary: GetMinDeposit + description: GetMinDeposit is called by the bidder to get the minimum deposit required in the bidder registry to make bids. + operationId: Bidder_GetMinDeposit responses: "200": description: A successful response. schema: - $ref: '#/definitions/v1PrepayResponse' + $ref: '#/definitions/v1DepositResponse' default: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' - parameters: - - name: amount - description: Amount of ETH to be prepaid in wei. - in: path - required: true - type: string - - name: windowNumber - description: Optional window number for querying allowances. If not specified, the current block number is used. - in: query - required: false - type: string - format: uint64 - - name: blockNumber - description: Optional block number for querying allowance. If specified, calculate window based on this block number. - in: query - required: false - type: string - format: uint64 definitions: bidderapiv1Bid: type: object @@ -200,7 +200,7 @@ definitions: type: string format: int64 description: Timestamp at which the bid ends decaying. - v1PrepayResponse: + v1DepositResponse: type: object example: amount: "1000000000000000000" @@ -211,5 +211,5 @@ definitions: windowNumber: type: string format: uint64 - description: Get prepaid allowance for bidder in the bidder registry. - title: Prepay response + description: Get deposit for bidder in the bidder registry. + title: Deposit response diff --git a/go.mod b/go.mod index a092a297..ecb039e7 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 - github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60 + github.com/primevprotocol/contracts-abi v0.2.4-0.20240423171419-a959d3727058 github.com/prometheus/client_golang v1.18.0 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 diff --git a/go.sum b/go.sum index 516afc55..f9f6c1e1 100644 --- a/go.sum +++ b/go.sum @@ -350,6 +350,8 @@ github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8 h1: github.com/primevprotocol/contracts-abi v0.2.4-0.20240418181518-36932433f9a8/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60 h1:FEYkczFrI/CwTZRm0wARuWshpn185BEw4uFAKxlqQBg= github.com/primevprotocol/contracts-abi v0.2.4-0.20240419134844-6dd1a8c7bf60/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240423171419-a959d3727058 h1:IG9XeHGs8/S9tW/4dfLosOa6NL0LGODp+FvWVIWNIBE= +github.com/primevprotocol/contracts-abi v0.2.4-0.20240423171419-a959d3727058/go.mod h1:dE2KkvEqC+itvPa3SCrqQfvH5Hfnfn6omNRwWDTdIp8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= diff --git a/integrationtest/bidder/main.go b/integrationtest/bidder/main.go index 9d6a94aa..af158508 100644 --- a/integrationtest/bidder/main.go +++ b/integrationtest/bidder/main.go @@ -188,7 +188,7 @@ func main() { defer ticker.Stop() for { - err = checkOrPrepay(bidderClient, logger) + err = checkOrDeposit(bidderClient, logger) if err != nil { logger.Error("failed to check or stake", "error", err) } @@ -213,52 +213,52 @@ func main() { wg.Wait() } -func checkOrPrepay( +func checkOrDeposit( bidderClient pb.BidderClient, logger *slog.Logger, ) error { - allowance, err := bidderClient.GetAllowance(context.Background(), &pb.GetAllowanceRequest{}) + deposit, err := bidderClient.GetDeposit(context.Background(), &pb.GetDepositRequest{}) if err != nil { - logger.Error("failed to get allowance", "error", err) + logger.Error("failed to get deposit", "error", err) return err } - logger.Info("prepaid allowance", "amount", allowance.Amount) + logger.Info("deposited", "amount", deposit.Amount) - minAllowance, err := bidderClient.GetMinAllowance(context.Background(), &pb.EmptyMessage{}) + minDeposit, err := bidderClient.GetMinDeposit(context.Background(), &pb.EmptyMessage{}) if err != nil { - logger.Error("failed to get min allowance", "error", err) + logger.Error("failed to get min deposit", "error", err) return err } - allowanceAmt, set := big.NewInt(0).SetString(allowance.Amount, 10) + depositAmt, set := big.NewInt(0).SetString(deposit.Amount, 10) if !set { - logger.Error("failed to parse allowance amount") - return errors.New("failed to parse allowance amount") + logger.Error("failed to parse deposit amount") + return errors.New("failed to parse deposit amount") } - minAllowanceAmt, set := big.NewInt(0).SetString(minAllowance.Amount, 10) + minDepositAmt, set := big.NewInt(0).SetString(minDeposit.Amount, 10) if !set { - logger.Error("failed to parse min allowance amount") - return errors.New("failed to parse min allowance amount") + logger.Error("failed to parse min deposit amount") + return errors.New("failed to parse min deposit amount") } - if allowanceAmt.Cmp(minAllowanceAmt) > 0 { + if depositAmt.Cmp(minDepositAmt) > 0 { logger.Error("bidder already has balance") return nil } - topup := big.NewInt(0).Mul(minAllowanceAmt, big.NewInt(10)) + topup := big.NewInt(0).Mul(minDepositAmt, big.NewInt(10)) - _, err = bidderClient.PrepayAllowance(context.Background(), &pb.PrepayRequest{ + _, err = bidderClient.Deposit(context.Background(), &pb.DepositRequest{ Amount: topup.String(), }) if err != nil { - logger.Error("failed to prepay allowance", "error", err) + logger.Error("failed to deposit", "error", err) return err } - logger.Info("prepaid allowance", "amount", topup.String()) + logger.Info("deposit", "amount", topup.String()) return nil } diff --git a/integrationtest/real-bidder/main.go b/integrationtest/real-bidder/main.go index 95ce1e0a..02f7b1b9 100644 --- a/integrationtest/real-bidder/main.go +++ b/integrationtest/real-bidder/main.go @@ -128,7 +128,7 @@ func main() { defer ticker.Stop() for { - err = checkOrPrepay(bidderClient, logger) + err = checkOrDeposit(bidderClient, logger) if err != nil { logger.Error("failed to check or stake", "err", err) } @@ -227,52 +227,52 @@ func RetreivedBlock(rpcClient *ethclient.Client) ([]string, int64, error) { return blockTxns, int64(blkNum), nil } -func checkOrPrepay( +func checkOrDeposit( bidderClient pb.BidderClient, logger *slog.Logger, ) error { - allowance, err := bidderClient.GetAllowance(context.Background(), &pb.GetAllowanceRequest{}) + deposit, err := bidderClient.GetDeposit(context.Background(), &pb.GetDepositRequest{}) if err != nil { - logger.Error("failed to get allowance", "err", err) + logger.Error("failed to get deposit", "err", err) return err } - logger.Info("prepaid allowance", "amount", allowance.Amount) + logger.Info("deposit", "amount", deposit.Amount) - minAllowance, err := bidderClient.GetMinAllowance(context.Background(), &pb.EmptyMessage{}) + minDeposit, err := bidderClient.GetMinDeposit(context.Background(), &pb.EmptyMessage{}) if err != nil { - logger.Error("failed to get min allowance", "err", err) + logger.Error("failed to get min deposit", "err", err) return err } - allowanceAmt, set := big.NewInt(0).SetString(allowance.Amount, 10) + depositAmt, set := big.NewInt(0).SetString(deposit.Amount, 10) if !set { - logger.Error("failed to parse allowance amount") - return errors.New("failed to parse allowance amount") + logger.Error("failed to parse deposit amount") + return errors.New("failed to parse deposit amount") } - minAllowanceAmt, set := big.NewInt(0).SetString(minAllowance.Amount, 10) + minDepositAmt, set := big.NewInt(0).SetString(minDeposit.Amount, 10) if !set { - logger.Error("failed to parse min allowance amount") - return errors.New("failed to parse min allowance amount") + logger.Error("failed to parse min deposit amount") + return errors.New("failed to parse min deposit amount") } - if allowanceAmt.Cmp(minAllowanceAmt) > 0 { + if depositAmt.Cmp(minDepositAmt) > 0 { logger.Error("bidder already has balance") return nil } - topup := big.NewInt(0).Mul(minAllowanceAmt, big.NewInt(10)) + topup := big.NewInt(0).Mul(minDepositAmt, big.NewInt(10)) - _, err = bidderClient.PrepayAllowance(context.Background(), &pb.PrepayRequest{ + _, err = bidderClient.Deposit(context.Background(), &pb.DepositRequest{ Amount: topup.String(), }) if err != nil { - logger.Error("failed to prepay allowance", "err", err) + logger.Error("failed to deposit", "err", err) return err } - logger.Info("prepaid allowance", "amount", topup.String()) + logger.Info("deposit", "amount", topup.String()) return nil } diff --git a/pkg/contracts/bidder_registry/bidder_registry.go b/pkg/contracts/bidder_registry/bidder_registry.go index d47ceeeb..c938d3e0 100644 --- a/pkg/contracts/bidder_registry/bidder_registry.go +++ b/pkg/contracts/bidder_registry/bidder_registry.go @@ -22,16 +22,16 @@ var bidderRegistryABI = func() abi.ABI { } type Interface interface { - // PrepayAllowanceForSpecificWindow registers a bidder with the bidder_registry contract for a specific window. - PrepayAllowanceForSpecificWindow(ctx context.Context, amount, window *big.Int) error - // GetAllowance returns the stake of a bidder. - GetAllowance(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) - // GetMinAllowance returns the minimum stake required to register as a bidder. - GetMinAllowance(ctx context.Context) (*big.Int, error) + // DepositForSpecificWindow registers a bidder with the bidder_registry contract for a specific window. + DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error + // GetDeposit returns the stake of a bidder. + GetDeposit(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) + // GetMinDeposit returns the minimum stake required to register as a bidder. + GetMinDeposit(ctx context.Context) (*big.Int, error) // CheckBidderRegistred returns true if bidder is registered - CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int, blocksPerWindow *big.Int) bool - // WithdrawAllowance withdraws the stake of a bidder. - WithdrawAllowance(ctx context.Context, window *big.Int) error + CheckBidderDeposit(ctx context.Context, address common.Address, window, blocksPerWindow *big.Int) bool + // WithdrawDeposit withdraws the stake of a bidder. + WithdrawDeposit(ctx context.Context, window *big.Int) error } type bidderRegistryContract struct { @@ -57,8 +57,8 @@ func New( } } -func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, amount, window *big.Int) error { - callData, err := r.bidderRegistryABI.Pack("prepayAllowanceForSpecificWindow", window) +func (r *bidderRegistryContract) DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error { + callData, err := r.bidderRegistryABI.Pack("depositForSpecificWindow", window) if err != nil { r.logger.Error("error packing call data", "error", err) return err @@ -80,7 +80,7 @@ func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Co if receipt.Status != types.ReceiptStatusSuccessful { r.logger.Error( - "prepay failed for bidder registry", + "deposit failed for bidder registry", "txnHash", txnHash, "receipt", receipt, ) @@ -89,7 +89,7 @@ func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Co var bidderRegistered struct { Bidder common.Address - PrepaidAmount *big.Int + DepositedAmount *big.Int WindowNumber *big.Int } for _, log := range receipt.Logs { @@ -99,23 +99,23 @@ func (r *bidderRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Co err := r.bidderRegistryABI.UnpackIntoInterface(&bidderRegistered, "BidderRegistered", log.Data) if err != nil { - r.logger.Debug("Failed to unpack event", "err", err) + r.logger.Debug("failed to unpack event", "err", err) continue } - r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "prepaidAmount", bidderRegistered.PrepaidAmount.String(), "windowNumber", bidderRegistered.WindowNumber.Int64()) + r.logger.Info("bidder registered", "address", bidderRegistered.Bidder, "depositedAmount", bidderRegistered.DepositedAmount.String(), "windowNumber", bidderRegistered.WindowNumber.Int64()) } - r.logger.Info("prepay successful for bidder registry", "txnHash", txnHash, "bidder", bidderRegistered.Bidder) + r.logger.Info("deposit successful for bidder registry", "txnHash", txnHash, "bidder", bidderRegistered.Bidder) return nil } -func (r *bidderRegistryContract) GetAllowance( +func (r *bidderRegistryContract) GetDeposit( ctx context.Context, address common.Address, window *big.Int, ) (*big.Int, error) { - callData, err := r.bidderRegistryABI.Pack("getAllowance", address, window) + callData, err := r.bidderRegistryABI.Pack("getDeposit", address, window) if err != nil { r.logger.Error("error packing call data", "error", err) return nil, err @@ -129,7 +129,7 @@ func (r *bidderRegistryContract) GetAllowance( return nil, err } - results, err := r.bidderRegistryABI.Unpack("getAllowance", result) + results, err := r.bidderRegistryABI.Unpack("getDeposit", result) if err != nil { r.logger.Error("error unpacking result", "error", err) return nil, err @@ -138,8 +138,8 @@ func (r *bidderRegistryContract) GetAllowance( return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil } -func (r *bidderRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, error) { - callData, err := r.bidderRegistryABI.Pack("minAllowance") +func (r *bidderRegistryContract) GetMinDeposit(ctx context.Context) (*big.Int, error) { + callData, err := r.bidderRegistryABI.Pack("minDeposit") if err != nil { r.logger.Error("error packing call data", "error", err) return nil, err @@ -153,7 +153,7 @@ func (r *bidderRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, return nil, err } - results, err := r.bidderRegistryABI.Unpack("minAllowance", result) + results, err := r.bidderRegistryABI.Unpack("minDeposit", result) if err != nil { r.logger.Error("error unpacking result", "error", err) return nil, err @@ -162,7 +162,7 @@ func (r *bidderRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil } -func (r *bidderRegistryContract) WithdrawAllowance(ctx context.Context, window *big.Int) error { +func (r *bidderRegistryContract) WithdrawDeposit(ctx context.Context, window *big.Int) error { callData, err := r.bidderRegistryABI.Pack("withdrawBidderAmountFromWindow", r.owner, window) if err != nil { r.logger.Error("error packing call data", "error", err) @@ -215,24 +215,24 @@ func (r *bidderRegistryContract) WithdrawAllowance(ctx context.Context, window * return nil } -func (r *bidderRegistryContract) CheckBidderAllowance( +func (r *bidderRegistryContract) CheckBidderDeposit( ctx context.Context, address common.Address, window *big.Int, blocksPerWindow *big.Int, ) bool { - minStake, err := r.GetMinAllowance(ctx) + minStake, err := r.GetMinDeposit(ctx) if err != nil { r.logger.Error("error getting min stake", "error", err) return false } - stake, err := r.GetAllowance(ctx, address, window) + stake, err := r.GetDeposit(ctx, address, window) if err != nil { r.logger.Error("error getting stake", "error", err) return false } - r.logger.Info("checking bidder allowance", + r.logger.Info("checking bidder deposit", "stake", stake.Uint64(), "blocksPerWindow", blocksPerWindow.Uint64(), "minStake", minStake.Uint64(), diff --git a/pkg/contracts/bidder_registry/bidder_registry_test.go b/pkg/contracts/bidder_registry/bidder_registry_test.go index a4cef71f..54bb4f65 100644 --- a/pkg/contracts/bidder_registry/bidder_registry_test.go +++ b/pkg/contracts/bidder_registry/bidder_registry_test.go @@ -20,13 +20,13 @@ func TestBidderRegistryContract(t *testing.T) { owner := common.HexToAddress("abcd") - t.Run("PrepayAllowance", func(t *testing.T) { + t.Run("Deposit", func(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") txHash := common.HexToHash("abcdef") amount := big.NewInt(1000000000000000000) window := big.NewInt(1) - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("prepayAllowanceForSpecificWindow", window) + expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("depositForSpecificWindow", window) if err != nil { t.Fatal(err) } @@ -74,18 +74,18 @@ func TestBidderRegistryContract(t *testing.T) { mockClient, util.NewTestLogger(os.Stdout), ) - err = registryContract.PrepayAllowanceForSpecificWindow(context.Background(), amount, big.NewInt(1)) + err = registryContract.DepositForSpecificWindow(context.Background(), amount, big.NewInt(1)) if err != nil { t.Fatal(err) } }) - t.Run("GetAllowance", func(t *testing.T) { + t.Run("GetDeposit", func(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") amount := big.NewInt(1000000000000000000) address := common.HexToAddress("abcdef") window := big.NewInt(1) - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("getAllowance", address, window) + expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("getDeposit", address, window) if err != nil { t.Fatal(err) } @@ -114,7 +114,7 @@ func TestBidderRegistryContract(t *testing.T) { mockClient, util.NewTestLogger(os.Stdout), ) - stakeAmt, err := registryContract.GetAllowance(context.Background(), address, window) + stakeAmt, err := registryContract.GetDeposit(context.Background(), address, window) if err != nil { t.Fatal(err) } @@ -128,7 +128,7 @@ func TestBidderRegistryContract(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") amount := big.NewInt(1000000000000000000) - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("minAllowance") + expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("minDeposit") if err != nil { t.Fatal(err) } @@ -158,7 +158,7 @@ func TestBidderRegistryContract(t *testing.T) { util.NewTestLogger(os.Stdout), ) - stakeAmt, err := registryContract.GetMinAllowance(context.Background()) + stakeAmt, err := registryContract.GetMinDeposit(context.Background()) if err != nil { t.Fatal(err) } @@ -168,7 +168,7 @@ func TestBidderRegistryContract(t *testing.T) { } }) - t.Run("CheckBidderAllowance", func(t *testing.T) { + t.Run("CheckBidderDeposit", func(t *testing.T) { registryContractAddr := common.HexToAddress("abcd") blocksPerWindow := big.NewInt(64) amount := new(big.Int).Mul(big.NewInt(1000000000000000000), blocksPerWindow) @@ -204,7 +204,7 @@ func TestBidderRegistryContract(t *testing.T) { ) window := big.NewInt(1) - isRegistered := registryContract.CheckBidderAllowance(context.Background(), address, window, blocksPerWindow) + isRegistered := registryContract.CheckBidderDeposit(context.Background(), address, window, blocksPerWindow) if !isRegistered { t.Fatal("expected bidder to be registered") } diff --git a/pkg/allowancemanager/allowance.go b/pkg/depositmanager/deposit.go similarity index 77% rename from pkg/allowancemanager/allowance.go rename to pkg/depositmanager/deposit.go index 2036e118..a218c9ca 100644 --- a/pkg/allowancemanager/allowance.go +++ b/pkg/depositmanager/deposit.go @@ -1,4 +1,4 @@ -package allowancemanager +package depositmanager import ( "context" @@ -19,8 +19,8 @@ import ( ) type BidderRegistry interface { - CheckBidderAllowance(context.Context, common.Address, *big.Int, *big.Int) bool - GetMinAllowance(ctx context.Context) (*big.Int, error) + CheckBidderDeposit(context.Context, common.Address, *big.Int, *big.Int) bool + GetMinDeposit(ctx context.Context) (*big.Int, error) } type Store interface { @@ -30,27 +30,27 @@ type Store interface { RefundBalanceForBlock(bidder common.Address, amount *big.Int, blockNumber int64) error } -type AllowanceManager struct { +type DepositManager struct { bidderRegistry BidderRegistry blockTracker blocktrackercontract.Interface commitmentDA preconfcontract.Interface store Store evtMgr events.EventManager blocksPerWindow atomic.Uint64 // todo: move to the store - minAllowance atomic.Int64 // todo: move to the store + minDeposit atomic.Int64 // todo: move to the store currentWindow atomic.Int64 // todo: move to the store logger *slog.Logger } -func NewAllowanceManager( +func NewDepositManager( br BidderRegistry, blockTracker blocktrackercontract.Interface, commitmentDA preconfcontract.Interface, store Store, evtMgr events.EventManager, logger *slog.Logger, -) *AllowanceManager { - return &AllowanceManager{ +) *DepositManager { + return &DepositManager{ bidderRegistry: br, blockTracker: blockTracker, commitmentDA: commitmentDA, @@ -60,7 +60,7 @@ func NewAllowanceManager( } } -func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { +func (a *DepositManager) Start(ctx context.Context) <-chan struct{} { doneChan := make(chan struct{}) eg, egCtx := errgroup.WithContext(ctx) @@ -84,7 +84,7 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { "BidderRegistered", func(bidderReg *bidderregistry.BidderregistryBidderRegistered) error { // todo: do we need to check if commiter is connected to this bidder? - return a.store.SetBalance(bidderReg.Bidder, bidderReg.WindowNumber, bidderReg.PrepaidAmount) + return a.store.SetBalance(bidderReg.Bidder, bidderReg.WindowNumber, bidderReg.DepositedAmount) }, ) @@ -107,14 +107,14 @@ func (a *AllowanceManager) Start(ctx context.Context) <-chan struct{} { go func() { defer close(doneChan) if err := eg.Wait(); err != nil { - a.logger.Error("error in AllowanceManager", "error", err) + a.logger.Error("error in DepositManager", "error", err) } }() return doneChan } -func (a *AllowanceManager) CheckAndDeductAllowance(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { +func (a *DepositManager) CheckAndDeductDeposit(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { if a.blocksPerWindow.Load() == 0 { blocksPerWindow, err := a.blockTracker.GetBlocksPerWindow(ctx) if err != nil { @@ -124,14 +124,14 @@ func (a *AllowanceManager) CheckAndDeductAllowance(ctx context.Context, address a.blocksPerWindow.Store(blocksPerWindow) } - if a.minAllowance.Load() == 0 { - minAllowance, err := a.bidderRegistry.GetMinAllowance(ctx) + if a.minDeposit.Load() == 0 { + minDeposit, err := a.bidderRegistry.GetMinDeposit(ctx) if err != nil { - a.logger.Error("getting min allowance", "error", err) - return nil, status.Errorf(codes.Internal, "failed to get min allowance: %v", err) + a.logger.Error("getting min deposit", "error", err) + return nil, status.Errorf(codes.Internal, "failed to get min deposit: %v", err) } - a.minAllowance.Store(minAllowance.Int64()) + a.minDeposit.Store(minDeposit.Int64()) } bidAmount, ok := new(big.Int).SetString(bidAmountStr, 10) @@ -154,26 +154,26 @@ func (a *AllowanceManager) CheckAndDeductAllowance(ctx context.Context, address return nil, status.Errorf(codes.FailedPrecondition, "balance not found") } - a.logger.Info("checking bidder allowance", + a.logger.Info("checking bidder deposit", "stake", balance.Uint64(), "blocksPerWindow", a.blocksPerWindow.Load(), - "minStake", a.minAllowance.Load(), + "minStake", a.minDeposit.Load(), "window", windowToCheck.Uint64(), "address", address.Hex(), ) blocksPerWindow := new(big.Int).SetUint64(a.blocksPerWindow.Load()) - minAllowance := big.NewInt(a.minAllowance.Load()) + minDeposit := big.NewInt(a.minDeposit.Load()) // todo: make sense to do division only once, when bidder deposit funds, - // not everytime, when checking allowance + // not everytime, when checking deposit effectiveStake := new(big.Int).Div(new(big.Int).Set(balance), blocksPerWindow) - isEnoughAllowance := effectiveStake.Cmp(minAllowance) >= 0 + isEnoughDeposit := effectiveStake.Cmp(minDeposit) >= 0 - if !isEnoughAllowance { - a.logger.Error("bidder does not have enough allowance", "ethAddress", address) - return nil, status.Errorf(codes.FailedPrecondition, "bidder not allowed") + if !isEnoughDeposit { + a.logger.Error("bidder does not have enough deposit", "ethAddress", address) + return nil, status.Errorf(codes.FailedPrecondition, "bidder do not have enough deposit") } deductedBalance, err := a.store.DeductAndCheckBalanceForBlock(address, effectiveStake, bidAmount, blockNumber) @@ -184,6 +184,6 @@ func (a *AllowanceManager) CheckAndDeductAllowance(ctx context.Context, address return deductedBalance, nil } -func (a *AllowanceManager) RefundAllowance(address common.Address, deductedAmount *big.Int, blockNumber int64) error { +func (a *DepositManager) RefundDeposit(address common.Address, deductedAmount *big.Int, blockNumber int64) error { return a.store.RefundBalanceForBlock(address, deductedAmount, blockNumber) } diff --git a/pkg/events/events_test.go b/pkg/events/events_test.go index bdf27e3d..1fd28062 100644 --- a/pkg/events/events_test.go +++ b/pkg/events/events_test.go @@ -23,9 +23,9 @@ func TestEventHandler(t *testing.T) { t.Parallel() b := bidderregistry.BidderregistryBidderRegistered{ - Bidder: common.HexToAddress("0xabcd"), - PrepaidAmount: big.NewInt(1000), - WindowNumber: big.NewInt(99), + Bidder: common.HexToAddress("0xabcd"), + DepositedAmount: big.NewInt(1000), + WindowNumber: big.NewInt(99), } evtHdlr := events.NewEventHandler( @@ -34,8 +34,8 @@ func TestEventHandler(t *testing.T) { if ev.Bidder.Hex() != b.Bidder.Hex() { return fmt.Errorf("expected bidder %s, got %s", b.Bidder.Hex(), ev.Bidder.Hex()) } - if ev.PrepaidAmount.Cmp(b.PrepaidAmount) != 0 { - return fmt.Errorf("expected prepaid amount %d, got %d", b.PrepaidAmount, ev.PrepaidAmount) + if ev.DepositedAmount.Cmp(b.DepositedAmount) != 0 { + return fmt.Errorf("expected deposited amount %d, got %d", b.DepositedAmount, ev.DepositedAmount) } if ev.WindowNumber.Cmp(b.WindowNumber) != 0 { return fmt.Errorf("expected window number %d, got %d", b.WindowNumber, ev.WindowNumber) @@ -62,7 +62,7 @@ func TestEventHandler(t *testing.T) { } buf, err := event.Inputs.NonIndexed().Pack( - b.PrepaidAmount, + b.DepositedAmount, b.WindowNumber, ) if err != nil { @@ -90,14 +90,14 @@ func TestEventManager(t *testing.T) { bidders := []bidderregistry.BidderregistryBidderRegistered{ { - Bidder: common.HexToAddress("0xabcd"), - PrepaidAmount: big.NewInt(1000), - WindowNumber: big.NewInt(99), + Bidder: common.HexToAddress("0xabcd"), + DepositedAmount: big.NewInt(1000), + WindowNumber: big.NewInt(99), }, { - Bidder: common.HexToAddress("0xcdef"), - PrepaidAmount: big.NewInt(2000), - WindowNumber: big.NewInt(100), + Bidder: common.HexToAddress("0xcdef"), + DepositedAmount: big.NewInt(2000), + WindowNumber: big.NewInt(100), }, } @@ -115,8 +115,8 @@ func TestEventManager(t *testing.T) { if ev.Bidder.Hex() != bidders[count].Bidder.Hex() { return fmt.Errorf("expected bidder %s, got %s", bidders[count].Bidder.Hex(), ev.Bidder.Hex()) } - if ev.PrepaidAmount.Cmp(bidders[count].PrepaidAmount) != 0 { - return fmt.Errorf("expected prepaid amount %d, got %d", bidders[count].PrepaidAmount, ev.PrepaidAmount) + if ev.DepositedAmount.Cmp(bidders[count].DepositedAmount) != 0 { + return fmt.Errorf("expected deposited amount %d, got %d", bidders[count].DepositedAmount, ev.DepositedAmount) } if ev.WindowNumber.Cmp(bidders[count].WindowNumber) != 0 { return fmt.Errorf("expected window number %d, got %d", bidders[count].WindowNumber, ev.WindowNumber) @@ -137,7 +137,7 @@ func TestEventManager(t *testing.T) { } data1, err := bidderABI.Events["BidderRegistered"].Inputs.NonIndexed().Pack( - bidders[0].PrepaidAmount, + bidders[0].DepositedAmount, bidders[0].WindowNumber, ) if err != nil { @@ -145,7 +145,7 @@ func TestEventManager(t *testing.T) { } data2, err := bidderABI.Events["BidderRegistered"].Inputs.NonIndexed().Pack( - bidders[1].PrepaidAmount, + bidders[1].DepositedAmount, bidders[1].WindowNumber, ) if err != nil { diff --git a/pkg/node/node.go b/pkg/node/node.go index b9256b61..ed8203df 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -24,7 +24,7 @@ import ( bidderapiv1 "github.com/primevprotocol/mev-commit/gen/go/bidderapi/v1" preconfpb "github.com/primevprotocol/mev-commit/gen/go/preconfirmation/v1" providerapiv1 "github.com/primevprotocol/mev-commit/gen/go/providerapi/v1" - "github.com/primevprotocol/mev-commit/pkg/allowancemanager" + "github.com/primevprotocol/mev-commit/pkg/depositmanager" "github.com/primevprotocol/mev-commit/pkg/apiserver" bidder_registrycontract "github.com/primevprotocol/mev-commit/pkg/contracts/bidder_registry" blocktrackercontract "github.com/primevprotocol/mev-commit/pkg/contracts/block_tracker" @@ -250,7 +250,7 @@ func NewNode(opts *Options) (*Node, error) { var ( bidProcessor preconfirmation.BidProcessor = noOpBidProcessor{} - allowanceMgr preconfirmation.AllowanceManager = noOpAllowanceManager{} + depositMgr preconfirmation.DepositManager = noOpDepositManager{} ) blockTrackerAddr := common.HexToAddress(opts.BlockTrackerContract) @@ -289,20 +289,20 @@ func NewNode(opts *Options) (*Node, error) { providerapiv1.RegisterProviderServer(grpcServer, providerAPI) bidProcessor = providerAPI srv.RegisterMetricsCollectors(providerAPI.Metrics()...) - allowanceMgr = allowancemanager.NewAllowanceManager(bidderRegistry, + depositMgr = depositmanager.NewDepositManager(bidderRegistry, blockTracker, commitmentDA, store, evtMgr, - opts.Logger.With("component", "allowancemanager"), + opts.Logger.With("component", "depositmanager"), ) - allowanceMgr.Start(ctx) + depositMgr.Start(ctx) preconfProto := preconfirmation.New( keyKeeper.GetAddress(), topo, p2pSvc, preconfEncryptor, - allowanceMgr, + depositMgr, bidProcessor, commitmentDA, blockTracker, @@ -331,7 +331,7 @@ func NewNode(opts *Options) (*Node, error) { topo, p2pSvc, preconfEncryptor, - allowanceMgr, + depositMgr, bidProcessor, commitmentDA, blockTracker, @@ -564,16 +564,16 @@ func (noOpBidProcessor) ProcessBid( return statusC, nil } -type noOpAllowanceManager struct{} +type noOpDepositManager struct{} -func (noOpAllowanceManager) Start(_ context.Context) <-chan struct{} { +func (noOpDepositManager) Start(_ context.Context) <-chan struct{} { return nil } -func (noOpAllowanceManager) CheckAndDeductAllowance(_ context.Context, _ common.Address, _ string, _ int64) (*big.Int, error) { +func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Address, _ string, _ int64) (*big.Int, error) { return big.NewInt(0), nil } -func (noOpAllowanceManager) RefundAllowance(_ common.Address, _ *big.Int, _ int64) error { +func (noOpDepositManager) RefundDeposit(_ common.Address, _ *big.Int, _ int64) error { return nil } diff --git a/pkg/preconfirmation/preconfirmation.go b/pkg/preconfirmation/preconfirmation.go index 984c42a8..bbd25ac8 100644 --- a/pkg/preconfirmation/preconfirmation.go +++ b/pkg/preconfirmation/preconfirmation.go @@ -36,7 +36,7 @@ type Preconfirmation struct { encryptor encryptor.Encryptor topo Topology streamer p2p.Streamer - allowanceMgr AllowanceManager + depositMgr DepositManager processer BidProcessor commitmentDA preconfcontract.Interface blockTracker blocktrackercontract.Interface @@ -64,10 +64,10 @@ type EncrDecrCommitmentStore interface { SetCommitmentIndexByCommitmentDigest(commitmentDigest, commitmentIndex [32]byte) error } -type AllowanceManager interface { +type DepositManager interface { Start(ctx context.Context) <-chan struct{} - CheckAndDeductAllowance(ctx context.Context, ethAddress common.Address, bidAmount string, blockNumber int64) (*big.Int, error) - RefundAllowance(ethAddress common.Address, amount *big.Int, blockNumber int64) error + CheckAndDeductDeposit(ctx context.Context, ethAddress common.Address, bidAmount string, blockNumber int64) (*big.Int, error) + RefundDeposit(ethAddress common.Address, amount *big.Int, blockNumber int64) error } func New( @@ -75,7 +75,7 @@ func New( topo Topology, streamer p2p.Streamer, encryptor encryptor.Encryptor, - allowanceMgr AllowanceManager, + depositMgr DepositManager, processor BidProcessor, commitmentDA preconfcontract.Interface, blockTracker blocktrackercontract.Interface, @@ -88,7 +88,7 @@ func New( topo: topo, streamer: streamer, encryptor: encryptor, - allowanceMgr: allowanceMgr, + depositMgr: depositMgr, processer: processor, commitmentDA: commitmentDA, blockTracker: blockTracker, @@ -335,9 +335,9 @@ func (p *Preconfirmation) handleBid( return err } - deductedAmount, err := p.allowanceMgr.CheckAndDeductAllowance(ctx, *ethAddress, bid.BidAmount, bid.BlockNumber) + deductedAmount, err := p.depositMgr.CheckAndDeductDeposit(ctx, *ethAddress, bid.BidAmount, bid.BlockNumber) if err != nil { - p.logger.Error("checking allowance", "error", err) + p.logger.Error("checking deposit", "error", err) return err } @@ -346,9 +346,9 @@ func (p *Preconfirmation) handleBid( defer func() { if !successful { // Refund the deducted amount if the bid process did not succeed - refundErr := p.allowanceMgr.RefundAllowance(*ethAddress, deductedAmount, bid.BlockNumber) + refundErr := p.depositMgr.RefundDeposit(*ethAddress, deductedAmount, bid.BlockNumber) if refundErr != nil { - p.logger.Error("refunding allowance", "error", refundErr) + p.logger.Error("refunding deposit", "error", refundErr) } } }() @@ -433,7 +433,7 @@ func (p *Preconfirmation) handleNewL1Block(ctx context.Context, newL1Block *bloc duration := time.Since(startTime) p.logger.Info("opened commitment", "txHash", txHash, "duration", duration) } - + err = p.ecds.DeleteCommitmentByBlockNumber(newL1Block.BlockNumber.Int64()) if err != nil { p.logger.Error("failed to delete commitments by block number", "error", err) diff --git a/pkg/preconfirmation/preconfirmation_test.go b/pkg/preconfirmation/preconfirmation_test.go index d6b08b18..f6182bfa 100644 --- a/pkg/preconfirmation/preconfirmation_test.go +++ b/pkg/preconfirmation/preconfirmation_test.go @@ -165,17 +165,17 @@ func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { return slog.New(testLogger) } -type testAllowanceManager struct{} +type testDepositManager struct{} -func (t *testAllowanceManager) Start(ctx context.Context) <-chan struct{} { +func (t *testDepositManager) Start(ctx context.Context) <-chan struct{} { return nil } -func (t *testAllowanceManager) CheckAndDeductAllowance(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { +func (t *testDepositManager) CheckAndDeductDeposit(ctx context.Context, address common.Address, bidAmountStr string, blockNumber int64) (*big.Int, error) { return big.NewInt(0), nil } -func (t *testAllowanceManager) RefundAllowance(address common.Address, deductedAmount *big.Int, blockNumber int64) error { +func (t *testDepositManager) RefundDeposit(address common.Address, deductedAmount *big.Int, blockNumber int64) error { return nil } @@ -262,13 +262,13 @@ func TestPreconfBidSubmission(t *testing.T) { if err != nil { t.Fatal(err) } - allowanceMgr := &testAllowanceManager{} + depositMgr := &testDepositManager{} p := preconfirmation.New( client.EthAddress, topo, svc, signer, - allowanceMgr, + depositMgr, proc, &testCommitmentDA{}, &testBlockTrackerContract{blockNumberToWinner: make(map[uint64]common.Address), blocksPerWindow: 64}, diff --git a/pkg/rpc/bidder/service.go b/pkg/rpc/bidder/service.go index 85e31dc6..a8f0d9eb 100644 --- a/pkg/rpc/bidder/service.go +++ b/pkg/rpc/bidder/service.go @@ -111,13 +111,13 @@ func (s *Service) SendBid( return nil } -func (s *Service) PrepayAllowance( +func (s *Service) Deposit( ctx context.Context, - r *bidderapiv1.PrepayRequest, -) (*bidderapiv1.PrepayResponse, error) { + r *bidderapiv1.DepositRequest, +) (*bidderapiv1.DepositResponse, error) { err := s.validator.Validate(r) if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "validating prepay request: %v", err) + return nil, status.Errorf(codes.InvalidArgument, "validating deposit request: %v", err) } currentWindow, err := s.blockTrackerContract.GetCurrentWindow(ctx) @@ -130,16 +130,16 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.InvalidArgument, "calculating window to deposit: %v", err) } if _, ok := s.depositedWindows[windowToDeposit]; ok { - return nil, status.Errorf(codes.FailedPrecondition, "allowance already pre-paid for window %d", windowToDeposit.Int64()) + return nil, status.Errorf(codes.FailedPrecondition, "deposited already for window %d", windowToDeposit.Int64()) } for window := range s.depositedWindows { if window.Cmp(new(big.Int).SetUint64(currentWindow)) < 0 { - err := s.registryContract.WithdrawAllowance(ctx, window) + err := s.registryContract.WithdrawDeposit(ctx, window) if err != nil { - return nil, status.Errorf(codes.Internal, "withdrawing allowance: %v", err) + return nil, status.Errorf(codes.Internal, "withdrawing deposit: %v", err) } - s.logger.Info("withdrew allowance", "window", window) + s.logger.Info("withdrew deposit", "window", window) delete(s.depositedWindows, window) } } @@ -149,23 +149,23 @@ func (s *Service) PrepayAllowance( return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", r.Amount) } - err = s.registryContract.PrepayAllowanceForSpecificWindow(ctx, amount, windowToDeposit) + err = s.registryContract.DepositForSpecificWindow(ctx, amount, windowToDeposit) if err != nil { - return nil, status.Errorf(codes.Internal, "prepaying allowance: %v", err) + return nil, status.Errorf(codes.Internal, "deposit: %v", err) } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, windowToDeposit) + stakeAmount, err := s.registryContract.GetDeposit(ctx, s.owner, windowToDeposit) if err != nil { - return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) + return nil, status.Errorf(codes.Internal, "getting deposit: %v", err) } - s.logger.Info("prepay successful", "amount", stakeAmount.String(), "window", windowToDeposit) + s.logger.Info("deposit successful", "amount", stakeAmount.String(), "window", windowToDeposit) s.depositedWindows[windowToDeposit] = struct{}{} - return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String(), WindowNumber: wrapperspb.UInt64(windowToDeposit.Uint64())}, nil + return &bidderapiv1.DepositResponse{Amount: stakeAmount.String(), WindowNumber: wrapperspb.UInt64(windowToDeposit.Uint64())}, nil } -func (s *Service) calculateWindowToDeposit(ctx context.Context, r *bidderapiv1.PrepayRequest, currentWindow uint64) (*big.Int, error) { +func (s *Service) calculateWindowToDeposit(ctx context.Context, r *bidderapiv1.DepositRequest, currentWindow uint64) (*big.Int, error) { if r.WindowNumber != nil { // Directly use the specified window number if available. return new(big.Int).SetUint64(r.WindowNumber.Value), nil @@ -182,10 +182,10 @@ func (s *Service) calculateWindowToDeposit(ctx context.Context, r *bidderapiv1.P return new(big.Int).SetUint64(currentWindow + 2), nil } -func (s *Service) GetAllowance( +func (s *Service) GetDeposit( ctx context.Context, - r *bidderapiv1.GetAllowanceRequest, -) (*bidderapiv1.PrepayResponse, error) { + r *bidderapiv1.GetDepositRequest, +) (*bidderapiv1.DepositResponse, error) { var ( window uint64 err error @@ -200,22 +200,22 @@ func (s *Service) GetAllowance( } else { window = r.WindowNumber.Value } - stakeAmount, err := s.registryContract.GetAllowance(ctx, s.owner, new(big.Int).SetUint64(window)) + stakeAmount, err := s.registryContract.GetDeposit(ctx, s.owner, new(big.Int).SetUint64(window)) if err != nil { - return nil, status.Errorf(codes.Internal, "getting allowance: %v", err) + return nil, status.Errorf(codes.Internal, "getting deposit: %v", err) } - return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil + return &bidderapiv1.DepositResponse{Amount: stakeAmount.String()}, nil } -func (s *Service) GetMinAllowance( +func (s *Service) GetMinDeposit( ctx context.Context, _ *bidderapiv1.EmptyMessage, -) (*bidderapiv1.PrepayResponse, error) { - stakeAmount, err := s.registryContract.GetMinAllowance(ctx) +) (*bidderapiv1.DepositResponse, error) { + stakeAmount, err := s.registryContract.GetMinDeposit(ctx) if err != nil { - return nil, status.Errorf(codes.Internal, "getting min allowance: %v", err) + return nil, status.Errorf(codes.Internal, "getting min deposit: %v", err) } - return &bidderapiv1.PrepayResponse{Amount: stakeAmount.String()}, nil + return &bidderapiv1.DepositResponse{Amount: stakeAmount.String()}, nil } diff --git a/pkg/rpc/bidder/service_test.go b/pkg/rpc/bidder/service_test.go index b9cd89c7..a2975f72 100644 --- a/pkg/rpc/bidder/service_test.go +++ b/pkg/rpc/bidder/service_test.go @@ -76,28 +76,28 @@ func (s *testSender) SendBid( } type testRegistryContract struct { - allowance *big.Int - minAllowance *big.Int + deposit *big.Int + minDeposit *big.Int } -func (t *testRegistryContract) PrepayAllowanceForSpecificWindow(ctx context.Context, amount *big.Int, window *big.Int) error { - t.allowance = amount +func (t *testRegistryContract) DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error { + t.deposit = amount return nil } -func (t *testRegistryContract) GetAllowance(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) { - return t.allowance, nil +func (t *testRegistryContract) GetDeposit(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) { + return t.deposit, nil } -func (t *testRegistryContract) GetMinAllowance(ctx context.Context) (*big.Int, error) { - return t.minAllowance, nil +func (t *testRegistryContract) GetMinDeposit(ctx context.Context) (*big.Int, error) { + return t.minDeposit, nil } -func (t *testRegistryContract) CheckBidderAllowance(ctx context.Context, address common.Address, window *big.Int, numberOfRounds *big.Int) bool { - return t.allowance.Cmp(t.minAllowance) > 0 +func (t *testRegistryContract) CheckBidderDeposit(ctx context.Context, address common.Address, window, numberOfRounds *big.Int) bool { + return t.deposit.Cmp(t.minDeposit) > 0 } -func (t *testRegistryContract) WithdrawAllowance(ctx context.Context, window *big.Int) error { +func (t *testRegistryContract) WithdrawDeposit(ctx context.Context, window *big.Int) error { return nil } @@ -127,7 +127,7 @@ func startServer(t *testing.T) bidderapiv1.BidderClient { } owner := common.HexToAddress("0x00001") - registryContract := &testRegistryContract{minAllowance: big.NewInt(100000000000000000)} + registryContract := &testRegistryContract{minDeposit: big.NewInt(100000000000000000)} sender := &testSender{noOfPreconfs: 2} blockTrackerContract := &testBlockTrackerContract{blocksPerWindow: 64, blockNumberToWinner: make(map[uint64]common.Address)} srvImpl := bidderapi.NewService( @@ -168,12 +168,12 @@ func startServer(t *testing.T) bidderapiv1.BidderClient { return client } -func TestAllowanceHandling(t *testing.T) { +func TestDepositHandling(t *testing.T) { t.Parallel() client := startServer(t) - t.Run("prepay", func(t *testing.T) { + t.Run("deposit", func(t *testing.T) { type testCase struct { amount string err string @@ -197,39 +197,39 @@ func TestAllowanceHandling(t *testing.T) { err: "", }, } { - allowance, err := client.PrepayAllowance(context.Background(), &bidderapiv1.PrepayRequest{Amount: tc.amount}) + deposit, err := client.Deposit(context.Background(), &bidderapiv1.DepositRequest{Amount: tc.amount}) if tc.err != "" { if err == nil || !strings.Contains(err.Error(), tc.err) { - t.Fatalf("expected error prepaying allowance") + t.Fatalf("expected error depositing") } } else { if err != nil { - t.Fatalf("error prepaying allowance: %v", err) + t.Fatalf("error depositing: %v", err) } - if allowance.Amount != tc.amount { - t.Fatalf("expected amount to be %v, got %v", tc.amount, allowance.Amount) + if deposit.Amount != tc.amount { + t.Fatalf("expected amount to be %v, got %v", tc.amount, deposit.Amount) } } } }) - t.Run("get allowance", func(t *testing.T) { - allowance, err := client.GetAllowance(context.Background(), &bidderapiv1.GetAllowanceRequest{WindowNumber: wrapperspb.UInt64(1)}) + t.Run("get deposit", func(t *testing.T) { + deposit, err := client.GetDeposit(context.Background(), &bidderapiv1.GetDepositRequest{WindowNumber: wrapperspb.UInt64(1)}) if err != nil { - t.Fatalf("error getting allowance: %v", err) + t.Fatalf("error getting deposit: %v", err) } - if allowance.Amount != "1000000000000000000" { - t.Fatalf("expected amount to be 1000000000000000000, got %v", allowance.Amount) + if deposit.Amount != "1000000000000000000" { + t.Fatalf("expected amount to be 1000000000000000000, got %v", deposit.Amount) } }) - t.Run("get min allowance", func(t *testing.T) { - allowance, err := client.GetMinAllowance(context.Background(), &bidderapiv1.EmptyMessage{}) + t.Run("get min deposit", func(t *testing.T) { + deposit, err := client.GetMinDeposit(context.Background(), &bidderapiv1.EmptyMessage{}) if err != nil { - t.Fatalf("error getting min allowance: %v", err) + t.Fatalf("error getting min deposit: %v", err) } - if allowance.Amount != "100000000000000000" { - t.Fatalf("expected amount to be 100000000000000000, got %v", allowance.Amount) + if deposit.Amount != "100000000000000000" { + t.Fatalf("expected amount to be 100000000000000000, got %v", deposit.Amount) } }) } diff --git a/pkg/store/store.go b/pkg/store/store.go index c96a33ec..32fcc231 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -153,11 +153,11 @@ type BidderBalancesStore struct { mu sync.RWMutex } -func (bbs *BidderBalancesStore) SetBalance(bidder common.Address, windowNumber *big.Int, prepaidAmount *big.Int) error { +func (bbs *BidderBalancesStore) SetBalance(bidder common.Address, windowNumber, depositedAmount *big.Int) error { bbs.mu.Lock() defer bbs.mu.Unlock() bssKey := getBBSKey(bidder, windowNumber) - bbs.balances[bssKey] = prepaidAmount + bbs.balances[bssKey] = depositedAmount return nil } diff --git a/rpc/bidderapi/v1/bidderapi.proto b/rpc/bidderapi/v1/bidderapi.proto index de7bb20d..6d2e4da0 100644 --- a/rpc/bidderapi/v1/bidderapi.proto +++ b/rpc/bidderapi/v1/bidderapi.proto @@ -28,39 +28,39 @@ service Bidder { body: "*" }; } - // PrepayAllowance + // Deposit // - // PrepayAllowance is called by the bidder node to add prepaid allowance in the bidder registry. - rpc PrepayAllowance(PrepayRequest) returns (PrepayResponse) { - option (google.api.http) = {post: "/v1/bidder/prepay/{amount}"}; + // Deposit is called by the bidder node to add deposit in the bidder registry. + rpc Deposit(DepositRequest) returns (DepositResponse) { + option (google.api.http) = {post: "/v1/bidder/deposit/{amount}"}; } - // GetAllowance + // GetDeposit // - // GetAllowance is called by the bidder to get its allowance in the bidder registry. - rpc GetAllowance(GetAllowanceRequest) returns (PrepayResponse) { + // GetDeposit is called by the bidder to get its deposit in the bidder registry. + rpc GetDeposit(GetDepositRequest) returns (DepositResponse) { option (google.api.http) = { - get: "/v1/bidder/get_allowance" + get: "/v1/bidder/get_deposit" }; } - // GetMinAllowance + // GetMinDeposit // - // GetMinAllowance is called by the bidder to get the minimum allowance required in the bidder registry to make bids. - rpc GetMinAllowance(EmptyMessage) returns (PrepayResponse) { - option (google.api.http) = {get: "/v1/bidder/get_min_allowance"}; + // GetMinDeposit is called by the bidder to get the minimum deposit required in the bidder registry to make bids. + rpc GetMinDeposit(EmptyMessage) returns (DepositResponse) { + option (google.api.http) = {get: "/v1/bidder/get_min_deposit"}; } } -message PrepayRequest { +message DepositRequest { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { json_schema: { - title: "Prepay request" - description: "Prepayment for bids to be issued by the bidder in wei." + title: "Deposit request" + description: "Deposit for bids to be issued by the bidder in wei." required: ["amount"] } example: "{\"amount\": \"1000000000000000000\", \"windowNumber\": 1 }" }; string amount = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Amount of ETH to be prepaid in wei." + description: "Amount of ETH to be deposited in wei." pattern: "[0-9]+" }, (buf.validate.field).cel = { id: "amount", @@ -69,7 +69,7 @@ message PrepayRequest { }]; google.protobuf.UInt64Value windowNumber = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Optional window number for querying allowances. If not specified, the current block number is used." + description: "Optional window number for querying deposit. If not specified, the current block number is used." }, (buf.validate.field).cel = { id: "windowNumber", message: "windowNumber must be a positive integer if specified.", @@ -77,7 +77,7 @@ message PrepayRequest { }]; google.protobuf.UInt64Value blockNumber = 3 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Optional block number for querying allowance. If specified, calculate window based on this block number." + description: "Optional block number for querying deposit. If specified, calculate window based on this block number." }, (buf.validate.field).cel = { id: "blockNumber", message: "blockNumber must be a positive integer if specified.", @@ -85,11 +85,11 @@ message PrepayRequest { }]; }; -message PrepayResponse { +message DepositResponse { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { json_schema: { - title: "Prepay response" - description: "Get prepaid allowance for bidder in the bidder registry." + title: "Deposit response" + description: "Get deposit for bidder in the bidder registry." } example: "{\"amount\": \"1000000000000000000\", \"windowNumber\": \"1\" }" }; @@ -99,10 +99,10 @@ message PrepayResponse { message EmptyMessage {}; -message GetAllowanceRequest { +message GetDepositRequest { google.protobuf.UInt64Value windowNumber = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Optional window number for querying allowances. If not specified, the current block number is used." + description: "Optional window number for querying deposits. If not specified, the current block number is used." }, (buf.validate.field).cel = { id: "windowNumber", message: "windowNumber must be a positive integer if specified.",