From 434dc51c29bb329afc2c1dd24cb5d396a0eede2c Mon Sep 17 00:00:00 2001 From: Richard Hua Date: Wed, 11 Sep 2024 11:03:52 -0700 Subject: [PATCH] Make server logic vector clock-aware (#153) - Modify server logic for queries and subscriptions to support vector clock cursors - Implement the changes from https://github.com/xmtp/proto/pull/206, including splitting SID into two fields, using a dict for the vector clock, and modifying node ID from uint16 to uint32 I was worried about type-conversions between int32 and uint32 and overflow issues, but it looks like with two's complement, [overflowed int32's behave the same as uint32's after conversion](https://go.dev/play/p/pQmLPP56nzx) (or in other words, the increment operation does exactly the same thing to the underlying byte representation either way). In other words, our postgres schema can only support signed int32's, but it seems like we can just pretend they are uint32's and have the same effect. We do still need to worry about the postgres sequence overflowing, as well as the max value of uint32/uint64 - when implementing the node-to-node syncing logic, my plan is to regularly log the node's vector clock, so that we can see it coming from a long way away. --- contracts/src/Nodes.sol | 18 +- contracts/test/Nodes.sol | 14 +- dev/test | 2 +- pkg/abis/nodes.go | 22 +- pkg/api/publishWorker.go | 2 +- pkg/api/service.go | 27 +- pkg/api/service_test.go | 10 +- pkg/db/subscription.go | 55 +- pkg/db/subscription_test.go | 42 +- pkg/db/types.go | 21 +- pkg/mocks/mock_NodeRegistry.go | 16 +- .../message_api/message_api.swagger.json | 8 +- .../xmtpv4/message_api/message_api.pb.go | 539 +++++++++--------- pkg/registrant/registrant.go | 20 +- pkg/registrant/registrant_test.go | 20 +- pkg/registry/contractRegistry.go | 10 +- pkg/registry/contractRegistry_test.go | 2 +- pkg/registry/fixedRegistry.go | 4 +- pkg/registry/interface.go | 2 +- pkg/registry/node.go | 2 +- pkg/testutils/envelopes.go | 12 +- pkg/utils/sid.go | 37 -- pkg/utils/sid_test.go | 67 --- 23 files changed, 434 insertions(+), 518 deletions(-) delete mode 100644 pkg/utils/sid.go delete mode 100644 pkg/utils/sid_test.go diff --git a/contracts/src/Nodes.sol b/contracts/src/Nodes.sol index 5998831c..cee83991 100644 --- a/contracts/src/Nodes.sol +++ b/contracts/src/Nodes.sol @@ -14,9 +14,9 @@ All nodes on the network periodically check this contract to determine which nod contract Nodes is ERC721, Ownable { constructor() ERC721("XMTP Node Operator", "XMTP") Ownable(msg.sender) {} - // uint16 counter so that we cannot create more than 65k IDs + // uint32 counter so that we cannot create more than max IDs // The ERC721 standard expects the tokenID to be uint256 for standard methods unfortunately - uint16 private _nodeIdCounter; + uint32 private _nodeIdCounter; // A node, as stored in the internal mapping struct Node { @@ -26,7 +26,7 @@ contract Nodes is ERC721, Ownable { } struct NodeWithId { - uint16 nodeId; + uint32 nodeId; Node node; } @@ -42,8 +42,8 @@ contract Nodes is ERC721, Ownable { address to, bytes calldata signingKeyPub, string calldata httpAddress - ) public onlyOwner returns (uint16) { - uint16 nodeId = _nodeIdCounter; + ) public onlyOwner returns (uint32) { + uint32 nodeId = _nodeIdCounter; _mint(to, nodeId); _nodes[nodeId] = Node(signingKeyPub, httpAddress, true); _emitNodeUpdate(nodeId); @@ -101,7 +101,7 @@ contract Nodes is ERC721, Ownable { Get a list of healthy nodes with their ID and metadata */ function healthyNodes() public view returns (NodeWithId[] memory) { - uint16 totalNodeCount = _nodeIdCounter; + uint32 totalNodeCount = _nodeIdCounter; uint256 healthyCount = 0; // First, count the number of healthy nodes @@ -116,7 +116,7 @@ contract Nodes is ERC721, Ownable { uint256 currentIndex = 0; // Populate the array with healthy nodes - for (uint16 i = 0; i < totalNodeCount; i++) { + for (uint32 i = 0; i < totalNodeCount; i++) { if (_nodeExists(i) && _nodes[i].isHealthy) { healthyNodesList[currentIndex] = NodeWithId({ nodeId: i, @@ -133,10 +133,10 @@ contract Nodes is ERC721, Ownable { Get all nodes regardless of their health status */ function allNodes() public view returns (NodeWithId[] memory) { - uint16 totalNodeCount = _nodeIdCounter; + uint32 totalNodeCount = _nodeIdCounter; NodeWithId[] memory allNodesList = new NodeWithId[](totalNodeCount); - for (uint16 i = 0; i < totalNodeCount; i++) { + for (uint32 i = 0; i < totalNodeCount; i++) { allNodesList[i] = NodeWithId({nodeId: i, node: _nodes[i]}); } diff --git a/contracts/test/Nodes.sol b/contracts/test/Nodes.sol index d7d742bf..14411d3a 100644 --- a/contracts/test/Nodes.sol +++ b/contracts/test/Nodes.sol @@ -41,7 +41,7 @@ contract NodesTest is Test { address operatorAddress = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operatorAddress, node.signingKeyPub, node.httpAddress @@ -62,7 +62,7 @@ contract NodesTest is Test { address operator2 = vm.randomAddress(); address operator3 = vm.randomAddress(); - uint16 node1Id = nodes.addNode( + uint32 node1Id = nodes.addNode( operator1, node1.signingKeyPub, node1.httpAddress @@ -82,7 +82,7 @@ contract NodesTest is Test { Nodes.Node memory node = _randomNode(true); address operator = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operator, node.signingKeyPub, node.httpAddress @@ -99,7 +99,7 @@ contract NodesTest is Test { Nodes.Node memory node = _randomNode(true); address operator = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operator, node.signingKeyPub, node.httpAddress @@ -113,7 +113,7 @@ contract NodesTest is Test { Nodes.Node memory node = _randomNode(true); address operator = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operator, node.signingKeyPub, node.httpAddress @@ -127,7 +127,7 @@ contract NodesTest is Test { Nodes.Node memory node = _randomNode(true); address operator = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operator, node.signingKeyPub, node.httpAddress @@ -147,7 +147,7 @@ contract NodesTest is Test { Nodes.Node memory node = _randomNode(true); address operator = vm.randomAddress(); - uint16 nodeId = nodes.addNode( + uint32 nodeId = nodes.addNode( operator, node.signingKeyPub, node.httpAddress diff --git a/dev/test b/dev/test index 9ef4f603..2ee698e6 100755 --- a/dev/test +++ b/dev/test @@ -3,7 +3,7 @@ set -e ulimit -n 2048 -go test -timeout 3s `go list ./... | grep -v -e 'pkg/abis' -e 'pkg/config' -e 'pkg/proto' -e 'pkg/mock' -e 'pkg/testing'` "$@" +go test -timeout 10s `go list ./... | grep -v -e 'pkg/abis' -e 'pkg/config' -e 'pkg/proto' -e 'pkg/mock' -e 'pkg/testing'` "$@" if [ -n "${RACE:-}" ]; then echo diff --git a/pkg/abis/nodes.go b/pkg/abis/nodes.go index e5f3b4a2..22a46a01 100644 --- a/pkg/abis/nodes.go +++ b/pkg/abis/nodes.go @@ -38,13 +38,13 @@ type NodesNode struct { // NodesNodeWithId is an auto generated low-level Go binding around an user-defined struct. type NodesNodeWithId struct { - NodeId uint16 + NodeId uint32 Node NodesNode } // NodesMetaData contains all meta data concerning the Nodes contract. var NodesMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addNode\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"allNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structNodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint16\",\"internalType\":\"uint16\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApproved\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNode\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"healthyNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structNodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint16\",\"internalType\":\"uint16\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isApprovedForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerOf\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setApprovalForAll\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"tokenURI\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateHealth\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateHttpAddress\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApprovalForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ERC721IncorrectOwner\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InsufficientApproval\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721NonexistentToken\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addNode\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"allNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structNodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApproved\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNode\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"healthyNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structNodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isApprovedForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerOf\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setApprovalForAll\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"tokenURI\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateHealth\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateHttpAddress\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApprovalForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structNodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isHealthy\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ERC721IncorrectOwner\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InsufficientApproval\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721NonexistentToken\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]}]", } // NodesABI is the input ABI used to generate the binding from. @@ -195,7 +195,7 @@ func (_Nodes *NodesTransactorRaw) Transact(opts *bind.TransactOpts, method strin // AllNodes is a free data retrieval call binding the contract method 0x02f6f1ba. // -// Solidity: function allNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function allNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesCaller) AllNodes(opts *bind.CallOpts) ([]NodesNodeWithId, error) { var out []interface{} err := _Nodes.contract.Call(opts, &out, "allNodes") @@ -212,14 +212,14 @@ func (_Nodes *NodesCaller) AllNodes(opts *bind.CallOpts) ([]NodesNodeWithId, err // AllNodes is a free data retrieval call binding the contract method 0x02f6f1ba. // -// Solidity: function allNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function allNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesSession) AllNodes() ([]NodesNodeWithId, error) { return _Nodes.Contract.AllNodes(&_Nodes.CallOpts) } // AllNodes is a free data retrieval call binding the contract method 0x02f6f1ba. // -// Solidity: function allNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function allNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesCallerSession) AllNodes() ([]NodesNodeWithId, error) { return _Nodes.Contract.AllNodes(&_Nodes.CallOpts) } @@ -319,7 +319,7 @@ func (_Nodes *NodesCallerSession) GetNode(tokenId *big.Int) (NodesNode, error) { // HealthyNodes is a free data retrieval call binding the contract method 0x17b5b840. // -// Solidity: function healthyNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function healthyNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesCaller) HealthyNodes(opts *bind.CallOpts) ([]NodesNodeWithId, error) { var out []interface{} err := _Nodes.contract.Call(opts, &out, "healthyNodes") @@ -336,14 +336,14 @@ func (_Nodes *NodesCaller) HealthyNodes(opts *bind.CallOpts) ([]NodesNodeWithId, // HealthyNodes is a free data retrieval call binding the contract method 0x17b5b840. // -// Solidity: function healthyNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function healthyNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesSession) HealthyNodes() ([]NodesNodeWithId, error) { return _Nodes.Contract.HealthyNodes(&_Nodes.CallOpts) } // HealthyNodes is a free data retrieval call binding the contract method 0x17b5b840. // -// Solidity: function healthyNodes() view returns((uint16,(bytes,string,bool))[]) +// Solidity: function healthyNodes() view returns((uint32,(bytes,string,bool))[]) func (_Nodes *NodesCallerSession) HealthyNodes() ([]NodesNodeWithId, error) { return _Nodes.Contract.HealthyNodes(&_Nodes.CallOpts) } @@ -567,21 +567,21 @@ func (_Nodes *NodesCallerSession) TokenURI(tokenId *big.Int) (string, error) { // AddNode is a paid mutator transaction binding the contract method 0xa0eae81d. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint16) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint32) func (_Nodes *NodesTransactor) AddNode(opts *bind.TransactOpts, to common.Address, signingKeyPub []byte, httpAddress string) (*types.Transaction, error) { return _Nodes.contract.Transact(opts, "addNode", to, signingKeyPub, httpAddress) } // AddNode is a paid mutator transaction binding the contract method 0xa0eae81d. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint16) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint32) func (_Nodes *NodesSession) AddNode(to common.Address, signingKeyPub []byte, httpAddress string) (*types.Transaction, error) { return _Nodes.Contract.AddNode(&_Nodes.TransactOpts, to, signingKeyPub, httpAddress) } // AddNode is a paid mutator transaction binding the contract method 0xa0eae81d. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint16) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress) returns(uint32) func (_Nodes *NodesTransactorSession) AddNode(to common.Address, signingKeyPub []byte, httpAddress string) (*types.Transaction, error) { return _Nodes.Contract.AddNode(&_Nodes.TransactOpts, to, signingKeyPub, httpAddress) } diff --git a/pkg/api/publishWorker.go b/pkg/api/publishWorker.go index cfe48ccc..10acc8ae 100644 --- a/pkg/api/publishWorker.go +++ b/pkg/api/publishWorker.go @@ -19,7 +19,7 @@ type PublishWorker struct { notifier chan<- bool registrant *registrant.Registrant store *sql.DB - subscription db.DBSubscription[queries.StagedOriginatorEnvelope] + subscription db.DBSubscription[queries.StagedOriginatorEnvelope, int64] } func StartPublishWorker( diff --git a/pkg/api/service.go b/pkg/api/service.go index 2c98501c..9eebac10 100644 --- a/pkg/api/service.go +++ b/pkg/api/service.go @@ -16,7 +16,8 @@ import ( ) const ( - maxRequestedRows int32 = 1000 + maxRequestedRows uint32 = 1000 + maxVectorClockLength int = 100 ) type Service struct { @@ -94,9 +95,11 @@ func (s *Service) queryReqToDBParams( req *message_api.QueryEnvelopesRequest, ) (*queries.SelectGatewayEnvelopesParams, error) { params := queries.SelectGatewayEnvelopesParams{ - Topic: []byte{}, - OriginatorNodeID: sql.NullInt32{}, - RowLimit: db.NullInt32(maxRequestedRows), + Topic: nil, + OriginatorNodeID: sql.NullInt32{}, + RowLimit: sql.NullInt32{}, + CursorNodeIds: nil, + CursorSequenceIds: nil, } query := req.GetQuery() @@ -112,11 +115,19 @@ func (s *Service) queryReqToDBParams( default: } - // TODO(rich): Handle last_seen properly + vc := query.GetLastSeen().GetNodeIdToSequenceId() + if len(vc) > maxVectorClockLength { + return nil, status.Errorf( + codes.InvalidArgument, + "vector clock length exceeds maximum of %d", + maxVectorClockLength, + ) + } + db.SetVectorClock(¶ms, vc) - limit := int32(req.GetLimit()) + limit := req.GetLimit() if limit > 0 && limit <= maxRequestedRows { - params.RowLimit = db.NullInt32(limit) + params.RowLimit = db.NullInt32(int32(limit)) } return ¶ms, nil @@ -194,7 +205,7 @@ func (s *Service) validateClientInfo(clientEnv *message_api.ClientEnvelope) ([]b return nil, status.Errorf(codes.InvalidArgument, "missing target topic") } - // TODO(rich): Verify all originators have synced past `last_originator_sids` + // TODO(rich): Verify all originators have synced past `last_seen` // TODO(rich): Check that the blockchain sequence ID is equal to the latest on the group // TODO(rich): Perform any payload-specific validation (e.g. identity updates) diff --git a/pkg/api/service_test.go b/pkg/api/service_test.go index 29ce0565..63908dd1 100644 --- a/pkg/api/service_test.go +++ b/pkg/api/service_test.go @@ -129,7 +129,6 @@ func TestMissingTopicOnPublish(t *testing.T) { func setupQueryTest(t *testing.T, db *sql.DB) []queries.InsertGatewayEnvelopeParams { db_rows := []queries.InsertGatewayEnvelopeParams{ { - // Auto-generated ID: 1 OriginatorNodeID: 1, OriginatorSequenceID: 1, Topic: []byte("topicA"), @@ -139,7 +138,6 @@ func setupQueryTest(t *testing.T, db *sql.DB) []queries.InsertGatewayEnvelopePar ), }, { - // Auto-generated ID: 2 OriginatorNodeID: 2, OriginatorSequenceID: 1, Topic: []byte("topicA"), @@ -149,7 +147,6 @@ func setupQueryTest(t *testing.T, db *sql.DB) []queries.InsertGatewayEnvelopePar ), }, { - // Auto-generated ID: 3 OriginatorNodeID: 1, OriginatorSequenceID: 2, Topic: []byte("topicB"), @@ -159,7 +156,6 @@ func setupQueryTest(t *testing.T, db *sql.DB) []queries.InsertGatewayEnvelopePar ), }, { - // Auto-generated ID: 4 OriginatorNodeID: 2, OriginatorSequenceID: 2, Topic: []byte("topicB"), @@ -169,7 +165,6 @@ func setupQueryTest(t *testing.T, db *sql.DB) []queries.InsertGatewayEnvelopePar ), }, { - // Auto-generated ID: 5 OriginatorNodeID: 1, OriginatorSequenceID: 3, Topic: []byte("topicA"), @@ -256,7 +251,6 @@ func TestQueryEnvelopesByTopic(t *testing.T) { } func TestQueryEnvelopesFromLastSeen(t *testing.T) { - t.Skip("Not implemented yet") svc, db, cleanup := newTestService(t) defer cleanup() db_rows := setupQueryTest(t, db) @@ -266,13 +260,13 @@ func TestQueryEnvelopesFromLastSeen(t *testing.T) { &message_api.QueryEnvelopesRequest{ Query: &message_api.EnvelopesQuery{ Filter: nil, - LastSeen: &message_api.VectorClock{}, + LastSeen: &message_api.VectorClock{NodeIdToSequenceId: map[uint32]uint64{1: 2}}, }, Limit: 0, }, ) require.NoError(t, err) - checkRowsMatchProtos(t, db_rows, []int{}, resp.GetEnvelopes()) + checkRowsMatchProtos(t, db_rows, []int{1, 3, 4}, resp.GetEnvelopes()) } func TestQueryEnvelopesWithEmptyResult(t *testing.T) { diff --git a/pkg/db/subscription.go b/pkg/db/subscription.go index be73734e..6a69343a 100644 --- a/pkg/db/subscription.go +++ b/pkg/db/subscription.go @@ -8,7 +8,11 @@ import ( "go.uber.org/zap" ) -type PollableDBQuery[ValueType any] func(ctx context.Context, lastSeenID int64, numRows int32) (results []ValueType, lastID int64, err error) +type PollableDBQuery[ValueType any, CursorType any] func( + ctx context.Context, + lastSeen CursorType, + numRows int32, +) (results []ValueType, nextCursor CursorType, err error) // Poll whenever notified, or at an interval if not notified type PollingOptions struct { @@ -17,33 +21,33 @@ type PollingOptions struct { NumRows int32 } -type DBSubscription[ValueType any] struct { - ctx context.Context - log *zap.Logger - lastSeenID int64 - options PollingOptions - query PollableDBQuery[ValueType] - updates chan<- []ValueType +type DBSubscription[ValueType any, CursorType any] struct { + ctx context.Context + log *zap.Logger + lastSeen CursorType + options PollingOptions + query PollableDBQuery[ValueType, CursorType] + updates chan<- []ValueType } -func NewDBSubscription[ValueType any]( +func NewDBSubscription[ValueType any, CursorType any]( ctx context.Context, log *zap.Logger, - query PollableDBQuery[ValueType], - lastSeenID int64, + query PollableDBQuery[ValueType, CursorType], + lastSeen CursorType, options PollingOptions, -) *DBSubscription[ValueType] { - return &DBSubscription[ValueType]{ - ctx: ctx, - log: log, - lastSeenID: lastSeenID, - options: options, - query: query, - updates: nil, +) *DBSubscription[ValueType, CursorType] { + return &DBSubscription[ValueType, CursorType]{ + ctx: ctx, + log: log, + lastSeen: lastSeen, + options: options, + query: query, + updates: nil, } } -func (s *DBSubscription[ValueType]) Start() (<-chan []ValueType, error) { +func (s *DBSubscription[ValueType, CursorType]) Start() (<-chan []ValueType, error) { if s.updates != nil { return nil, fmt.Errorf("Already started") } @@ -75,25 +79,24 @@ func (s *DBSubscription[ValueType]) Start() (<-chan []ValueType, error) { return updates, nil } -func (s *DBSubscription[ValueType]) poll() { +func (s *DBSubscription[ValueType, CursorType]) poll() { // Repeatedly query page by page until no more results for { - results, lastID, err := s.query(s.ctx, s.lastSeenID, s.options.NumRows) + results, lastID, err := s.query(s.ctx, s.lastSeen, s.options.NumRows) if s.ctx.Err() != nil { break } else if err != nil { s.log.Error( "Error querying for DB subscription", - zap.Error(err), - zap.Int64("lastSeenID", s.lastSeenID), + zap.Any("lastSeen", s.lastSeen), zap.Int32("numRows", s.options.NumRows), ) - // Did not update lastSeenID; will retry on next poll + // Did not update lastSeen; will retry on next poll break } else if len(results) == 0 { break } - s.lastSeenID = lastID + s.lastSeen = lastID s.updates <- results if int32(len(results)) < s.options.NumRows { break diff --git a/pkg/db/subscription_test.go b/pkg/db/subscription_test.go index bba68030..213ad614 100644 --- a/pkg/db/subscription_test.go +++ b/pkg/db/subscription_test.go @@ -39,21 +39,20 @@ func insertInitialRows(t *testing.T, db *sql.DB) { }) } -func envelopesQuery(db *sql.DB) PollableDBQuery[queries.GatewayEnvelope] { - return func(ctx context.Context, lastSeenID int64, numRows int32) ([]queries.GatewayEnvelope, int64, error) { +func envelopesQuery(db *sql.DB) PollableDBQuery[queries.GatewayEnvelope, VectorClock] { + return func(ctx context.Context, lastSeen VectorClock, numRows int32) ([]queries.GatewayEnvelope, VectorClock, error) { envs, err := queries.New(db). - SelectGatewayEnvelopes(ctx, queries.SelectGatewayEnvelopesParams{ + SelectGatewayEnvelopes(ctx, *SetVectorClock(&queries.SelectGatewayEnvelopesParams{ OriginatorNodeID: NullInt32(1), RowLimit: NullInt32(numRows), - }) + }, lastSeen)) if err != nil { - return nil, 0, err + return nil, lastSeen, err } - if len(envs) > 0 { - // TODO(rich) fix cursor - lastSeenID = envs[len(envs)-1].OriginatorSequenceID + for _, env := range envs { + lastSeen[uint32(env.OriginatorNodeID)] = uint64(env.OriginatorSequenceID) } - return envs, lastSeenID, nil + return envs, lastSeen, nil } } @@ -83,14 +82,14 @@ func insertAdditionalRows(t *testing.T, db *sql.DB, notifyChan ...chan bool) { func validateUpdates(t *testing.T, updates <-chan []queries.GatewayEnvelope, ctxCancel func()) { envs := <-updates require.Equal(t, 1, len(envs)) - // TODO(rich) fix cursor - // require.Equal(t, int64(3), envs[0].OriginatorSequenceID) + require.Equal(t, int32(1), envs[0].OriginatorNodeID) + require.Equal(t, int64(2), envs[0].OriginatorSequenceID) require.Equal(t, []byte("envelope3"), envs[0].OriginatorEnvelope) envs = <-updates require.Equal(t, 1, len(envs)) - // TODO(rich) fix cursor - // require.Equal(t, int64(5), envs[0].OriginatorSequenceID) + require.Equal(t, int32(1), envs[0].OriginatorNodeID) + require.Equal(t, int64(3), envs[0].OriginatorSequenceID) require.Equal(t, []byte("envelope5"), envs[0].OriginatorEnvelope) ctxCancel() @@ -100,21 +99,20 @@ func validateUpdates(t *testing.T, updates <-chan []queries.GatewayEnvelope, ctx // flakyEnvelopesQuery returns a query that fails every other time // to simulate a transient database error -func flakyEnvelopesQuery(db *sql.DB) PollableDBQuery[queries.GatewayEnvelope] { +func flakyEnvelopesQuery(db *sql.DB) PollableDBQuery[queries.GatewayEnvelope, VectorClock] { numQueries := 0 query := envelopesQuery(db) - return func(ctx context.Context, lastSeenID int64, numRows int32) ([]queries.GatewayEnvelope, int64, error) { + return func(ctx context.Context, lastSeen VectorClock, numRows int32) ([]queries.GatewayEnvelope, VectorClock, error) { numQueries++ if numQueries%2 == 1 { - return nil, 0, fmt.Errorf("flaky query") + return nil, lastSeen, fmt.Errorf("flaky query") } - return query(ctx, lastSeenID, numRows) + return query(ctx, lastSeen, numRows) } } func TestIntervalSubscription(t *testing.T) { - t.Skip("TODO(rich) fix cursor") db, log, cleanup := setup(t) defer cleanup() @@ -126,7 +124,7 @@ func TestIntervalSubscription(t *testing.T) { ctx, log, envelopesQuery(db), - 1, // lastSeenID + VectorClock{1: 1}, PollingOptions{ Interval: 100 * time.Millisecond, NumRows: 1, @@ -140,7 +138,6 @@ func TestIntervalSubscription(t *testing.T) { } func TestNotifiedSubscription(t *testing.T) { - t.Skip("TODO(rich) fix cursor") db, log, cleanup := setup(t) defer cleanup() @@ -153,7 +150,7 @@ func TestNotifiedSubscription(t *testing.T) { ctx, log, envelopesQuery(db), - 1, // lastSeenID + VectorClock{1: 1}, PollingOptions{ Notifier: notifyChan, Interval: 30 * time.Second, @@ -168,7 +165,6 @@ func TestNotifiedSubscription(t *testing.T) { } func TestTemporaryDBError(t *testing.T) { - t.Skip("TODO(rich) fix cursor") db, log, cleanup := setup(t) defer cleanup() @@ -180,7 +176,7 @@ func TestTemporaryDBError(t *testing.T) { ctx, log, flakyEnvelopesQuery(db), - 1, // lastSeenID + VectorClock{1: 1}, PollingOptions{ Interval: 100 * time.Millisecond, NumRows: 1, diff --git a/pkg/db/types.go b/pkg/db/types.go index eff3dfe0..da9a7058 100644 --- a/pkg/db/types.go +++ b/pkg/db/types.go @@ -1,6 +1,12 @@ package db -import "database/sql" +import ( + "database/sql" + + "github.com/xmtp/xmtpd/pkg/db/queries" +) + +type VectorClock = map[uint32]uint64 func NullInt32(v int32) sql.NullInt32 { return sql.NullInt32{Int32: v, Valid: true} @@ -9,3 +15,16 @@ func NullInt32(v int32) sql.NullInt32 { func NullInt64(v int64) sql.NullInt64 { return sql.NullInt64{Int64: v, Valid: true} } + +func SetVectorClock( + q *queries.SelectGatewayEnvelopesParams, + vc VectorClock, +) *queries.SelectGatewayEnvelopesParams { + q.CursorNodeIds = make([]int32, 0, len(vc)) + q.CursorSequenceIds = make([]int64, 0, len(vc)) + for nodeID, sequenceID := range vc { + q.CursorNodeIds = append(q.CursorNodeIds, int32(nodeID)) + q.CursorSequenceIds = append(q.CursorSequenceIds, int64(sequenceID)) + } + return q +} diff --git a/pkg/mocks/mock_NodeRegistry.go b/pkg/mocks/mock_NodeRegistry.go index ced56dd4..3831b1d8 100644 --- a/pkg/mocks/mock_NodeRegistry.go +++ b/pkg/mocks/mock_NodeRegistry.go @@ -78,7 +78,7 @@ func (_c *MockNodeRegistry_GetNodes_Call) RunAndReturn(run func() ([]registry.No } // OnChangedNode provides a mock function with given fields: _a0 -func (_m *MockNodeRegistry) OnChangedNode(_a0 uint16) (<-chan registry.Node, registry.CancelSubscription) { +func (_m *MockNodeRegistry) OnChangedNode(_a0 uint32) (<-chan registry.Node, registry.CancelSubscription) { ret := _m.Called(_a0) if len(ret) == 0 { @@ -87,10 +87,10 @@ func (_m *MockNodeRegistry) OnChangedNode(_a0 uint16) (<-chan registry.Node, reg var r0 <-chan registry.Node var r1 registry.CancelSubscription - if rf, ok := ret.Get(0).(func(uint16) (<-chan registry.Node, registry.CancelSubscription)); ok { + if rf, ok := ret.Get(0).(func(uint32) (<-chan registry.Node, registry.CancelSubscription)); ok { return rf(_a0) } - if rf, ok := ret.Get(0).(func(uint16) <-chan registry.Node); ok { + if rf, ok := ret.Get(0).(func(uint32) <-chan registry.Node); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { @@ -98,7 +98,7 @@ func (_m *MockNodeRegistry) OnChangedNode(_a0 uint16) (<-chan registry.Node, reg } } - if rf, ok := ret.Get(1).(func(uint16) registry.CancelSubscription); ok { + if rf, ok := ret.Get(1).(func(uint32) registry.CancelSubscription); ok { r1 = rf(_a0) } else { if ret.Get(1) != nil { @@ -115,14 +115,14 @@ type MockNodeRegistry_OnChangedNode_Call struct { } // OnChangedNode is a helper method to define mock.On call -// - _a0 uint16 +// - _a0 uint32 func (_e *MockNodeRegistry_Expecter) OnChangedNode(_a0 interface{}) *MockNodeRegistry_OnChangedNode_Call { return &MockNodeRegistry_OnChangedNode_Call{Call: _e.mock.On("OnChangedNode", _a0)} } -func (_c *MockNodeRegistry_OnChangedNode_Call) Run(run func(_a0 uint16)) *MockNodeRegistry_OnChangedNode_Call { +func (_c *MockNodeRegistry_OnChangedNode_Call) Run(run func(_a0 uint32)) *MockNodeRegistry_OnChangedNode_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(uint16)) + run(args[0].(uint32)) }) return _c } @@ -132,7 +132,7 @@ func (_c *MockNodeRegistry_OnChangedNode_Call) Return(_a0 <-chan registry.Node, return _c } -func (_c *MockNodeRegistry_OnChangedNode_Call) RunAndReturn(run func(uint16) (<-chan registry.Node, registry.CancelSubscription)) *MockNodeRegistry_OnChangedNode_Call { +func (_c *MockNodeRegistry_OnChangedNode_Call) RunAndReturn(run func(uint32) (<-chan registry.Node, registry.CancelSubscription)) *MockNodeRegistry_OnChangedNode_Call { _c.Call.Return(run) return _c } diff --git a/pkg/proto/openapi/xmtpv4/message_api/message_api.swagger.json b/pkg/proto/openapi/xmtpv4/message_api/message_api.swagger.json index 20491598..52692aed 100644 --- a/pkg/proto/openapi/xmtpv4/message_api/message_api.swagger.json +++ b/pkg/proto/openapi/xmtpv4/message_api/message_api.swagger.json @@ -207,7 +207,7 @@ "type": "string", "format": "uint64" }, - "publisherId": { + "publisherNodeId": { "type": "integer", "format": "int64" } @@ -309,9 +309,9 @@ "xmtpv4VectorClock": { "type": "object", "properties": { - "originatorSids": { - "type": "array", - "items": { + "nodeIdToSequenceId": { + "type": "object", + "additionalProperties": { "type": "string", "format": "uint64" } diff --git a/pkg/proto/xmtpv4/message_api/message_api.pb.go b/pkg/proto/xmtpv4/message_api/message_api.pb.go index dc24f5c8..ffb2c9ea 100644 --- a/pkg/proto/xmtpv4/message_api/message_api.pb.go +++ b/pkg/proto/xmtpv4/message_api/message_api.pb.go @@ -88,7 +88,7 @@ type VectorClock struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - OriginatorSids []uint64 `protobuf:"varint,1,rep,packed,name=originator_sids,json=originatorSids,proto3" json:"originator_sids,omitempty"` + NodeIdToSequenceId map[uint32]uint64 `protobuf:"bytes,1,rep,name=node_id_to_sequence_id,json=nodeIdToSequenceId,proto3" json:"node_id_to_sequence_id,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` } func (x *VectorClock) Reset() { @@ -123,9 +123,9 @@ func (*VectorClock) Descriptor() ([]byte, []int) { return file_xmtpv4_message_api_message_api_proto_rawDescGZIP(), []int{0} } -func (x *VectorClock) GetOriginatorSids() []uint64 { +func (x *VectorClock) GetNodeIdToSequenceId() map[uint32]uint64 { if x != nil { - return x.OriginatorSids + return x.NodeIdToSequenceId } return nil } @@ -374,9 +374,10 @@ type UnsignedOriginatorEnvelope struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - OriginatorSid uint64 `protobuf:"varint,1,opt,name=originator_sid,json=originatorSid,proto3" json:"originator_sid,omitempty"` - OriginatorNs int64 `protobuf:"varint,2,opt,name=originator_ns,json=originatorNs,proto3" json:"originator_ns,omitempty"` - PayerEnvelope *PayerEnvelope `protobuf:"bytes,3,opt,name=payer_envelope,json=payerEnvelope,proto3" json:"payer_envelope,omitempty"` + OriginatorNodeId uint32 `protobuf:"varint,1,opt,name=originator_node_id,json=originatorNodeId,proto3" json:"originator_node_id,omitempty"` + OriginatorSequenceId uint64 `protobuf:"varint,2,opt,name=originator_sequence_id,json=originatorSequenceId,proto3" json:"originator_sequence_id,omitempty"` + OriginatorNs int64 `protobuf:"varint,3,opt,name=originator_ns,json=originatorNs,proto3" json:"originator_ns,omitempty"` + PayerEnvelope *PayerEnvelope `protobuf:"bytes,4,opt,name=payer_envelope,json=payerEnvelope,proto3" json:"payer_envelope,omitempty"` } func (x *UnsignedOriginatorEnvelope) Reset() { @@ -411,9 +412,16 @@ func (*UnsignedOriginatorEnvelope) Descriptor() ([]byte, []int) { return file_xmtpv4_message_api_message_api_proto_rawDescGZIP(), []int{4} } -func (x *UnsignedOriginatorEnvelope) GetOriginatorSid() uint64 { +func (x *UnsignedOriginatorEnvelope) GetOriginatorNodeId() uint32 { if x != nil { - return x.OriginatorSid + return x.OriginatorNodeId + } + return 0 +} + +func (x *UnsignedOriginatorEnvelope) GetOriginatorSequenceId() uint64 { + if x != nil { + return x.OriginatorSequenceId } return 0 } @@ -438,8 +446,8 @@ type BlockchainProof struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` - PublisherId uint32 `protobuf:"varint,2,opt,name=publisher_id,json=publisherId,proto3" json:"publisher_id,omitempty"` + BlockNumber uint64 `protobuf:"varint,1,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + PublisherNodeId uint32 `protobuf:"varint,2,opt,name=publisher_node_id,json=publisherNodeId,proto3" json:"publisher_node_id,omitempty"` } func (x *BlockchainProof) Reset() { @@ -481,9 +489,9 @@ func (x *BlockchainProof) GetBlockNumber() uint64 { return 0 } -func (x *BlockchainProof) GetPublisherId() uint32 { +func (x *BlockchainProof) GetPublisherNodeId() uint32 { if x != nil { - return x.PublisherId + return x.PublisherNodeId } return 0 } @@ -1032,7 +1040,7 @@ type BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest struct { func (x *BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest) Reset() { *x = BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_xmtpv4_message_api_message_api_proto_msgTypes[15] + mi := &file_xmtpv4_message_api_message_api_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1045,7 +1053,7 @@ func (x *BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest) String() stri func (*BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest) ProtoMessage() {} func (x *BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest) ProtoReflect() protoreflect.Message { - mi := &file_xmtpv4_message_api_message_api_proto_msgTypes[15] + mi := &file_xmtpv4_message_api_message_api_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1082,204 +1090,217 @@ var file_xmtpv4_message_api_message_api_proto_rawDesc = []byte{ 0x74, 0x69, 0x74, 0x79, 0x2f, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x6d, 0x6c, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x6c, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a, 0x0b, 0x56, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, - 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x52, - 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x64, 0x73, 0x22, - 0x9a, 0x01, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, - 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x70, - 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, - 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x22, 0x9a, 0x03, 0x0a, - 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, - 0x49, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, - 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x77, 0x65, - 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x65, 0x6c, - 0x63, 0x6f, 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x55, 0x0a, 0x0f, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x48, 0x00, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x58, 0x0a, 0x12, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6b, 0x65, 0x79, - 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x10, 0x75, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x03, - 0x61, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x03, 0x61, 0x61, 0x64, 0x42, 0x09, - 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x0d, 0x50, 0x61, - 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x75, - 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x65, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x75, - 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x5e, 0x0a, 0x0f, 0x70, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x73, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x01, 0x0a, 0x0b, 0x56, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x16, 0x6e, 0x6f, 0x64, 0x65, 0x5f, + 0x69, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x49, + 0x64, 0x54, 0x6f, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x45, 0x0a, + 0x17, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x65, 0x49, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9a, 0x01, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x69, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x56, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, + 0x6e, 0x22, 0x9a, 0x03, 0x0a, 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, + 0x00, 0x52, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x4f, 0x0a, 0x0f, 0x77, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, + 0x6d, 0x6c, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x65, 0x6c, 0x63, 0x6f, + 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x00, + 0x52, 0x0e, 0x77, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x55, 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x58, 0x0a, 0x12, 0x75, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x6d, 0x6c, 0x73, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x50, + 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, + 0x10, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x12, 0x30, 0x0a, 0x03, 0x61, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x41, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x03, + 0x61, 0x61, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xa9, + 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x12, 0x38, 0x0a, 0x18, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x16, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x5e, 0x0a, 0x0f, 0x70, 0x61, + 0x79, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x63, 0x64, 0x73, + 0x61, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x65, + 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xe8, 0x01, 0x0a, 0x1a, 0x55, + 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x6f, 0x72, 0x69, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, + 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x16, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x23, 0x0a, + 0x0d, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x4e, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x22, 0x60, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x11, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x96, 0x02, 0x0a, 0x12, 0x4f, 0x72, 0x69, 0x67, + 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x40, + 0x0a, 0x1c, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x12, 0x6a, 0x0a, 0x14, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0e, 0x70, 0x61, 0x79, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x1a, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, - 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6f, 0x72, - 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x73, - 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x22, 0x57, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x72, 0x49, 0x64, 0x22, 0x96, 0x02, 0x0a, - 0x12, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x1c, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, - 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x75, 0x6e, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x6a, 0x0a, 0x14, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, - 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x2e, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x63, 0x64, 0x73, - 0x61, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x13, 0x6f, 0x72, - 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x49, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, - 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0f, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x07, 0x0a, 0x05, - 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x80, 0x01, 0x0a, 0x11, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, - 0x61, 0x76, 0x69, 0x6f, 0x72, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, - 0x69, 0x6f, 0x72, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x65, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x09, 0x65, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x22, 0x99, 0x01, 0x0a, 0x0e, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x05, 0x74, - 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, - 0x70, 0x69, 0x63, 0x12, 0x2e, 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, - 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, - 0x00, 0x52, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x6f, 0x64, - 0x65, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x76, 0x34, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x63, 0x6b, - 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x22, 0xd3, 0x01, 0x0a, 0x1e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x13, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x49, 0x0a, 0x10, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x07, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x22, 0x80, 0x01, 0x0a, 0x11, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x76, 0x34, 0x2e, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x73, 0x22, 0x99, 0x01, 0x0a, 0x0e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2e, + 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x6f, 0x64, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x10, 0x6f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x35, + 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, + 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x08, 0x6c, 0x61, 0x73, + 0x74, 0x53, 0x65, 0x65, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, + 0xd3, 0x01, 0x0a, 0x1e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x61, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, + 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x08, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x4e, 0x0a, 0x19, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x60, 0x0a, 0x1f, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x61, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x4e, 0x0a, 0x19, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, - 0x74, 0x70, 0x76, 0x34, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x60, 0x0a, 0x1f, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, - 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x52, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x22, 0x60, 0x0a, 0x15, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x76, 0x34, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x57, - 0x0a, 0x16, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x09, 0x65, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x6d, 0x74, 0x70, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, - 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x22, 0x6b, 0x0a, 0x17, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x50, 0x0a, 0x13, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x12, 0x6f, - 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x2a, 0xce, 0x01, 0x0a, 0x0b, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, - 0x72, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, - 0x0a, 0x1c, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, 0x4e, - 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x10, 0x01, - 0x12, 0x2b, 0x0a, 0x27, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, - 0x4f, 0x55, 0x54, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x4f, 0x52, 0x49, - 0x47, 0x49, 0x4e, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x02, 0x12, 0x28, 0x0a, - 0x24, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x44, 0x55, 0x50, - 0x4c, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, 0x54, 0x4f, - 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x03, 0x12, 0x29, 0x0a, 0x25, 0x4d, 0x49, 0x53, 0x42, 0x45, - 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x49, 0x43, 0x41, 0x4c, 0x5f, - 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x49, 0x4e, 0x47, - 0x10, 0x04, 0x32, 0xb4, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x41, 0x70, 0x69, 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, - 0x73, 0x12, 0x2b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, - 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, - 0x6f, 0x70, 0x65, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, - 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x78, - 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x6d, - 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2d, 0x65, 0x6e, 0x76, 0x65, - 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x23, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x22, 0x60, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x45, 0x6e, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x57, 0x0a, 0x16, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, + 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, + 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x09, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, + 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0e, + 0x70, 0x61, 0x79, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x76, 0x34, 0x2e, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x52, 0x0d, 0x70, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x22, + 0x6b, 0x0a, 0x17, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x13, 0x6f, 0x72, + 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, + 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, + 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2a, 0xce, 0x01, 0x0a, + 0x0b, 0x4d, 0x69, 0x73, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x17, + 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x4d, 0x49, 0x53, + 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, 0x4c, + 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4e, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x12, 0x2b, 0x0a, 0x27, 0x4d, + 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x4f, 0x55, 0x54, 0x5f, 0x4f, + 0x46, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, 0x54, + 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, 0x10, 0x02, 0x12, 0x28, 0x0a, 0x24, 0x4d, 0x49, 0x53, 0x42, + 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x44, 0x55, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x5f, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x44, + 0x10, 0x03, 0x12, 0x29, 0x0a, 0x25, 0x4d, 0x49, 0x53, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, + 0x52, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x49, 0x43, 0x41, 0x4c, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, + 0x47, 0x45, 0x5f, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x32, 0xb4, 0x03, + 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x69, + 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x2b, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, + 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x30, + 0x01, 0x12, 0x7d, 0x0a, 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, + 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, + 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x76, 0x65, 0x6c, + 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1c, 0x3a, 0x01, 0x2a, 0x22, 0x17, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, + 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, + 0x12, 0x81, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x23, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, + 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, + 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, - 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, - 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, - 0x18, 0x2f, 0x6d, 0x6c, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x42, 0xa3, 0x01, 0x0a, 0x0f, 0x63, 0x6f, - 0x6d, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x42, 0x0f, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x6d, 0x74, - 0x70, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x61, 0x70, 0x69, 0xa2, 0x02, 0x03, 0x58, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x58, 0x6d, 0x74, - 0x70, 0x2e, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0xca, 0x02, 0x0b, 0x58, 0x6d, 0x74, 0x70, 0x5c, - 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0xe2, 0x02, 0x17, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x58, 0x6d, - 0x74, 0x70, 0x76, 0x34, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x0c, 0x58, 0x6d, 0x74, 0x70, 0x3a, 0x3a, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, 0x6d, 0x6c, 0x73, + 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x2d, 0x65, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x42, 0xa3, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x6d, 0x74, + 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x42, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x41, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x6d, 0x74, 0x70, 0x2f, 0x78, 0x6d, 0x74, + 0x70, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x78, 0x6d, 0x74, + 0x70, 0x76, 0x34, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x70, 0x69, 0xa2, + 0x02, 0x03, 0x58, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x58, 0x6d, 0x74, 0x70, 0x2e, 0x58, 0x6d, 0x74, + 0x70, 0x76, 0x34, 0xca, 0x02, 0x0b, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x58, 0x6d, 0x74, 0x70, 0x76, + 0x34, 0xe2, 0x02, 0x17, 0x58, 0x6d, 0x74, 0x70, 0x5c, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x5c, + 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x58, 0x6d, + 0x74, 0x70, 0x3a, 0x3a, 0x58, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1295,63 +1316,65 @@ func file_xmtpv4_message_api_message_api_proto_rawDescGZIP() []byte { } var file_xmtpv4_message_api_message_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_xmtpv4_message_api_message_api_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_xmtpv4_message_api_message_api_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_xmtpv4_message_api_message_api_proto_goTypes = []any{ - (Misbehavior)(0), // 0: xmtp.xmtpv4.Misbehavior - (*VectorClock)(nil), // 1: xmtp.xmtpv4.VectorClock - (*AuthenticatedData)(nil), // 2: xmtp.xmtpv4.AuthenticatedData - (*ClientEnvelope)(nil), // 3: xmtp.xmtpv4.ClientEnvelope - (*PayerEnvelope)(nil), // 4: xmtp.xmtpv4.PayerEnvelope - (*UnsignedOriginatorEnvelope)(nil), // 5: xmtp.xmtpv4.UnsignedOriginatorEnvelope - (*BlockchainProof)(nil), // 6: xmtp.xmtpv4.BlockchainProof - (*OriginatorEnvelope)(nil), // 7: xmtp.xmtpv4.OriginatorEnvelope - (*MisbehaviorReport)(nil), // 8: xmtp.xmtpv4.MisbehaviorReport - (*EnvelopesQuery)(nil), // 9: xmtp.xmtpv4.EnvelopesQuery - (*BatchSubscribeEnvelopesRequest)(nil), // 10: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest - (*BatchSubscribeEnvelopesResponse)(nil), // 11: xmtp.xmtpv4.BatchSubscribeEnvelopesResponse - (*QueryEnvelopesRequest)(nil), // 12: xmtp.xmtpv4.QueryEnvelopesRequest - (*QueryEnvelopesResponse)(nil), // 13: xmtp.xmtpv4.QueryEnvelopesResponse - (*PublishEnvelopeRequest)(nil), // 14: xmtp.xmtpv4.PublishEnvelopeRequest - (*PublishEnvelopeResponse)(nil), // 15: xmtp.xmtpv4.PublishEnvelopeResponse - (*BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest)(nil), // 16: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest - (*v1.GroupMessageInput)(nil), // 17: xmtp.mls.api.v1.GroupMessageInput - (*v1.WelcomeMessageInput)(nil), // 18: xmtp.mls.api.v1.WelcomeMessageInput - (*associations.IdentityUpdate)(nil), // 19: xmtp.identity.associations.IdentityUpdate - (*v1.UploadKeyPackageRequest)(nil), // 20: xmtp.mls.api.v1.UploadKeyPackageRequest - (*associations.RecoverableEcdsaSignature)(nil), // 21: xmtp.identity.associations.RecoverableEcdsaSignature + (Misbehavior)(0), // 0: xmtp.xmtpv4.Misbehavior + (*VectorClock)(nil), // 1: xmtp.xmtpv4.VectorClock + (*AuthenticatedData)(nil), // 2: xmtp.xmtpv4.AuthenticatedData + (*ClientEnvelope)(nil), // 3: xmtp.xmtpv4.ClientEnvelope + (*PayerEnvelope)(nil), // 4: xmtp.xmtpv4.PayerEnvelope + (*UnsignedOriginatorEnvelope)(nil), // 5: xmtp.xmtpv4.UnsignedOriginatorEnvelope + (*BlockchainProof)(nil), // 6: xmtp.xmtpv4.BlockchainProof + (*OriginatorEnvelope)(nil), // 7: xmtp.xmtpv4.OriginatorEnvelope + (*MisbehaviorReport)(nil), // 8: xmtp.xmtpv4.MisbehaviorReport + (*EnvelopesQuery)(nil), // 9: xmtp.xmtpv4.EnvelopesQuery + (*BatchSubscribeEnvelopesRequest)(nil), // 10: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest + (*BatchSubscribeEnvelopesResponse)(nil), // 11: xmtp.xmtpv4.BatchSubscribeEnvelopesResponse + (*QueryEnvelopesRequest)(nil), // 12: xmtp.xmtpv4.QueryEnvelopesRequest + (*QueryEnvelopesResponse)(nil), // 13: xmtp.xmtpv4.QueryEnvelopesResponse + (*PublishEnvelopeRequest)(nil), // 14: xmtp.xmtpv4.PublishEnvelopeRequest + (*PublishEnvelopeResponse)(nil), // 15: xmtp.xmtpv4.PublishEnvelopeResponse + nil, // 16: xmtp.xmtpv4.VectorClock.NodeIdToSequenceIdEntry + (*BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest)(nil), // 17: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest + (*v1.GroupMessageInput)(nil), // 18: xmtp.mls.api.v1.GroupMessageInput + (*v1.WelcomeMessageInput)(nil), // 19: xmtp.mls.api.v1.WelcomeMessageInput + (*associations.IdentityUpdate)(nil), // 20: xmtp.identity.associations.IdentityUpdate + (*v1.UploadKeyPackageRequest)(nil), // 21: xmtp.mls.api.v1.UploadKeyPackageRequest + (*associations.RecoverableEcdsaSignature)(nil), // 22: xmtp.identity.associations.RecoverableEcdsaSignature } var file_xmtpv4_message_api_message_api_proto_depIdxs = []int32{ - 1, // 0: xmtp.xmtpv4.AuthenticatedData.last_seen:type_name -> xmtp.xmtpv4.VectorClock - 17, // 1: xmtp.xmtpv4.ClientEnvelope.group_message:type_name -> xmtp.mls.api.v1.GroupMessageInput - 18, // 2: xmtp.xmtpv4.ClientEnvelope.welcome_message:type_name -> xmtp.mls.api.v1.WelcomeMessageInput - 19, // 3: xmtp.xmtpv4.ClientEnvelope.identity_update:type_name -> xmtp.identity.associations.IdentityUpdate - 20, // 4: xmtp.xmtpv4.ClientEnvelope.upload_key_package:type_name -> xmtp.mls.api.v1.UploadKeyPackageRequest - 2, // 5: xmtp.xmtpv4.ClientEnvelope.aad:type_name -> xmtp.xmtpv4.AuthenticatedData - 21, // 6: xmtp.xmtpv4.PayerEnvelope.payer_signature:type_name -> xmtp.identity.associations.RecoverableEcdsaSignature - 4, // 7: xmtp.xmtpv4.UnsignedOriginatorEnvelope.payer_envelope:type_name -> xmtp.xmtpv4.PayerEnvelope - 21, // 8: xmtp.xmtpv4.OriginatorEnvelope.originator_signature:type_name -> xmtp.identity.associations.RecoverableEcdsaSignature - 6, // 9: xmtp.xmtpv4.OriginatorEnvelope.blockchain_proof:type_name -> xmtp.xmtpv4.BlockchainProof - 0, // 10: xmtp.xmtpv4.MisbehaviorReport.type:type_name -> xmtp.xmtpv4.Misbehavior - 7, // 11: xmtp.xmtpv4.MisbehaviorReport.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope - 1, // 12: xmtp.xmtpv4.EnvelopesQuery.last_seen:type_name -> xmtp.xmtpv4.VectorClock - 16, // 13: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.requests:type_name -> xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest - 7, // 14: xmtp.xmtpv4.BatchSubscribeEnvelopesResponse.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope - 9, // 15: xmtp.xmtpv4.QueryEnvelopesRequest.query:type_name -> xmtp.xmtpv4.EnvelopesQuery - 7, // 16: xmtp.xmtpv4.QueryEnvelopesResponse.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope - 4, // 17: xmtp.xmtpv4.PublishEnvelopeRequest.payer_envelope:type_name -> xmtp.xmtpv4.PayerEnvelope - 7, // 18: xmtp.xmtpv4.PublishEnvelopeResponse.originator_envelope:type_name -> xmtp.xmtpv4.OriginatorEnvelope - 9, // 19: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest.query:type_name -> xmtp.xmtpv4.EnvelopesQuery - 10, // 20: xmtp.xmtpv4.ReplicationApi.BatchSubscribeEnvelopes:input_type -> xmtp.xmtpv4.BatchSubscribeEnvelopesRequest - 12, // 21: xmtp.xmtpv4.ReplicationApi.QueryEnvelopes:input_type -> xmtp.xmtpv4.QueryEnvelopesRequest - 14, // 22: xmtp.xmtpv4.ReplicationApi.PublishEnvelope:input_type -> xmtp.xmtpv4.PublishEnvelopeRequest - 11, // 23: xmtp.xmtpv4.ReplicationApi.BatchSubscribeEnvelopes:output_type -> xmtp.xmtpv4.BatchSubscribeEnvelopesResponse - 13, // 24: xmtp.xmtpv4.ReplicationApi.QueryEnvelopes:output_type -> xmtp.xmtpv4.QueryEnvelopesResponse - 15, // 25: xmtp.xmtpv4.ReplicationApi.PublishEnvelope:output_type -> xmtp.xmtpv4.PublishEnvelopeResponse - 23, // [23:26] is the sub-list for method output_type - 20, // [20:23] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 16, // 0: xmtp.xmtpv4.VectorClock.node_id_to_sequence_id:type_name -> xmtp.xmtpv4.VectorClock.NodeIdToSequenceIdEntry + 1, // 1: xmtp.xmtpv4.AuthenticatedData.last_seen:type_name -> xmtp.xmtpv4.VectorClock + 18, // 2: xmtp.xmtpv4.ClientEnvelope.group_message:type_name -> xmtp.mls.api.v1.GroupMessageInput + 19, // 3: xmtp.xmtpv4.ClientEnvelope.welcome_message:type_name -> xmtp.mls.api.v1.WelcomeMessageInput + 20, // 4: xmtp.xmtpv4.ClientEnvelope.identity_update:type_name -> xmtp.identity.associations.IdentityUpdate + 21, // 5: xmtp.xmtpv4.ClientEnvelope.upload_key_package:type_name -> xmtp.mls.api.v1.UploadKeyPackageRequest + 2, // 6: xmtp.xmtpv4.ClientEnvelope.aad:type_name -> xmtp.xmtpv4.AuthenticatedData + 22, // 7: xmtp.xmtpv4.PayerEnvelope.payer_signature:type_name -> xmtp.identity.associations.RecoverableEcdsaSignature + 4, // 8: xmtp.xmtpv4.UnsignedOriginatorEnvelope.payer_envelope:type_name -> xmtp.xmtpv4.PayerEnvelope + 22, // 9: xmtp.xmtpv4.OriginatorEnvelope.originator_signature:type_name -> xmtp.identity.associations.RecoverableEcdsaSignature + 6, // 10: xmtp.xmtpv4.OriginatorEnvelope.blockchain_proof:type_name -> xmtp.xmtpv4.BlockchainProof + 0, // 11: xmtp.xmtpv4.MisbehaviorReport.type:type_name -> xmtp.xmtpv4.Misbehavior + 7, // 12: xmtp.xmtpv4.MisbehaviorReport.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope + 1, // 13: xmtp.xmtpv4.EnvelopesQuery.last_seen:type_name -> xmtp.xmtpv4.VectorClock + 17, // 14: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.requests:type_name -> xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest + 7, // 15: xmtp.xmtpv4.BatchSubscribeEnvelopesResponse.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope + 9, // 16: xmtp.xmtpv4.QueryEnvelopesRequest.query:type_name -> xmtp.xmtpv4.EnvelopesQuery + 7, // 17: xmtp.xmtpv4.QueryEnvelopesResponse.envelopes:type_name -> xmtp.xmtpv4.OriginatorEnvelope + 4, // 18: xmtp.xmtpv4.PublishEnvelopeRequest.payer_envelope:type_name -> xmtp.xmtpv4.PayerEnvelope + 7, // 19: xmtp.xmtpv4.PublishEnvelopeResponse.originator_envelope:type_name -> xmtp.xmtpv4.OriginatorEnvelope + 9, // 20: xmtp.xmtpv4.BatchSubscribeEnvelopesRequest.SubscribeEnvelopesRequest.query:type_name -> xmtp.xmtpv4.EnvelopesQuery + 10, // 21: xmtp.xmtpv4.ReplicationApi.BatchSubscribeEnvelopes:input_type -> xmtp.xmtpv4.BatchSubscribeEnvelopesRequest + 12, // 22: xmtp.xmtpv4.ReplicationApi.QueryEnvelopes:input_type -> xmtp.xmtpv4.QueryEnvelopesRequest + 14, // 23: xmtp.xmtpv4.ReplicationApi.PublishEnvelope:input_type -> xmtp.xmtpv4.PublishEnvelopeRequest + 11, // 24: xmtp.xmtpv4.ReplicationApi.BatchSubscribeEnvelopes:output_type -> xmtp.xmtpv4.BatchSubscribeEnvelopesResponse + 13, // 25: xmtp.xmtpv4.ReplicationApi.QueryEnvelopes:output_type -> xmtp.xmtpv4.QueryEnvelopesResponse + 15, // 26: xmtp.xmtpv4.ReplicationApi.PublishEnvelope:output_type -> xmtp.xmtpv4.PublishEnvelopeResponse + 24, // [24:27] is the sub-list for method output_type + 21, // [21:24] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_xmtpv4_message_api_message_api_proto_init() } @@ -1540,7 +1563,7 @@ func file_xmtpv4_message_api_message_api_proto_init() { return nil } } - file_xmtpv4_message_api_message_api_proto_msgTypes[15].Exporter = func(v any, i int) any { + file_xmtpv4_message_api_message_api_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*BatchSubscribeEnvelopesRequest_SubscribeEnvelopesRequest); i { case 0: return &v.state @@ -1573,7 +1596,7 @@ func file_xmtpv4_message_api_message_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_xmtpv4_message_api_message_api_proto_rawDesc, NumEnums: 1, - NumMessages: 16, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/registrant/registrant.go b/pkg/registrant/registrant.go index 4b6673a5..c912bc37 100644 --- a/pkg/registrant/registrant.go +++ b/pkg/registrant/registrant.go @@ -47,19 +47,12 @@ func NewRegistrant( }, nil } -func (r *Registrant) SID(localID int64) (uint64, error) { - if !utils.IsValidSequenceID(localID) { - return 0, fmt.Errorf("Invalid local ID %d, likely due to ID exhaustion", localID) - } - return utils.SID(r.record.NodeID, localID), nil -} - func (r *Registrant) signKeccak256(data []byte) ([]byte, error) { hash := crypto.Keccak256(data) return crypto.Sign(hash, r.privateKey) } -func (r *Registrant) NodeID() uint16 { +func (r *Registrant) NodeID() uint32 { return r.record.NodeID } @@ -70,14 +63,11 @@ func (r *Registrant) SignStagedEnvelope( if err := proto.Unmarshal(stagedEnv.PayerEnvelope, payerEnv); err != nil { return nil, fmt.Errorf("Could not unmarshal payer envelope: %v", err) } - sid, err := r.SID(stagedEnv.ID) - if err != nil { - return nil, err - } unsignedEnv := message_api.UnsignedOriginatorEnvelope{ - OriginatorSid: sid, - OriginatorNs: stagedEnv.OriginatorTime.UnixNano(), - PayerEnvelope: payerEnv, + OriginatorNodeId: r.record.NodeID, + OriginatorSequenceId: uint64(stagedEnv.ID), + OriginatorNs: stagedEnv.OriginatorTime.UnixNano(), + PayerEnvelope: payerEnv, } unsignedBytes, err := proto.Marshal(&unsignedEnv) if err != nil { diff --git a/pkg/registrant/registrant_test.go b/pkg/registrant/registrant_test.go index 8ed5d794..e79b9601 100644 --- a/pkg/registrant/registrant_test.go +++ b/pkg/registrant/registrant_test.go @@ -199,23 +199,6 @@ func TestSignStagedEnvelopeInvalidEnvelope(t *testing.T) { require.ErrorContains(t, err, "unmarshal") } -func TestSignStagedEnvelopeSIDExhaustion(t *testing.T) { - _, r, cleanup := setupWithRegistrant(t) - defer cleanup() - payerBytes, err := proto.Marshal(&message_api.PayerEnvelope{}) - require.NoError(t, err) - - _, err = r.SignStagedEnvelope( - queries.StagedOriginatorEnvelope{ - ID: 0b0000000000000001000000000000000000000000000000000000000000000000, - OriginatorTime: time.Now(), - PayerEnvelope: payerBytes, - }, - ) - - require.ErrorContains(t, err, "exhaustion") -} - func TestSignStagedEnvelopeSuccess(t *testing.T) { deps, r, cleanup := setupWithRegistrant(t) defer cleanup() @@ -245,6 +228,7 @@ func TestSignStagedEnvelopeSuccess(t *testing.T) { unsignedEnv := &message_api.UnsignedOriginatorEnvelope{} require.NoError(t, proto.Unmarshal(env.GetUnsignedOriginatorEnvelope(), unsignedEnv)) - require.Equal(t, unsignedEnv.GetOriginatorSid(), uint64(1<<48|50)) + require.Equal(t, unsignedEnv.GetOriginatorNodeId(), uint32(1)) + require.Equal(t, unsignedEnv.GetOriginatorSequenceId(), uint64(50)) require.Equal(t, unsignedEnv.GetPayerEnvelope().GetUnsignedClientEnvelope()[0], uint8(3)) } diff --git a/pkg/registry/contractRegistry.go b/pkg/registry/contractRegistry.go index d559588a..0621d680 100644 --- a/pkg/registry/contractRegistry.go +++ b/pkg/registry/contractRegistry.go @@ -34,11 +34,11 @@ type SmartContractRegistry struct { // How frequently to poll the smart contract refreshInterval time.Duration // Mapping of nodes from ID -> Node - nodes map[uint16]Node + nodes map[uint32]Node nodesMutex sync.RWMutex // Notifiers for new nodes and changed nodes newNodesNotifier *notifier[[]Node] - changedNodeNotifiers map[uint16]*notifier[Node] + changedNodeNotifiers map[uint32]*notifier[Node] changedNodeNotifiersMutex sync.RWMutex } @@ -61,8 +61,8 @@ func NewSmartContractRegistry( refreshInterval: options.RefreshInterval, logger: logger.Named("smartContractRegistry"), newNodesNotifier: newNotifier[[]Node](), - nodes: make(map[uint16]Node), - changedNodeNotifiers: make(map[uint16]*notifier[Node]), + nodes: make(map[uint32]Node), + changedNodeNotifiers: make(map[uint32]*notifier[Node]), }, nil } @@ -90,7 +90,7 @@ func (s *SmartContractRegistry) OnNewNodes() (<-chan []Node, CancelSubscription) } func (s *SmartContractRegistry) OnChangedNode( - nodeId uint16, + nodeId uint32, ) (<-chan Node, CancelSubscription) { s.changedNodeNotifiersMutex.Lock() defer s.changedNodeNotifiersMutex.Unlock() diff --git a/pkg/registry/contractRegistry_test.go b/pkg/registry/contractRegistry_test.go index e749634c..da0ccccc 100644 --- a/pkg/registry/contractRegistry_test.go +++ b/pkg/registry/contractRegistry_test.go @@ -111,7 +111,7 @@ func TestStopOnContextCancel(t *testing.T) { RunAndReturn(func(*bind.CallOpts) ([]abis.NodesNodeWithId, error) { return []abis.NodesNodeWithId{ { - NodeId: uint16(rand.Intn(1000)), + NodeId: uint32(rand.Intn(1000)), Node: abis.NodesNode{HttpAddress: "http://foo.com"}, }, }, nil diff --git a/pkg/registry/fixedRegistry.go b/pkg/registry/fixedRegistry.go index 38a8e064..057c3963 100644 --- a/pkg/registry/fixedRegistry.go +++ b/pkg/registry/fixedRegistry.go @@ -6,7 +6,7 @@ import "sync" type FixedNodeRegistry struct { nodes []Node newNodeNotifier *notifier[[]Node] - changedNodeNotifiers map[uint16]*notifier[Node] + changedNodeNotifiers map[uint32]*notifier[Node] changedNodeNotifiersMutex sync.Mutex } @@ -27,7 +27,7 @@ func (f *FixedNodeRegistry) OnNewNodes() (<-chan []Node, CancelSubscription) { } func (f *FixedNodeRegistry) OnChangedNode( - nodeId uint16, + nodeId uint32, ) (<-chan Node, CancelSubscription) { f.changedNodeNotifiersMutex.Lock() defer f.changedNodeNotifiersMutex.Unlock() diff --git a/pkg/registry/interface.go b/pkg/registry/interface.go index eddfca71..3914e93f 100644 --- a/pkg/registry/interface.go +++ b/pkg/registry/interface.go @@ -24,5 +24,5 @@ and notifying listeners when the list of nodes changes. type NodeRegistry interface { GetNodes() ([]Node, error) OnNewNodes() (<-chan []Node, CancelSubscription) - OnChangedNode(uint16) (<-chan Node, CancelSubscription) + OnChangedNode(uint32) (<-chan Node, CancelSubscription) } diff --git a/pkg/registry/node.go b/pkg/registry/node.go index 45800fbe..78cb8915 100644 --- a/pkg/registry/node.go +++ b/pkg/registry/node.go @@ -3,7 +3,7 @@ package registry import "crypto/ecdsa" type Node struct { - NodeID uint16 + NodeID uint32 SigningKey *ecdsa.PublicKey HttpAddress string IsHealthy bool diff --git a/pkg/testutils/envelopes.go b/pkg/testutils/envelopes.go index 3499c100..dbc5ad7d 100644 --- a/pkg/testutils/envelopes.go +++ b/pkg/testutils/envelopes.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/require" "github.com/xmtp/xmtpd/pkg/proto/identity/associations" "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/message_api" - "github.com/xmtp/xmtpd/pkg/utils" "google.golang.org/protobuf/proto" ) @@ -45,8 +44,8 @@ func CreatePayerEnvelope( func CreateOriginatorEnvelope( t *testing.T, - originatorNodeID uint16, - originatorSequenceID int64, + originatorNodeID uint32, + originatorSequenceID uint64, payerEnv ...*message_api.PayerEnvelope, ) *message_api.OriginatorEnvelope { if len(payerEnv) == 0 { @@ -54,9 +53,10 @@ func CreateOriginatorEnvelope( } unsignedEnv := &message_api.UnsignedOriginatorEnvelope{ - OriginatorSid: utils.SID(originatorNodeID, originatorSequenceID), - OriginatorNs: 0, - PayerEnvelope: payerEnv[0], + OriginatorNodeId: originatorNodeID, + OriginatorSequenceId: originatorSequenceID, + OriginatorNs: 0, + PayerEnvelope: payerEnv[0], } unsignedBytes, err := proto.Marshal(unsignedEnv) diff --git a/pkg/utils/sid.go b/pkg/utils/sid.go deleted file mode 100644 index 8229b0cc..00000000 --- a/pkg/utils/sid.go +++ /dev/null @@ -1,37 +0,0 @@ -package utils - -// SIDS are 64-bit numbers consisting of 16 bits for the node ID -// followed by 48 bits for the sequence ID. This file -// contains methods for reading and constructing sids. -// -// We also leverage type-checking throughout the repo to avoid confusion: -// - SIDs are uint64 -// - node IDs are uint16 -// - sequence IDs are int64 - -const ( - // Number of bits used for node ID - nodeIDBits uint64 = 16 - // Number of bits used for local ID - localIDBits uint64 = 64 - nodeIDBits - // A mask made by setting every bit in the node ID - nodeIDMask uint64 = 0xFFFF << localIDBits - // A mask made by setting every bit in the local ID - localIDMask uint64 = ^nodeIDMask -) - -func IsValidSequenceID(localID int64) bool { - return localID > 0 && localID>>localIDBits == 0 -} - -func NodeID(sid uint64) uint16 { - return uint16(sid >> localIDBits) -} - -func SequenceID(sid uint64) int64 { - return int64(sid & localIDMask) -} - -func SID(nodeID uint16, localID int64) uint64 { - return uint64(nodeID)<