diff --git a/consensus/blake3pow/consensus.go b/consensus/blake3pow/consensus.go index 4b03bd4193..b0c23cbb34 100644 --- a/consensus/blake3pow/consensus.go +++ b/consensus/blake3pow/consensus.go @@ -607,7 +607,7 @@ func (blake3pow *Blake3pow) Finalize(chain consensus.ChainHeaderReader, header * } state.CreateAccount(lockupContract) - alloc := core.ReadGenesisAlloc("genallocs/gen_quai_alloc_"+nodeLocation.Name()+".json", blake3pow.logger) + alloc := core.ReadGenesisAlloc("genallocs/gen_alloc_quai_"+nodeLocation.Name()+".json", blake3pow.logger) blake3pow.logger.WithField("alloc", len(alloc)).Info("Allocating genesis accounts") for addressString, account := range alloc { @@ -632,6 +632,7 @@ func (blake3pow *Blake3pow) Finalize(chain consensus.ChainHeaderReader, header * core.AddGenesisUtxos(state, nodeLocation, addressOutpointMap, blake3pow.logger) if chain.Config().IndexAddressUtxos { chain.WriteAddressOutpoints(addressOutpointMap) + blake3pow.logger.Info("Indexed genesis utxos") } } header.Header().SetUTXORoot(state.UTXORoot()) diff --git a/consensus/misc/rewards.go b/consensus/misc/rewards.go index 8134a611b5..673d2a6e63 100644 --- a/consensus/misc/rewards.go +++ b/consensus/misc/rewards.go @@ -6,7 +6,7 @@ import ( "github.com/dominant-strategies/go-quai/core/types" ) -func CalculateReward(header *types.WorkObject) *big.Int { +func CalculateReward(header *types.WorkObjectHeader) *big.Int { if header.Coinbase().IsInQiLedgerScope() { return calculateQiReward(header) } else { @@ -15,24 +15,24 @@ func CalculateReward(header *types.WorkObject) *big.Int { } // Calculate the amount of Quai that Qi can be converted to. Expect the current Header and the Qi amount in "qits", returns the quai amount in "its" -func QiToQuai(currentHeader *types.WorkObject, qiAmt *big.Int) *big.Int { +func QiToQuai(currentHeader *types.WorkObjectHeader, qiAmt *big.Int) *big.Int { quaiPerQi := new(big.Int).Div(calculateQuaiReward(currentHeader), calculateQiReward(currentHeader)) return new(big.Int).Mul(qiAmt, quaiPerQi) } // Calculate the amount of Qi that Quai can be converted to. Expect the current Header and the Quai amount in "its", returns the Qi amount in "qits" -func QuaiToQi(currentHeader *types.WorkObject, quaiAmt *big.Int) *big.Int { +func QuaiToQi(currentHeader *types.WorkObjectHeader, quaiAmt *big.Int) *big.Int { qiPerQuai := new(big.Int).Div(calculateQiReward(currentHeader), calculateQuaiReward(currentHeader)) return new(big.Int).Mul(quaiAmt, qiPerQuai) } // CalculateQuaiReward calculates the quai that can be recieved for mining a block and returns value in its -func calculateQuaiReward(header *types.WorkObject) *big.Int { +func calculateQuaiReward(header *types.WorkObjectHeader) *big.Int { return big.NewInt(1000000000000000000) } // CalculateQiReward caculates the qi that can be received for mining a block and returns value in qits -func calculateQiReward(header *types.WorkObject) *big.Int { +func calculateQiReward(header *types.WorkObjectHeader) *big.Int { return big.NewInt(1000) } diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 599682bdb0..06c5b9e69b 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -200,11 +200,8 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.WorkObject, events chan Ch // Fire the initial new head event to start any outstanding processing c.newHead(currentHeader.NumberU64(nodeCtx), false) - - var ( - prevHeader = currentHeader - prevHash = currentHeader.Hash() - ) + qiIndexerCh := make(chan *types.WorkObject, 10000) + go c.indexerLoop(currentHeader, qiIndexerCh, nodeCtx, config) for { select { case errc := <-c.quit: @@ -219,21 +216,40 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.WorkObject, events chan Ch errc <- nil return } - header := ev.Block + select { + case qiIndexerCh <- ev.Block: + default: + c.logger.Warn("qiIndexerCh is full, dropping block") + } + } + } +} +func (c *ChainIndexer) indexerLoop(currentHeader *types.WorkObject, qiIndexerCh chan *types.WorkObject, nodeCtx int, config params.ChainConfig) { + var ( + prevHeader = currentHeader + prevHash = currentHeader.Hash() + ) + for { + select { + case errc := <-c.quit: + // Chain indexer terminating, report no failure and abort + errc <- nil + return + case block := <-qiIndexerCh: var validUtxoIndex bool var addressOutpoints map[string]map[string]*types.OutpointAndDenomination if c.indexAddressUtxos { validUtxoIndex = true - addressOutpoints = rawdb.ReadAddressOutpoints(c.chainDb, config.Location) + addressOutpoints = make(map[string]map[string]*types.OutpointAndDenomination) } - if header.ParentHash(nodeCtx) != prevHash { + if block.ParentHash(nodeCtx) != prevHash { // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) // TODO: This seems a bit brittle, can we detect this case explicitly? if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.NumberU64(nodeCtx)) != prevHash { - if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header, nodeCtx); h != nil { + if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, block, nodeCtx); h != nil { // If indexAddressUtxos flag is enabled, update the address utxo map // TODO: Need to be able to turn on/off indexer and fix corrupted state @@ -251,7 +267,7 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.WorkObject, events chan Ch } // Add new blocks from current hash back to common ancestor - for curr := header; curr.Hash() != h.Hash(); curr = rawdb.ReadHeader(c.chainDb, curr.ParentHash(nodeCtx)) { + for curr := block; curr.Hash() != h.Hash(); curr = rawdb.ReadHeader(c.chainDb, curr.ParentHash(nodeCtx)) { block := rawdb.ReadWorkObject(c.chainDb, curr.Hash(), types.BlockObject) c.addOutpointsToIndexer(addressOutpoints, nodeCtx, config, block) } @@ -263,10 +279,10 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.WorkObject, events chan Ch } if c.indexAddressUtxos { - c.addOutpointsToIndexer(addressOutpoints, nodeCtx, config, ev.Block) + c.addOutpointsToIndexer(addressOutpoints, nodeCtx, config, block) } - c.newHead(header.NumberU64(nodeCtx), false) + c.newHead(block.NumberU64(nodeCtx), false) if c.indexAddressUtxos && validUtxoIndex { err := rawdb.WriteAddressOutpoints(c.chainDb, addressOutpoints) @@ -275,7 +291,7 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.WorkObject, events chan Ch } } - prevHeader, prevHash = header, header.Hash() + prevHeader, prevHash = block, block.Hash() } } } @@ -546,20 +562,23 @@ func (c *ChainIndexer) removeSectionHead(section uint64) { // addOutpointsToIndexer removes the spent outpoints and adds new utxos to the indexer. func (c *ChainIndexer) addOutpointsToIndexer(addressOutpoints map[string]map[string]*types.OutpointAndDenomination, nodeCtx int, config params.ChainConfig, block *types.WorkObject) { - utxos := block.QiTransactions() + utxos := block.QiTransactions() // TODO: Need to add the coinbase outputs into the Indexer for _, tx := range utxos { for _, in := range tx.TxIn() { - // Skip Coinbase TxIns since they do not have a previous outpoint - if types.IsCoinBaseTx(tx, block.ParentHash(nodeCtx), config.Location) { + if types.IsCoinBaseTx(tx) { continue } outpoint := in.PreviousOutPoint address := crypto.PubkeyBytesToAddress(in.PubKey, config.Location).Hex() - outpointsForAddress := addressOutpoints[address] + outpointsForAddress, exists := addressOutpoints[address] + if !exists { + outpointsForAddress = rawdb.ReadOutpointsForAddress(c.chainDb, address) + addressOutpoints[address] = outpointsForAddress + } delete(outpointsForAddress, outpoint.Key()) } @@ -580,8 +599,8 @@ func (c *ChainIndexer) addOutpointsToIndexer(addressOutpoints map[string]map[str Denomination: out.Denomination, } - if _, ok := addressOutpoints[address]; !ok { - addressOutpoints[address] = make(map[string]*types.OutpointAndDenomination) + if _, exists := addressOutpoints[address]; !exists { + addressOutpoints[address] = rawdb.ReadOutpointsForAddress(c.chainDb, address) } addressOutpoints[address][outpointAndDenom.Key()] = outpointAndDenom } @@ -600,7 +619,11 @@ func (c *ChainIndexer) reorgUtxoIndexer(headers []*types.WorkObject, addressOutp address := out.Address addr := common.BytesToAddress(address, config.Location).Hex() - outpointsForAddress := addressOutpoints[addr] + outpointsForAddress, exists := addressOutpoints[addr] + if !exists { + outpointsForAddress = rawdb.ReadOutpointsForAddress(c.chainDb, addr) + addressOutpoints[addr] = outpointsForAddress + } // reconstruct outpoint to remove it via outpoint.Key() outpoint := types.OutPoint{ @@ -611,7 +634,7 @@ func (c *ChainIndexer) reorgUtxoIndexer(headers []*types.WorkObject, addressOutp delete(outpointsForAddress, outpoint.Key()) } - if types.IsCoinBaseTx(tx, block.ParentHash(nodeCtx), config.Location) { + if types.IsCoinBaseTx(tx) { continue } @@ -638,8 +661,8 @@ func (c *ChainIndexer) reorgUtxoIndexer(headers []*types.WorkObject, addressOutp Denomination: entry.Denomination, } - if _, ok := addressOutpoints[address]; !ok { - addressOutpoints[address] = make(map[string]*types.OutpointAndDenomination) + if _, exists := addressOutpoints[address]; !exists { + addressOutpoints[address] = rawdb.ReadOutpointsForAddress(c.chainDb, address) } addressOutpoints[address][outpointAndDenom.Key()] = outpointAndDenom } diff --git a/core/core.go b/core/core.go index 1e7b72b566..bac7094693 100644 --- a/core/core.go +++ b/core/core.go @@ -600,7 +600,7 @@ func (c *Core) WriteBlock(block *types.WorkObject) { func (c *Core) Append(header *types.WorkObject, manifest types.BlockManifest, domPendingHeader *types.WorkObject, domTerminus common.Hash, domOrigin bool, newInboundEtxs types.Transactions) (types.Transactions, bool, bool, error) { nodeCtx := c.NodeCtx() // Set the coinbase into the right interface before calling append in the sub - header.Header().SetCoinbase(common.BytesToAddress(header.Coinbase().Bytes(), c.NodeLocation())) + header.WorkObjectHeader().SetCoinbase(common.BytesToAddress(header.Coinbase().Bytes(), c.NodeLocation())) newPendingEtxs, subReorg, setHead, err := c.sl.Append(header, domPendingHeader, domTerminus, domOrigin, newInboundEtxs) if err != nil { if err.Error() == ErrBodyNotFound.Error() || err.Error() == consensus.ErrUnknownAncestor.Error() || err.Error() == ErrSubNotSyncedToDom.Error() { @@ -1155,9 +1155,7 @@ func (c *Core) TrieNode(hash common.Hash) ([]byte, error) { } func (c *Core) GetOutpointsByAddress(address common.Address) map[string]*types.OutpointAndDenomination { - outpoints := rawdb.ReadAddressOutpoints(c.sl.hc.bc.db, c.sl.hc.NodeLocation()) - outpointsForAddress := outpoints[address.Hex()] - return outpointsForAddress + return rawdb.ReadOutpointsForAddress(c.sl.sliceDb, address.Hex()) } func (c *Core) GetUTXOsByAddressAtState(state *state.StateDB, address common.Address) ([]*types.UtxoEntry, error) { diff --git a/core/evm.go b/core/evm.go index fd95438f80..44fefba66d 100644 --- a/core/evm.go +++ b/core/evm.go @@ -52,7 +52,7 @@ type ChainContext interface { } // NewEVMBlockContext creates a new context for use in the EVM. -func NewEVMBlockContext(header *types.WorkObject, chain ChainContext, author *common.Address) (vm.BlockContext, error) { +func NewEVMBlockContext(header *types.WorkObject, parent *types.WorkObject, chain ChainContext, author *common.Address) (vm.BlockContext, error) { var ( beneficiary common.Address baseFee *big.Int @@ -81,10 +81,19 @@ func NewEVMBlockContext(header *types.WorkObject, chain ChainContext, author *co // Prime terminus determines which location is eligible to accept the etx primeTerminus := header.PrimeTerminus() - primeTerminusHeader := chain.GetHeaderByHash(primeTerminus) - if primeTerminusHeader == nil { - log.Global.Error("Prime terminus header not found ", " headerHash ", header.Hash(), " primeTerminus ", primeTerminus) - return vm.BlockContext{}, ErrSubNotSyncedToDom + _, parentOrder, err := chain.Engine().CalcOrder(parent) + if err != nil { + return vm.BlockContext{}, fmt.Errorf("parent order cannot be calculated") + } + var primeTerminusHeader *types.WorkObject + if parentOrder == common.PRIME_CTX { + primeTerminusHeader = parent + } else { + primeTerminusHeader = chain.GetHeaderByHash(primeTerminus) + if primeTerminusHeader == nil { + log.Global.Error("Prime terminus header not found", "headerHash", header.Hash(), "primeTerminus", primeTerminus) + return vm.BlockContext{}, ErrSubNotSyncedToDom + } } etxEligibleSlices := primeTerminusHeader.EtxEligibleSlices() diff --git a/core/genesis.go b/core/genesis.go index cf81499541..d849685f65 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -271,6 +271,7 @@ func (g *Genesis) ToBlock(startingExpansionNumber uint64) *types.WorkObject { wo.WorkObjectHeader().SetNonce(types.EncodeNonce(g.Nonce)) wo.WorkObjectHeader().SetDifficulty(g.Difficulty) wo.WorkObjectHeader().SetTime(g.Timestamp) + wo.WorkObjectHeader().SetCoinbase(common.Zero) wo.Header().SetExtra(g.ExtraData) wo.Header().SetGasLimit(g.GasLimit) wo.Header().SetGasUsed(0) @@ -285,7 +286,6 @@ func (g *Genesis) ToBlock(startingExpansionNumber uint64) *types.WorkObject { } else { wo.Header().SetEtxEligibleSlices(common.Hash{}) } - wo.Header().SetCoinbase(common.Zero) wo.Header().SetBaseFee(new(big.Int).SetUint64(params.InitialBaseFee)) wo.Header().SetEtxSetRoot(types.EmptyRootHash) if g.GasLimit == 0 { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index f11ce613a9..4737d092af 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -558,7 +558,7 @@ func ReadWorkObjectHeader(db ethdb.Reader, hash common.Hash, woType types.WorkOb db.Logger().WithField("err", err).Fatal("Failed to proto Unmarshal work object header") } workObjectHeader := new(types.WorkObjectHeader) - err = workObjectHeader.ProtoDecode(protoWorkObjectHeader) + err = workObjectHeader.ProtoDecode(protoWorkObjectHeader, db.Location()) if err != nil { db.Logger().WithFields(log.Fields{ "hash": hash, @@ -1030,9 +1030,9 @@ func (b badWorkObject) ProtoEncode() *ProtoBadWorkObject { } // ProtoDecode decodes the protobuf encoding of the bad workObject. -func (b *badWorkObject) ProtoDecode(pb *ProtoBadWorkObject) error { +func (b *badWorkObject) ProtoDecode(pb *ProtoBadWorkObject, location common.Location) error { woHeader := new(types.WorkObjectHeader) - if err := woHeader.ProtoDecode(pb.WoHeader); err != nil { + if err := woHeader.ProtoDecode(pb.WoHeader, location); err != nil { return err } b.woHeader = woHeader @@ -1062,11 +1062,11 @@ func (s badWorkObjectList) ProtoEncode() *ProtoBadWorkObjects { return &ProtoBadWorkObjects{BadWorkObjects: protoList} } -func (s *badWorkObjectList) ProtoDecode(pb *ProtoBadWorkObjects) error { +func (s *badWorkObjectList) ProtoDecode(pb *ProtoBadWorkObjects, location common.Location) error { list := make(badWorkObjectList, len(pb.BadWorkObjects)) for i, protoBlock := range pb.BadWorkObjects { block := new(badWorkObject) - if err := block.ProtoDecode(protoBlock); err != nil { + if err := block.ProtoDecode(protoBlock, location); err != nil { return err } list[i] = block @@ -1088,7 +1088,7 @@ func ReadBadWorkObject(db ethdb.Reader, hash common.Hash) *types.WorkObject { } badWorkObjects := new(badWorkObjectList) - err = badWorkObjects.ProtoDecode(protoBadWorkObjects) + err = badWorkObjects.ProtoDecode(protoBadWorkObjects, db.Location()) if err != nil { return nil } @@ -1588,34 +1588,35 @@ func DeleteInboundEtxs(db ethdb.KeyValueWriter, hash common.Hash) { } func WriteAddressOutpoints(db ethdb.KeyValueWriter, outpointMap map[string]map[string]*types.OutpointAndDenomination) error { - outpointsProto := &types.ProtoOutPointsMap{ - Entries: make(map[string]*types.ProtoAddressOutPoints), - } - for address, outpoints := range outpointMap { - addressOutpointsProto := &types.ProtoAddressOutPoints{ - OutPoints: make(map[string]*types.ProtoOutPointAndDenomination, len(outpoints)), + if err := WriteOutpointsForAddress(db, address, outpoints); err != nil { + return err } + } + return nil +} - for _, outpoint := range outpoints { - outpointProto, err := outpoint.ProtoEncode() - if err != nil { - return err - } +func WriteOutpointsForAddress(db ethdb.KeyValueWriter, address string, outpoints map[string]*types.OutpointAndDenomination) error { - addressOutpointsProto.OutPoints[outpoint.Key()] = outpointProto + addressOutpointsProto := &types.ProtoAddressOutPoints{ + OutPoints: make(map[string]*types.ProtoOutPointAndDenomination, len(outpoints)), + } + + for _, outpoint := range outpoints { + outpointProto, err := outpoint.ProtoEncode() + if err != nil { + return err } - // Correctly assign the address's UTXOs to the Entries map within the utxosProto struct - outpointsProto.Entries[address] = addressOutpointsProto + addressOutpointsProto.OutPoints[outpoint.Key()] = outpointProto } // Now, marshal utxosProto to protobuf bytes - data, err := proto.Marshal(outpointsProto) + data, err := proto.Marshal(addressOutpointsProto) if err != nil { db.Logger().WithField("err", err).Fatal("Failed to rlp encode utxos") } - if err := db.Put(AddressUtxosPrefix, data); err != nil { + if err := db.Put(addressUtxosKey(address), data); err != nil { db.Logger().WithField("err", err).Fatal("Failed to store utxos") } @@ -1623,38 +1624,34 @@ func WriteAddressOutpoints(db ethdb.KeyValueWriter, outpointMap map[string]map[s return db.Put(AddressUtxosPrefix, data) } -func ReadAddressOutpoints(db ethdb.Reader, location common.Location) map[string]map[string]*types.OutpointAndDenomination { +func ReadOutpointsForAddress(db ethdb.Reader, address string) map[string]*types.OutpointAndDenomination { // Try to look up the data in leveldb. - data, _ := db.Get(AddressUtxosPrefix) + data, _ := db.Get(addressUtxosKey(address)) if len(data) == 0 { - return make(map[string]map[string]*types.OutpointAndDenomination) + return make(map[string]*types.OutpointAndDenomination) } - outpointsProto := &types.ProtoOutPointsMap{} - if err := proto.Unmarshal(data, outpointsProto); err != nil { + addressOutpointsProto := &types.ProtoAddressOutPoints{ + OutPoints: make(map[string]*types.ProtoOutPointAndDenomination), + } + if err := proto.Unmarshal(data, addressOutpointsProto); err != nil { return nil } + outpoints := map[string]*types.OutpointAndDenomination{} - outpointsMap := make(map[string]map[string]*types.OutpointAndDenomination) - for addrStr, addressOutpointsProto := range outpointsProto.Entries { - outpoints := map[string]*types.OutpointAndDenomination{} - - for _, outpointProto := range addressOutpointsProto.OutPoints { - outpoint := new(types.OutpointAndDenomination) - err := outpoint.ProtoDecode(outpointProto) - if err != nil { - db.Logger().WithFields(log.Fields{ - "err": err, - "outpoint": outpointProto, - }).Error("Invalid outpointProto") - return nil - } - outpoints[outpoint.Key()] = outpoint + for _, outpointProto := range addressOutpointsProto.OutPoints { + outpoint := new(types.OutpointAndDenomination) + err := outpoint.ProtoDecode(outpointProto) + if err != nil { + db.Logger().WithFields(log.Fields{ + "err": err, + "outpoint": outpointProto, + }).Error("Invalid outpointProto") + return nil } - - outpointsMap[addrStr] = outpoints + outpoints[outpoint.Key()] = outpoint } - return outpointsMap + return outpoints } func DeleteAddressUtxos(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 8fb1218661..380961b24c 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -72,7 +72,7 @@ func TestHeaderStorage(t *testing.T) { woBody := types.EmptyWorkObjectBody() woBody.SetHeader(header) - woHeader := types.NewWorkObjectHeader(header.Hash(), common.Hash{1}, big.NewInt(1), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01})) + woHeader := types.NewWorkObjectHeader(header.Hash(), common.Hash{1}, big.NewInt(1), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01}), common.BytesToAddress([]byte{1}, common.Location{0, 0})) wo := types.NewWorkObject(woHeader, woBody, nil) @@ -219,7 +219,7 @@ func TestPbCacheStorage(t *testing.T) { woBody.SetExtTransactions([]*types.Transaction{}) woBody.SetHeader(types.EmptyHeader()) - woHeader := types.NewWorkObjectHeader(types.EmptyRootHash, types.EmptyRootHash, big.NewInt(11), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01})) + woHeader := types.NewWorkObjectHeader(types.EmptyRootHash, types.EmptyRootHash, big.NewInt(11), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01}), common.BytesToAddress([]byte{1}, common.Location{0, 0})) wo := types.NewWorkObject(woHeader, woBody, nil) WritePbCacheBody(db, common.Hash{1}, wo) @@ -398,7 +398,7 @@ func TestBlockHashesIterator(t *testing.T) { blockHeader := types.EmptyHeader() blockBody := types.EmptyWorkObjectBody() blockBody.SetHeader(blockHeader) - blockWoHeader := types.NewWorkObjectHeader(blockHeader.Hash(), types.EmptyHash, big.NewInt(int64(i+1)), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, byte(j)}) + blockWoHeader := types.NewWorkObjectHeader(blockHeader.Hash(), types.EmptyHash, big.NewInt(int64(i+1)), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, byte(j)}, common.BytesToAddress([]byte{1}, common.Location{0, byte(j)})) block := types.NewWorkObject(blockWoHeader, blockBody, nil) WriteWorkObject(db, block.Hash(), block, types.BlockObject, common.ZONE_CTX) hashes[i][block.Hash()] = true @@ -423,7 +423,7 @@ func TestCommonAncestor(t *testing.T) { regionHeader.SetNumber(big.NewInt(1), common.REGION_CTX) regionBody := types.EmptyWorkObjectBody() regionBody.SetHeader(regionHeader) - regionWoHeader := types.NewWorkObjectHeader(regionHeader.Hash(), types.EmptyRootHash, big.NewInt(1), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.Location{0}) + regionWoHeader := types.NewWorkObjectHeader(regionHeader.Hash(), types.EmptyRootHash, big.NewInt(1), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.Location{0}, common.BytesToAddress([]byte{0}, common.Location{0, 0})) regionBlock := types.NewWorkObject(regionWoHeader, regionBody, nil) WriteWorkObject(db, regionBlock.Hash(), regionBlock, types.BlockObject, common.REGION_CTX) @@ -431,7 +431,7 @@ func TestCommonAncestor(t *testing.T) { zone0Header := types.EmptyHeader() zone0Body := types.EmptyWorkObjectBody() zone0Body.SetHeader(zone0Header) - zone0WoHeader := types.NewWorkObjectHeader(zone0Header.Hash(), regionBlock.Hash(), big.NewInt(2), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, 0}) + zone0WoHeader := types.NewWorkObjectHeader(zone0Header.Hash(), regionBlock.Hash(), big.NewInt(2), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, 0}, common.BytesToAddress([]byte{0}, common.Location{0, 0})) zone0Block := types.NewWorkObject(zone0WoHeader, zone0Body, nil) WriteWorkObject(db, zone0Block.Hash(), zone0Block, types.BlockObject, common.ZONE_CTX) @@ -439,14 +439,14 @@ func TestCommonAncestor(t *testing.T) { zone1Header1 := types.EmptyHeader() zone1Body1 := types.EmptyWorkObjectBody() zone1Body1.SetHeader(zone1Header1) - zone1WoHeader1 := types.NewWorkObjectHeader(zone1Header1.Hash(), regionBlock.Hash(), big.NewInt(2), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, 1}) + zone1WoHeader1 := types.NewWorkObjectHeader(zone1Header1.Hash(), regionBlock.Hash(), big.NewInt(2), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 2, common.Location{0, 1}, common.BytesToAddress([]byte{0}, common.Location{0, 1})) zone1Block1 := types.NewWorkObject(zone1WoHeader1, zone1Body1, nil) WriteWorkObject(db, zone1Block1.Hash(), zone1Block1, types.BlockObject, common.ZONE_CTX) zone1Header2 := types.EmptyHeader() zone1Body2 := types.EmptyWorkObjectBody() zone1Body2.SetHeader(zone1Header2) - zone1WoHeader2 := types.NewWorkObjectHeader(zone1Header2.Hash(), zone1Block1.Hash(), big.NewInt(3), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 3, common.Location{0, 1}) + zone1WoHeader2 := types.NewWorkObjectHeader(zone1Header2.Hash(), zone1Block1.Hash(), big.NewInt(3), big.NewInt(3000), types.EmptyRootHash, types.BlockNonce{23}, 3, common.Location{0, 1}, common.BytesToAddress([]byte{0}, common.Location{0, 1})) zone1Block2 := types.NewWorkObject(zone1WoHeader2, zone1Body2, nil) WriteWorkObject(db, zone1Block2.Hash(), zone1Block2, types.BlockObject, common.ZONE_CTX) @@ -639,7 +639,7 @@ func TestWorkObjectStorage(t *testing.T) { woBody.SetTransactions([]*types.Transaction{}) woBody.SetExtTransactions([]*types.Transaction{}) woBody.SetHeader(types.EmptyHeader()) - header := types.NewWorkObject(types.NewWorkObjectHeader(types.EmptyRootHash, types.EmptyRootHash, big.NewInt(11), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01})), woBody, nil) + header := types.NewWorkObject(types.NewWorkObjectHeader(types.EmptyRootHash, types.EmptyRootHash, big.NewInt(11), big.NewInt(30000), types.EmptyRootHash, types.BlockNonce{23}, 1, common.LocationFromAddressBytes([]byte{0x01, 0x01}), common.BytesToAddress([]byte{0}, common.Location{0, 0})), woBody, nil) if entry := ReadWorkObject(db, header.Hash(), types.BlockObject); entry != nil { t.Fatalf("Non existent header returned: %v", entry) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 5af28094d6..3b26432db0 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -383,3 +383,7 @@ func bloomKey(hash common.Hash) []byte { func inboundEtxsKey(hash common.Hash) []byte { return append(inboundEtxsPrefix, hash.Bytes()...) } + +func addressUtxosKey(address string) []byte { + return append(AddressUtxosPrefix, address[:]...) +} diff --git a/core/slice.go b/core/slice.go index 4dec37dbee..f7bd5e9b26 100644 --- a/core/slice.go +++ b/core/slice.go @@ -255,7 +255,7 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb // After writing the inbound etxs, we need to just send the inbounds for // the given block location down in the region if nodeCtx == common.REGION_CTX { - newInboundEtxs = newInboundEtxs.FilterToSub(block.Location(), nodeCtx) + newInboundEtxs = newInboundEtxs.FilterToSub(block.Location(), nodeCtx, order) } } @@ -268,7 +268,7 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb if exists && cachedInboundEtxs != nil { newInboundEtxs = cachedInboundEtxs } else { - newInboundEtxs, _, err = sl.CollectNewlyConfirmedEtxs(block) + newInboundEtxs, err = sl.CollectNewlyConfirmedEtxs(block, order) if err != nil { sl.logger.WithField("err", err).Trace("Error collecting newly confirmed etxs") // Keeping track of the number of times pending etx fails and if it crossed the retry threshold @@ -318,7 +318,7 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb } for _, etx := range subRollup { to := etx.To().Location() - if to.Region() != sl.NodeLocation().Region() || etx.IsTxAConversionTx(sl.NodeLocation()) { + if to.Region() != sl.NodeLocation().Region() || types.IsConversionTx(etx) || types.IsCoinBaseTx(etx) { crossPrimeRollup = append(crossPrimeRollup, etx) } } @@ -381,6 +381,7 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb time9 = common.PrettyDuration(time.Since(start)) sl.updatePhCache(pendingHeaderWithTermini, true, nil, subReorg, sl.NodeLocation()) + time10 := common.PrettyDuration(time.Since(start)) var updateDom bool if subReorg { if order == common.ZONE_CTX && pendingHeaderWithTermini.Termini().DomTerminus(sl.NodeLocation()) != bestPh.Termini().DomTerminus(sl.NodeLocation()) { @@ -399,12 +400,15 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb sl.WriteBestPhKey(pendingHeaderWithTermini.Termini().DomTerminus(sl.NodeLocation())) block.SetAppendTime(time.Duration(time9)) } + time11 := common.PrettyDuration(time.Since(start)) // Append has succeeded write the batch if err := batch.Write(); err != nil { return nil, false, false, err } + time12 := common.PrettyDuration(time.Since(start)) + if setHead { sl.hc.SetCurrentHeader(block) } else if !setHead && nodeCtx == common.ZONE_CTX && sl.hc.ProcessingState() { @@ -416,12 +420,13 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb }).Debug("Found uncle") sl.hc.chainSideFeed.Send(ChainSideEvent{Blocks: []*types.WorkObject{block}}) } - + time13 := common.PrettyDuration(time.Since(start)) // Chain head feed is only used by the Zone chains if subReorg && nodeCtx == common.ZONE_CTX { sl.hc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) } + time14 := common.PrettyDuration(time.Since(start)) // If efficiency score changed on this block compared to the parent block // we trigger the expansion using the expansion feed if nodeCtx == common.PRIME_CTX { @@ -431,12 +436,11 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb } } + time15 := common.PrettyDuration(time.Since(start)) // Relay the new pendingHeader sl.relayPh(block, pendingHeaderWithTermini, domOrigin, block.Location(), subReorg) - inputs, outputs := block.InputsAndOutputsWithoutCoinbase() - net := int(outputs) - int(inputs) - time10 := common.PrettyDuration(time.Since(start)) + time16 := common.PrettyDuration(time.Since(start)) sl.logger.WithFields(log.Fields{ "t0_1": time0_1, "t0_2": time0_2, @@ -450,6 +454,12 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb "t8": time8, "t9": time9, "t10": time10, + "t11": time11, + "t12": time12, + "t13": time13, + "t14": time14, + "t15": time15, + "t16": time16, }).Info("Times during append") sl.logger.WithFields(log.Fields{ @@ -464,6 +474,10 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb workShare = big.NewInt(0) } + if nodeCtx == common.ZONE_CTX { + sl.logger.WithFields(block.TransactionsInfo()).Info("Transactions info for Block") + } + sl.logger.WithFields(log.Fields{ "number": block.NumberArray(), "hash": block.Hash(), @@ -472,11 +486,6 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb "totalTxs": len(block.Transactions()), "iworkShare": common.BigBitsToBitsFloat(workShare), "intrinsicS": common.BigBitsToBits(intrinsicS), - "etxs emitted": len(block.ExtTransactions()), - "qiTxs": len(block.QiTransactions()), - "net outputs-inputs": net, - "quaiTxs": len(block.QuaiTransactions()), - "etxs inbound": len(block.Body().ExternalTransactions()), "inboundEtxs from dom": len(newInboundEtxs), "gas": block.GasUsed(), "gasLimit": block.GasLimit(), @@ -746,7 +755,7 @@ func (sl *Slice) generateSlicePendingHeader(block *types.WorkObject, newTermini } // CollectNewlyConfirmedEtxs collects all newly confirmed ETXs since the last coincident with the given location -func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject) (types.Transactions, types.Transactions, error) { +func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject, blockOrder int) (types.Transactions, error) { nodeCtx := sl.NodeCtx() blockLocation := block.Location() // Collect rollup of ETXs from the subordinate node's manifest @@ -763,20 +772,20 @@ func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject) (types.Trans } else { subRollup, err = sl.hc.CollectSubRollup(block) if err != nil { - return nil, nil, err + return nil, err } sl.hc.subRollupCache.Add(block.Hash(), subRollup) } } // Filter for ETXs destined to this sub - newInboundEtxs := subRollup.FilterToSub(blockLocation, sl.NodeCtx()) + newInboundEtxs := subRollup.FilterToSub(blockLocation, sl.NodeCtx(), blockOrder) newlyConfirmedEtxs := newInboundEtxs for { ancHash := block.ParentHash(nodeCtx) ancNum := block.NumberU64(nodeCtx) - 1 parent := sl.hc.GetBlock(ancHash, ancNum) if parent == nil { - return nil, nil, fmt.Errorf("unable to find parent, hash: %s", ancHash.String()) + return nil, fmt.Errorf("unable to find parent, hash: %s", ancHash.String()) } if sl.hc.IsGenesisHash(ancHash) { @@ -791,7 +800,7 @@ func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject) (types.Trans var err error _, order, err := sl.Engine().CalcOrder(parent) if err != nil { - return nil, nil, err + return nil, err } regions, zones := common.GetHierarchySizeForExpansionNumber(parent.ExpansionNumber()) if order == common.PRIME_CTX && (blockLocation.Region() > int(regions) || blockLocation.Zone() > int(zones)) { @@ -815,7 +824,7 @@ func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject) (types.Trans } else { subRollup, err = sl.hc.CollectSubRollup(parent) if err != nil { - return nil, nil, err + return nil, err } sl.hc.subRollupCache.Add(parent.Hash(), subRollup) } @@ -825,14 +834,16 @@ func (sl *Slice) CollectNewlyConfirmedEtxs(block *types.WorkObject) (types.Trans // are going towards the given zone if nodeCtx == common.REGION_CTX && order < nodeCtx && !blockLocation.Equal(parent.Location()) { inboundEtxs := rawdb.ReadInboundEtxs(sl.sliceDb, parent.Hash()) - subRollup = append(subRollup, inboundEtxs...) + // Filter the Conversion and Coinbase Txs that needs to go the blockLocation + filteredInboundEtxs := inboundEtxs.FilterToSub(blockLocation, sl.NodeCtx(), common.PRIME_CTX) + newlyConfirmedEtxs = append(newlyConfirmedEtxs, filteredInboundEtxs...) } - ancInboundEtxs := subRollup.FilterToSub(blockLocation, sl.NodeCtx()) + ancInboundEtxs := subRollup.FilterToSub(blockLocation, sl.NodeCtx(), blockOrder) newlyConfirmedEtxs = append(newlyConfirmedEtxs, ancInboundEtxs...) block = parent } - return newlyConfirmedEtxs, subRollup, nil + return newlyConfirmedEtxs, nil } // PCRC previous coincidence reference check makes sure there are not any cyclic references in the graph and calculates new termini and the block terminus @@ -1334,7 +1345,7 @@ func (sl *Slice) ConstructLocalMinedBlock(wo *types.WorkObject) (*types.WorkObje }).Error("Pending Block Body not found") return nil, ErrBodyNotFound } - if len(pendingBlockBody.Transactions()) == 0 { + if len(pendingBlockBody.ExtTransactions()) == 0 { sl.logger.WithFields(log.Fields{"wo.Hash": wo.Hash(), "wo.Header": wo.HeaderHash(), "wo.ParentHash": wo.ParentHash(common.ZONE_CTX), @@ -1416,6 +1427,7 @@ func (sl *Slice) combinePendingHeader(header *types.WorkObject, slPendingHeader if inSlice { combinedPendingHeader.WorkObjectHeader().SetDifficulty(header.Difficulty()) combinedPendingHeader.WorkObjectHeader().SetTxHash(header.TxHash()) + combinedPendingHeader.WorkObjectHeader().SetCoinbase(header.Coinbase()) combinedPendingHeader.Header().SetEtxRollupHash(header.EtxRollupHash()) combinedPendingHeader.Header().SetUncledS(header.Header().UncledS()) @@ -1427,7 +1439,6 @@ func (sl *Slice) combinePendingHeader(header *types.WorkObject, slPendingHeader combinedPendingHeader.Header().SetEVMRoot(header.EVMRoot()) combinedPendingHeader.Header().SetUTXORoot(header.UTXORoot()) combinedPendingHeader.Header().SetEtxSetRoot(header.EtxSetRoot()) - combinedPendingHeader.Header().SetCoinbase(header.Coinbase()) combinedPendingHeader.Header().SetBaseFee(header.BaseFee()) combinedPendingHeader.Header().SetGasLimit(header.GasLimit()) combinedPendingHeader.Header().SetGasUsed(header.GasUsed()) @@ -1549,7 +1560,7 @@ func (sl *Slice) NewGenesisPendingHeader(domPendingHeader *types.WorkObject, dom } if nodeCtx != common.ZONE_CTX { - localPendingHeader.Header().SetCoinbase(common.Zero) + localPendingHeader.WorkObjectHeader().SetCoinbase(common.Zero) } localPendingHeader.WorkObjectHeader().SetLocation(common.Location{0, 0}) diff --git a/core/state_processor.go b/core/state_processor.go index 98e5c35928..bdd03d3f8d 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -239,9 +239,6 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty if err != nil { return types.Receipts{}, []*types.Transaction{}, []*types.Log{}, nil, 0, err } - if len(block.Transactions()) == 0 { - return types.Receipts{}, []*types.Transaction{}, []*types.Log{}, statedb, 0, nil - } // Apply the previous inbound ETXs to the ETX set state prevInboundEtxs := rawdb.ReadInboundEtxs(p.hc.bc.db, header.ParentHash(nodeCtx)) if len(prevInboundEtxs) > 0 { @@ -256,11 +253,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty senders := make(map[common.Hash]*common.InternalAddress) // temporary cache for senders of internal txs numInternalTxs := 0 p.hc.pool.SendersMu.RLock() // Prevent the txpool from grabbing the lock during the entire block tx lookup - for i, tx := range block.Transactions() { // get all senders of internal txs from cache - if i == 0 && types.IsCoinBaseTx(tx, header.ParentHash(nodeCtx), nodeLocation) { - // coinbase tx is not in senders cache - continue - } + for _, tx := range block.Transactions() { // get all senders of internal txs from cache if tx.Type() == types.QuaiTxType { numInternalTxs++ if sender, ok := p.hc.pool.PeekSenderNoLock(tx.Hash()); ok { @@ -277,7 +270,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty } p.hc.pool.SendersMu.RUnlock() timeSenders = time.Since(startTimeSenders) - blockContext, err := NewEVMBlockContext(header, p.hc, nil) + blockContext, err := NewEVMBlockContext(header, parent, p.hc, nil) if err != nil { return nil, nil, nil, nil, 0, err } @@ -298,13 +291,31 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty totalEtxGas := uint64(0) totalFees := big.NewInt(0) emittedEtxs := make([]*types.Transaction, 0) + // create a etx for the Coinbase and all the workshares in the block + coinbase := block.Coinbase() + if coinbase.IsInQiLedgerScope() { // placeholder for the coinbase + coinbaseEtx := types.NewTx(&types.ExternalTx{}) + emittedEtxs = append(emittedEtxs, coinbaseEtx) + } else if coinbase.IsInQuaiLedgerScope() { + coinbaseEtx := types.NewTx(&types.ExternalTx{}) + emittedEtxs = append(emittedEtxs, coinbaseEtx) + } + + // Add an etx for each workshare for it to be rewarded + for i, uncle := range block.Uncles() { + reward := misc.CalculateReward(uncle) + uncleCoinbase := uncle.Coinbase() + // parent hash encoding for populating into the originating tx hash for coinbase + origin := block.ParentHash(nodeCtx) + origin[0] = byte(block.Location().Region()) + origin[1] = byte(block.Location().Zone()) + + emittedEtxs = append(emittedEtxs, types.NewTx(&types.ExternalTx{To: &uncleCoinbase, Value: reward, IsCoinbase: true, OriginatingTxHash: origin, ETXIndex: uint16(i) + 1, Sender: uncleCoinbase})) + } var totalQiTime time.Duration for i, tx := range block.Transactions() { - if i == 0 && types.IsCoinBaseTx(tx, header.ParentHash(nodeCtx), nodeLocation) { - // coinbase tx currently exempt from gas and outputs are added after all txs are processed - continue - } startProcess := time.Now() + if tx.Type() == types.QiTxType { qiTimeBefore := time.Now() checkSig := true @@ -318,7 +329,15 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty for _, etx := range etxs { emittedEtxs = append(emittedEtxs, types.NewTx(etx)) } - totalFees.Add(totalFees, fees) + if block.Coinbase().IsInQiLedgerScope() { + totalFees.Add(totalFees, fees) + } else { + primeTerminus := p.hc.GetHeaderByHash(header.PrimeTerminus()) + if primeTerminus == nil { + return nil, nil, nil, nil, 0, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) + } + totalFees.Add(totalFees, misc.QiToQuai(primeTerminus.WorkObjectHeader(), fees)) + } totalQiTime += time.Since(qiTimeBefore) continue } @@ -337,6 +356,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty var receipt *types.Receipt var addReceipt bool + quaiFees := big.NewInt(0) if tx.Type() == types.ExternalTxType { startTimeEtx := time.Now() // ETXs MUST be included in order, so popping the first from the queue must equal the first in the block @@ -350,6 +370,45 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty if etx.Hash() != tx.Hash() { return nil, nil, nil, nil, 0, fmt.Errorf("invalid external transaction: etx %x is not in order or not found in unspent etx set", tx.Hash()) } + // check if the tx is a coinbase tx + // coinbase tx + // 1) is a external tx type + // 2) do not consume any gas + // 3) do not produce any receipts/logs + // 4) etx emit threshold numbers + if types.IsCoinBaseTx(tx) { + iAddr, err := tx.To().InternalAddress() + if err != nil { + return nil, nil, nil, nil, 0, errors.New("coinbase address is not in the chain scope") + } + if tx.To().IsInQiLedgerScope() { + value := tx.Value() + denominations := misc.FindMinDenominations(value) + outputIndex := uint16(0) + // Iterate over the denominations in descending order + for denomination := types.MaxDenomination; denomination >= 0; denomination-- { + // If the denomination count is zero, skip it + if denominations[uint8(denomination)] == 0 { + continue + } + for j := uint8(0); j < denominations[uint8(denomination)]; j++ { + if outputIndex >= types.MaxOutputIndex { + // No more gas, the rest of the denominations are lost but the tx is still valid + break + } + // the ETX hash is guaranteed to be unique + if err := statedb.CreateUTXO(etx.Hash(), outputIndex, types.NewUtxoEntry(types.NewTxOut(uint8(denomination), tx.To().Bytes(), block.Number(nodeCtx)))); err != nil { + return nil, nil, nil, nil, 0, err + } + outputIndex++ + } + } + } else if tx.To().IsInQuaiLedgerScope() { + // This includes the value and the fees + statedb.AddBalance(iAddr, tx.Value()) + } + continue + } if etx.To().IsInQiLedgerScope() { if etx.ETXSender().Location().Equal(*etx.To().Location()) { // Quai->Qi Conversion lock := new(big.Int).Add(header.Number(nodeCtx), big.NewInt(params.ConversionLockPeriod)) @@ -357,7 +416,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty if primeTerminus == nil { return nil, nil, nil, nil, 0, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) } - value := misc.QuaiToQi(primeTerminus, etx.Value()) // convert Quai to Qi + value := misc.QuaiToQi(primeTerminus.WorkObjectHeader(), etx.Value()) // convert Quai to Qi txGas := etx.Gas() denominations := misc.FindMinDenominations(value) outputIndex := uint16(0) @@ -409,17 +468,26 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty return nil, nil, nil, nil, 0, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) } // Convert Qi to Quai - msg.SetValue(misc.QiToQuai(primeTerminus, etx.Value())) + msg.SetValue(misc.QiToQuai(primeTerminus.WorkObjectHeader(), etx.Value())) msg.SetData([]byte{}) // data is not used in conversion log.Global.Infof("Converting Qi to Quai for ETX %032x with value %d lock %d", tx.Hash(), msg.Value().Uint64(), msg.Lock().Uint64()) } prevZeroBal := prepareApplyETX(statedb, msg.Value(), nodeLocation) - receipt, err = applyTransaction(msg, parent, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, etx, usedGas, vmenv, &etxRLimit, &etxPLimit, p.logger) + receipt, quaiFees, err = applyTransaction(msg, parent, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, etx, usedGas, vmenv, &etxRLimit, &etxPLimit, p.logger) statedb.SetBalance(common.ZeroInternal(nodeLocation), prevZeroBal) // Reset the balance to what it previously was. Residual balance will be lost if err != nil { return nil, nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } addReceipt = true + if block.Coinbase().IsInQuaiLedgerScope() { + totalFees.Add(totalFees, quaiFees) + } else { + primeTerminus := p.hc.GetHeaderByHash(header.PrimeTerminus()) + if primeTerminus == nil { + return nil, nil, nil, nil, 0, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) + } + totalFees.Add(totalFees, misc.QuaiToQi(primeTerminus.WorkObjectHeader(), quaiFees)) + } totalEtxGas += receipt.GasUsed timeEtxDelta := time.Since(startTimeEtx) timeEtx += timeEtxDelta @@ -427,13 +495,22 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty } else if tx.Type() == types.QuaiTxType { startTimeTx := time.Now() - receipt, err = applyTransaction(msg, parent, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, &etxRLimit, &etxPLimit, p.logger) + receipt, quaiFees, err = applyTransaction(msg, parent, p.config, p.hc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, &etxRLimit, &etxPLimit, p.logger) if err != nil { return nil, nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } addReceipt = true timeTxDelta := time.Since(startTimeTx) timeTx += timeTxDelta + if block.Coinbase().IsInQuaiLedgerScope() { + totalFees.Add(totalFees, quaiFees) + } else { + primeTerminus := p.hc.GetHeaderByHash(header.PrimeTerminus()) + if primeTerminus == nil { + return nil, nil, nil, nil, 0, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) + } + totalFees.Add(totalFees, misc.QuaiToQi(primeTerminus.WorkObjectHeader(), quaiFees)) + } } else { return nil, nil, nil, nil, 0, ErrTxTypeNotSupported } @@ -449,86 +526,6 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty i++ } - coinbaseTx := block.Transactions()[0] - // Coinbase check - if types.IsCoinBaseTx(coinbaseTx, header.ParentHash(nodeCtx), nodeLocation) { - if coinbaseTx.Type() == types.QiTxType { - // Public key aggregation for coinbase tx inputs - pubKeys := make([]*btcec.PublicKey, 0) - for _, txIn := range coinbaseTx.TxIn() { - pubKey, err := btcec.ParsePubKey(txIn.PubKey) - if err != nil { - return nil, nil, nil, nil, 0, err - } - pubKeys = append(pubKeys, pubKey) - } - - // Ensure the coinbase signature is valid - var finalKey *btcec.PublicKey - if len(coinbaseTx.TxIn()) > 1 { - aggKey, _, _, err := musig2.AggregateKeys( - pubKeys, false, - ) - if err != nil { - return nil, nil, nil, nil, 0, err - } - finalKey = aggKey.FinalKey - } else { - finalKey = pubKeys[0] - } - txDigestHash := p.hc.pool.signer.Hash(coinbaseTx) - if !coinbaseTx.GetSchnorrSignature().Verify(txDigestHash[:], finalKey) { - return nil, nil, nil, nil, 0, errors.New("invalid signature for coinbase digest hash " + txDigestHash.String()) - } - // Ensure the reward is valid - totalCoinbaseOut := big.NewInt(0) - for txOutIdx, txOut := range coinbaseTx.TxOut() { - coinbase := common.BytesToAddress(txOut.Address, nodeLocation) - if !coinbase.IsInQiLedgerScope() { // a coinbase tx cannot emit a conversion - return nil, nil, nil, nil, 0, fmt.Errorf("coinbase tx emits UTXO with To address not in the Qi ledger scope") - } - if _, err := coinbase.InternalAddress(); err != nil { // a coinbase tx cannot emit an ETX - return nil, nil, nil, nil, 0, fmt.Errorf("invalid coinbase address %v: %w", coinbase, err) - } - if !header.Coinbase().Equal(coinbase) { - return nil, nil, nil, nil, 0, fmt.Errorf("coinbase tx emits UTXO with To address not equal to block coinbase") - } - if txOutIdx > types.MaxOutputIndex { - return nil, nil, nil, nil, 0, fmt.Errorf("coinbase tx emits UTXO with index %d greater than max uint16", txOutIdx) - } - utxo := types.NewUtxoEntry(&txOut) - if err := statedb.CreateUTXO(coinbaseTx.Hash(), uint16(txOutIdx), utxo); err != nil { - return nil, nil, nil, nil, 0, fmt.Errorf("could not create UTXO for coinbase tx %032x: %w", coinbaseTx.Hash(), err) - } - p.logger.WithFields(log.Fields{ - "txHash": coinbaseTx.Hash().Hex(), - "txOutIdx": txOutIdx, - "denomination": txOut.Denomination, - }).Debug("Created Coinbase UTXO") - totalCoinbaseOut.Add(totalCoinbaseOut, types.Denominations[txOut.Denomination]) - } - reward := misc.CalculateReward(header) - maxCoinbaseOut := new(big.Int).Add(reward, totalFees) // TODO: Miner tip will soon no longer exist - - if totalCoinbaseOut.Cmp(maxCoinbaseOut) > 0 { - return nil, nil, nil, nil, 0, fmt.Errorf("coinbase output value of %v is higher than expected value of %v", totalCoinbaseOut, maxCoinbaseOut) - } - } else if coinbaseTx.Type() == types.QuaiTxType { - // Apply the coinbase transaction to the current state - reward := misc.CalculateReward(header) - internal, err := coinbaseTx.To().InternalAddress() - if err != nil { - return nil, nil, nil, nil, 0, fmt.Errorf("invalid coinbase address %v: %w", coinbaseTx.To(), err) - } - if coinbaseTx.Value().Cmp(reward) > 0 { - return nil, nil, nil, nil, 0, fmt.Errorf("coinbase tx value %v is greater than expected reward %v", coinbaseTx.Value(), reward) - } - // Miner tips are added during EVM tx execution, so not added in the coinbase tx (and will be removed in the future) - statedb.AddBalance(internal, coinbaseTx.Value()) - } else { - return nil, nil, nil, nil, 0, errors.New("coinbase tx type not supported") - } - } etxAvailable := false oldestIndex, err := statedb.GetOldestIndex() if err != nil { @@ -547,6 +544,14 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty return nil, nil, nil, nil, 0, fmt.Errorf("total gas used by ETXs %d is not within the range %d to %d", totalEtxGas, minimumEtxGas, maximumEtxGas) } + coinbaseReward := misc.CalculateReward(block.WorkObjectHeader()) + blockReward := new(big.Int).Add(coinbaseReward, totalFees) + // parent hash encoding for populating into the originating tx hash for coinbase + origin := block.ParentHash(nodeCtx) + origin[0] = byte(block.Location().Region()) + origin[1] = byte(block.Location().Zone()) + emittedEtxs[0] = types.NewTx(&types.ExternalTx{To: &coinbase, Value: blockReward, IsCoinbase: true, OriginatingTxHash: origin, ETXIndex: 0, Sender: coinbase}) + time4 := common.PrettyDuration(time.Since(start)) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.hc, block, statedb) @@ -575,12 +580,13 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty "prepare state time": common.PrettyDuration(timePrepare), "etx time": common.PrettyDuration(timeEtx), "tx time": common.PrettyDuration(timeTx), + "numTxs": len(block.Transactions()), }).Info("Total Tx Processing Time") return receipts, emittedEtxs, allLogs, statedb, *usedGas, nil } -func applyTransaction(msg types.Message, parent *types.WorkObject, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *types.GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, etxRLimit, etxPLimit *int, logger *log.Logger) (*types.Receipt, error) { +func applyTransaction(msg types.Message, parent *types.WorkObject, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *types.GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, etxRLimit, etxPLimit *int, logger *log.Logger) (*types.Receipt, *big.Int, error) { nodeLocation := config.Location // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) @@ -589,7 +595,7 @@ func applyTransaction(msg types.Message, parent *types.WorkObject, config *param // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) if err != nil { - return nil, err + return nil, nil, err } var ETXRCount int @@ -605,10 +611,10 @@ func applyTransaction(msg types.Message, parent *types.WorkObject, config *param } } if ETXRCount > *etxRLimit { - return nil, fmt.Errorf("tx %032x emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXRCount, *etxRLimit) + return nil, nil, fmt.Errorf("tx %032x emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXRCount, *etxRLimit) } if ETXPCount > *etxPLimit { - return nil, fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, *etxPLimit) + return nil, nil, fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, *etxPLimit) } *etxRLimit -= ETXRCount *etxPLimit -= ETXPCount @@ -641,7 +647,7 @@ func applyTransaction(msg types.Message, parent *types.WorkObject, config *param receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber receipt.TransactionIndex = uint(statedb.TxIndex()) - return receipt, err + return receipt, result.QuaiFees, err } func ValidateQiTxInputs(tx *types.Transaction, chain ChainContext, statedb *state.StateDB, currentHeader *types.WorkObject, signer types.Signer, location common.Location, chainId big.Int) (*big.Int, error) { @@ -808,7 +814,7 @@ func ValidateQiTxOutputsAndSignature(tx *types.Transaction, chain ChainContext, return nil, fmt.Errorf("tx %032x has too many ETXs to calculate required gas", tx.Hash()) } minimumFeeInQuai := new(big.Int).Mul(big.NewInt(int64(requiredGas)), currentHeader.BaseFee()) - minimumFee := misc.QuaiToQi(currentHeader, minimumFeeInQuai) + minimumFee := misc.QuaiToQi(currentHeader.WorkObjectHeader(), minimumFeeInQuai) if txFeeInQit.Cmp(minimumFee) < 0 { return nil, fmt.Errorf("tx %032x has insufficient fee for base fee, have %d want %d", tx.Hash(), txFeeInQit.Uint64(), minimumFee.Uint64()) } @@ -1025,7 +1031,7 @@ func ProcessQiTx(tx *types.Transaction, chain ChainContext, updateState bool, ch return nil, nil, fmt.Errorf("tx %032x has too many ETXs to calculate required gas", tx.Hash()) } minimumFeeInQuai := new(big.Int).Mul(big.NewInt(int64(requiredGas)), currentHeader.BaseFee()) - minimumFee := misc.QuaiToQi(currentHeader, minimumFeeInQuai) + minimumFee := misc.QuaiToQi(currentHeader.WorkObjectHeader(), minimumFeeInQuai) if txFeeInQit.Cmp(minimumFee) < 0 { return nil, nil, fmt.Errorf("tx %032x has insufficient fee for base fee, have %d want %d", tx.Hash(), txFeeInQit.Uint64(), minimumFee.Uint64()) } @@ -1033,7 +1039,7 @@ func ProcessQiTx(tx *types.Transaction, chain ChainContext, updateState bool, ch txFeeInQit.Sub(txFeeInQit, minimumFee) if conversion { // Since this transaction contains a conversion, the rest of the tx gas is given to conversion - remainingTxFeeInQuai := misc.QiToQuai(currentHeader, txFeeInQit) + remainingTxFeeInQuai := misc.QiToQuai(currentHeader.WorkObjectHeader(), txFeeInQit) // Fee is basefee * gas, so gas remaining is fee remaining / basefee remainingGas := new(big.Int).Div(remainingTxFeeInQuai, currentHeader.BaseFee()) if remainingGas.Uint64() > (currentHeader.GasLimit() / params.MinimumEtxGasDivisor) { @@ -1188,33 +1194,33 @@ func (p *StateProcessor) Apply(batch ethdb.Batch, block *types.WorkObject) ([]*t // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, parent *types.WorkObject, bc ChainContext, author *common.Address, gp *types.GasPool, statedb *state.StateDB, header *types.WorkObject, tx *types.Transaction, usedGas *uint64, cfg vm.Config, etxRLimit, etxPLimit *int, logger *log.Logger) (*types.Receipt, error) { +func ApplyTransaction(config *params.ChainConfig, parent *types.WorkObject, bc ChainContext, author *common.Address, gp *types.GasPool, statedb *state.StateDB, header *types.WorkObject, tx *types.Transaction, usedGas *uint64, cfg vm.Config, etxRLimit, etxPLimit *int, logger *log.Logger) (*types.Receipt, *big.Int, error) { nodeCtx := config.Location.Context() msg, err := tx.AsMessage(types.MakeSigner(config, header.Number(nodeCtx)), header.BaseFee()) if err != nil { - return nil, err + return nil, nil, err } if tx.Type() == types.ExternalTxType && tx.ETXSender().Location().Equal(*tx.To().Location()) { // Qi->Quai Conversion msg.SetLock(new(big.Int).Add(header.Number(nodeCtx), big.NewInt(params.ConversionLockPeriod))) primeTerminus := bc.GetHeaderByHash(header.PrimeTerminus()) if primeTerminus == nil { - return nil, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) + return nil, nil, fmt.Errorf("could not find prime terminus header %032x", header.PrimeTerminus()) } // Convert Qi to Quai - msg.SetValue(misc.QiToQuai(primeTerminus, tx.Value())) + msg.SetValue(misc.QiToQuai(primeTerminus.WorkObjectHeader(), tx.Value())) msg.SetData([]byte{}) // data is not used in conversion } // Create a new context to be used in the EVM environment - blockContext, err := NewEVMBlockContext(header, bc, author) + blockContext, err := NewEVMBlockContext(header, parent, bc, author) if err != nil { - return nil, err + return nil, nil, err } vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) if tx.Type() == types.ExternalTxType { prevZeroBal := prepareApplyETX(statedb, msg.Value(), config.Location) - receipt, err := applyTransaction(msg, parent, config, bc, author, gp, statedb, header.Number(nodeCtx), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit, logger) + receipt, quaiFees, err := applyTransaction(msg, parent, config, bc, author, gp, statedb, header.Number(nodeCtx), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit, logger) statedb.SetBalance(common.ZeroInternal(config.Location), prevZeroBal) // Reset the balance to what it previously was (currently a failed external transaction removes all the sent coins from the supply and any residual balance is gone as well) - return receipt, err + return receipt, quaiFees, err } return applyTransaction(msg, parent, config, bc, author, gp, statedb, header.Number(nodeCtx), header.Hash(), tx, usedGas, vmenv, etxRLimit, etxPLimit, logger) } @@ -1490,7 +1496,7 @@ func (p *StateProcessor) StateAtTransaction(block *types.WorkObject, txIndex int // Assemble the transaction call message and return if the requested offset msg, _ := tx.AsMessage(signer, block.BaseFee()) txContext := NewEVMTxContext(msg) - context, err := NewEVMBlockContext(block, p.hc, nil) + context, err := NewEVMBlockContext(block, parent, p.hc, nil) if err != nil { return nil, vm.BlockContext{}, nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index 2e38c57d13..2ad9b62ea9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -93,6 +93,7 @@ type ExecutionResult struct { Err error // Any error encountered during the execution(listed in core/vm/errors.go) ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) Etxs []*types.Transaction // External transactions generated from opETX + QuaiFees *big.Int // Fees that needs to be credited to the miner from the transaction ContractAddr *common.Address // Address of the contract created by the message } @@ -388,12 +389,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { effectiveTip := cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) - coinbase, err := st.evm.Context.Coinbase.InternalAddress() + _, err = st.evm.Context.Coinbase.InternalAddress() if err != nil { return nil, err } - if coinbase.IsInQuaiLedgerScope() && !st.msg.IsETX() { - st.state.AddBalance(coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) + fees := big.NewInt(0) + if !st.msg.IsETX() { + fees = new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip) } return &ExecutionResult{ @@ -401,6 +403,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { Err: vmerr, ReturnData: ret, Etxs: etxs, + QuaiFees: fees, ContractAddr: contractAddr, }, nil } diff --git a/core/tx_pool.go b/core/tx_pool.go index c6723349cb..af4c199b1c 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1152,6 +1152,8 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error { return errs } +var txPoolFullErrs uint64 + // addQiTx adds Qi transactions to the Qi pool. // The qiMu lock must be held by the caller. func (pool *TxPool) addQiTxsLocked(txs types.Transactions) []error { @@ -1198,6 +1200,13 @@ func (pool *TxPool) addQiTxsLocked(txs types.Transactions) []error { if uint64(len(pool.qiPool))+1 > pool.config.QiPoolSize { // If the pool is full, don't accept the transaction errs = append(errs, ErrTxPoolOverflow) + if txPoolFullErrs%1000 == 0 { + pool.logger.WithFields(logrus.Fields{ + "tx": tx.Hash().String(), + "fee": fee, + }).Error("Qi tx pool is full") + } + txPoolFullErrs++ continue } pool.qiPool[tx.Hash()] = txWithMinerFee @@ -1210,7 +1219,7 @@ func (pool *TxPool) addQiTxsLocked(txs types.Transactions) []error { pool.logger.WithFields(logrus.Fields{ "tx": tx.Hash().String(), "fee": fee, - }).Info("Added qi tx to pool") + }).Debug("Added qi tx to pool") qiTxGauge.Add(1) } return errs @@ -2128,7 +2137,7 @@ func (pool *TxPool) poolLimiterGoroutine() { pending += uint64(list.Len()) } pool.mu.RUnlock() - pool.logger.Infof("PoolSize: Pending: %d, Queued: %d, Number of accounts in queue: %d", pending, queued, len(pool.queue)) + pool.logger.Infof("PoolSize: Pending: %d, Queued: %d, Number of accounts in queue: %d, Qi Pool: %d", pending, queued, len(pool.queue), len(pool.qiPool)) pendingTxGauge.Set(float64(pending)) queuedGauge.Set(float64(queued)) if queued > pool.config.GlobalQueue { diff --git a/core/types/block.go b/core/types/block.go index c20de58d21..7fed527baf 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -87,32 +87,31 @@ func (c *writeCounter) Write(b []byte) (int, error) { // Header represents a block header in the Quai blockchain. type Header struct { - parentHash []common.Hash `json:"parentHash" gencodec:"required"` - uncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - coinbase common.Address `json:"miner" gencodec:"required"` - evmRoot common.Hash `json:"evmRoot" gencodec:"required"` - utxoRoot common.Hash `json:"utxoRoot" gencodec:"required"` - txHash common.Hash `json:"transactionsRoot" gencodec:"required"` - etxHash common.Hash `json:"extTransactionsRoot" gencodec:"required"` - etxSetRoot common.Hash `json:"etxSetRoot" gencodec:"required"` - etxRollupHash common.Hash `json:"extRollupRoot" gencodec:"required"` - manifestHash []common.Hash `json:"manifestHash" gencodec:"required"` - receiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - parentEntropy []*big.Int `json:"parentEntropy" gencodec:"required"` - parentDeltaS []*big.Int `json:"parentDeltaS" gencodec:"required"` - parentUncledSubDeltaS []*big.Int `json:"parentUncledSubDeltaS" gencodec:"required"` - efficiencyScore uint16 `json:"efficiencyScore" gencodec:"required"` - thresholdCount uint16 `json:"thresholdCount" gencodec:"required"` - expansionNumber uint8 `json:"expansionNumber" gencodec:"required"` - etxEligibleSlices common.Hash `json:"etxEligibleSlices" gencodec:"required"` - primeTerminus common.Hash `json:"primeTerminus" gencodec:"required"` - interlinkRootHash common.Hash `json:"interlinkRootHash" gencodec:"required"` - uncledS *big.Int `json:"uncledLogS" gencodec:"required"` - number []*big.Int `json:"number" gencodec:"required"` - gasLimit uint64 `json:"gasLimit" gencodec:"required"` - gasUsed uint64 `json:"gasUsed" gencodec:"required"` - baseFee *big.Int `json:"baseFeePerGas" gencodec:"required"` - extra []byte `json:"extraData" gencodec:"required"` + parentHash []common.Hash `json:"parentHash" gencodec:"required"` + uncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + evmRoot common.Hash `json:"evmRoot" gencodec:"required"` + utxoRoot common.Hash `json:"utxoRoot" gencodec:"required"` + txHash common.Hash `json:"transactionsRoot" gencodec:"required"` + etxHash common.Hash `json:"extTransactionsRoot" gencodec:"required"` + etxSetRoot common.Hash `json:"etxSetRoot" gencodec:"required"` + etxRollupHash common.Hash `json:"extRollupRoot" gencodec:"required"` + manifestHash []common.Hash `json:"manifestHash" gencodec:"required"` + receiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + parentEntropy []*big.Int `json:"parentEntropy" gencodec:"required"` + parentDeltaS []*big.Int `json:"parentDeltaS" gencodec:"required"` + parentUncledSubDeltaS []*big.Int `json:"parentUncledSubDeltaS" gencodec:"required"` + efficiencyScore uint16 `json:"efficiencyScore" gencodec:"required"` + thresholdCount uint16 `json:"thresholdCount" gencodec:"required"` + expansionNumber uint8 `json:"expansionNumber" gencodec:"required"` + etxEligibleSlices common.Hash `json:"etxEligibleSlices" gencodec:"required"` + primeTerminus common.Hash `json:"primeTerminus" gencodec:"required"` + interlinkRootHash common.Hash `json:"interlinkRootHash" gencodec:"required"` + uncledS *big.Int `json:"uncledLogS" gencodec:"required"` + number []*big.Int `json:"number" gencodec:"required"` + gasLimit uint64 `json:"gasLimit" gencodec:"required"` + gasUsed uint64 `json:"gasUsed" gencodec:"required"` + baseFee *big.Int `json:"baseFeePerGas" gencodec:"required"` + extra []byte `json:"extraData" gencodec:"required"` // caches hash atomic.Value @@ -220,7 +219,6 @@ func (h *Header) ProtoEncode() (*ProtoHeader, error) { protoHeader := &ProtoHeader{ UncleHash: &uncleHash, - Coinbase: h.Coinbase().Bytes(), EvmRoot: &evmRoot, UtxoRoot: &utxoRoot, TxHash: &txHash, @@ -271,9 +269,6 @@ func (h *Header) ProtoDecode(protoHeader *ProtoHeader, location common.Location) if protoHeader.UncleHash == nil { return errors.New("missing required field 'UncleHash' in Header") } - if protoHeader.Coinbase == nil { - return errors.New("missing required field 'Coinbase' in Header") - } if protoHeader.EvmRoot == nil { return errors.New("missing required field 'Root' in Header") } @@ -358,7 +353,6 @@ func (h *Header) ProtoDecode(protoHeader *ProtoHeader, location common.Location) } h.SetUncleHash(common.BytesToHash(protoHeader.GetUncleHash().GetValue())) - h.SetCoinbase(common.BytesToAddress(protoHeader.GetCoinbase(), location)) h.SetEVMRoot(common.BytesToHash(protoHeader.GetEvmRoot().GetValue())) h.SetUTXORoot(common.BytesToHash(protoHeader.GetUtxoRoot().GetValue())) h.SetTxHash(common.BytesToHash(protoHeader.GetTxHash().GetValue())) @@ -397,7 +391,6 @@ func (h *Header) RPCMarshalHeader() map[string]interface{} { "sha3Uncles": h.UncleHash(), "evmRoot": h.EVMRoot(), "utxoRoot": h.UTXORoot(), - "miner": h.Coinbase(), "extraData": hexutil.Bytes(h.Extra()), "size": hexutil.Uint64(h.Size()), "transactionsRoot": h.TxHash(), @@ -450,9 +443,6 @@ func (h *Header) ParentHash(nodeCtx int) common.Hash { func (h *Header) UncleHash() common.Hash { return h.uncleHash } -func (h *Header) Coinbase() common.Address { - return h.coinbase -} func (h *Header) EVMRoot() common.Hash { return h.evmRoot } @@ -530,11 +520,6 @@ func (h *Header) SetUncleHash(val common.Hash) { h.sealHash = atomic.Value{} // clear sealHash cache h.uncleHash = val } -func (h *Header) SetCoinbase(val common.Address) { - h.hash = atomic.Value{} // clear hash cache - h.sealHash = atomic.Value{} // clear sealHash cache - h.coinbase = val -} func (h *Header) SetEVMRoot(val common.Hash) { h.hash = atomic.Value{} // clear hash cache h.sealHash = atomic.Value{} // clear sealHash cache @@ -685,7 +670,6 @@ func (h *Header) SealEncode() *ProtoHeader { protoSealData := &ProtoHeader{ UncleHash: &uncleHash, - Coinbase: h.Coinbase().Bytes(), EvmRoot: &evmRoot, UtxoRoot: &utxoRoot, TxHash: &txHash, @@ -866,7 +850,6 @@ func CopyHeader(h *Header) *Header { } cpy.SetUncledS(h.UncledS()) cpy.SetUncleHash(h.UncleHash()) - cpy.SetCoinbase(h.Coinbase()) cpy.SetEVMRoot(h.EVMRoot()) cpy.SetUTXORoot(h.UTXORoot()) cpy.SetTxHash(h.TxHash()) diff --git a/core/types/block_test.go b/core/types/block_test.go index 75b6998f89..587ef4e431 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -35,7 +35,6 @@ func headerTestData() (*Header, common.Hash) { header := &Header{ parentHash: []common.Hash{common.HexToHash("0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0"), common.HexToHash("0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0")}, uncleHash: common.HexToHash("0x23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef1"), - coinbase: common.HexToAddress("0x9abcdef0123456789abcdef0123456789abcdef2", common.Location{0, 0}), evmRoot: common.HexToHash("0x456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef3"), utxoRoot: common.HexToHash("0x56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef4"), txHash: common.HexToHash("0x6789abcdef0123456789abcdef0123456789abcdef0123456789abcdef5"), @@ -65,7 +64,7 @@ func headerTestData() (*Header, common.Hash) { func TestHeaderHash(t *testing.T) { _, hash := headerTestData() - correctHash := common.HexToHash("0xe2ebfa9a0164ae53adaefeabc124facd012eab05d1084a65ae15d1ed17e82ef7") + correctHash := common.HexToHash("0x87fedc319b0a7c3a64136d0eba5fe861e0abd1e873a8fd10bf958a1be875f374") require.Equal(t, hash, correctHash, "Hash not equal to expected hash") } @@ -177,21 +176,6 @@ func FuzzHeaderUncleHash(f *testing.F) { fuzzHeaderHash(f, func(h *Header) common.Hash { return h.uncleHash }, func(h *Header, hash common.Hash) { h.uncleHash = hash }) } -func FuzzHeaderCoinbaseHash(f *testing.F) { - header, _ := headerTestData() - f.Add(testByte) - f.Add(header.coinbase.Bytes()) - f.Fuzz(func(t *testing.T, b []byte) { - localHeader, hash := headerTestData() - sc := common.BytesToAddress(b, common.Location{0, 0}) - if !localHeader.coinbase.Equal(sc) { - localHeader.coinbase = sc - require.NotEqual(t, localHeader.Hash(), hash, "Hash equal for Coinbase \noriginal: %v, modified: %v", header.coinbase, b) - } - - }) -} - func FuzzHeaderEvmRootHash(f *testing.F) { fuzzHeaderHash(f, func(h *Header) common.Hash { return h.evmRoot }, func(h *Header, hash common.Hash) { h.evmRoot = hash }) } diff --git a/core/types/external_tx.go b/core/types/external_tx.go index 8b0203aa77..100db06a3a 100644 --- a/core/types/external_tx.go +++ b/core/types/external_tx.go @@ -17,14 +17,11 @@ type ExternalTx struct { Data []byte AccessList AccessList Sender common.Address + IsCoinbase bool - // External transactions do not have signatures. The origin chain will - // emit an ETX, and consequently 'authorization' of this transaction comes - // from chain consensus and not from an account signature. - // - // Before an ETX can be processed at the destination chain, the ETX must - // become referencable through block manifests, thereby guaranteeing that - // the origin chain indeed confirmed emission of that ETX. + // External Transactions can be a tx generated by the EVM or a coinbase tx or a conversion tx + // External transactions do not have signatures + // for a coinbase tx the IsCoinbase returns true } // PendingEtxsRollup is Header and EtxRollups of that header that should @@ -138,6 +135,7 @@ func (tx *ExternalTx) copy() TxData { OriginatingTxHash: tx.OriginatingTxHash, ETXIndex: tx.ETXIndex, Sender: tx.Sender, + IsCoinbase: tx.IsCoinbase, // These are copied below. AccessList: make(AccessList, len(tx.AccessList)), @@ -164,19 +162,15 @@ func (tx *ExternalTx) to() *common.Address { return tx.To } func (tx *ExternalTx) etxSender() common.Address { return tx.Sender } func (tx *ExternalTx) originatingTxHash() common.Hash { return tx.OriginatingTxHash } func (tx *ExternalTx) etxIndex() uint16 { return tx.ETXIndex } +func (tx *ExternalTx) isCoinbase() bool { return tx.IsCoinbase } func (tx *ExternalTx) nonce() uint64 { panic("external TX does not have nonce") } -func (tx *ExternalTx) etxGasLimit() uint64 { panic("external TX does not have etxGasLimit") } -func (tx *ExternalTx) etxGasPrice() *big.Int { panic("external TX does not have etxGasPrice") } -func (tx *ExternalTx) etxGasTip() *big.Int { panic("external TX does not have etxGasTip") } -func (tx *ExternalTx) etxData() []byte { panic("external TX does not have etxData") } -func (tx *ExternalTx) etxAccessList() AccessList { panic("external TX does not have etxAccessList") } -func (tx *ExternalTx) txIn() TxIns { panic("external TX does not have txIn") } -func (tx *ExternalTx) txOut() TxOuts { panic("external TX does not have txOut") } +func (tx *ExternalTx) txIn() TxIns { panic("external TX does not have TxIn") } +func (tx *ExternalTx) txOut() TxOuts { panic("external TX does not have TxOut") } func (tx *ExternalTx) parentHash() *common.Hash { panic("external TX does not have parentHash") } func (tx *ExternalTx) mixHash() *common.Hash { panic("external TX does not have mixHash") } func (tx *ExternalTx) workNonce() *BlockNonce { panic("external TX does not have workNonce") } func (tx *ExternalTx) getSchnorrSignature() *schnorr.Signature { - panic("external TX does not have getSchnorrSignature") + panic("external TX does not have schnorr signature") } func (tx *ExternalTx) getEcdsaSignatureValues() (v, r, s *big.Int) { diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index f5d73e1d9c..6bc23d5e97 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -18,7 +18,6 @@ func (h Header) MarshalJSON() ([]byte, error) { var enc struct { ParentHash []common.Hash `json:"parentHash" gencodec:"required"` UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner" gencodec:"required"` EVMRoot common.Hash `json:"evmRoot" gencodec:"required"` UTXORoot common.Hash `json:"utxoRoot" gencodec:"required"` TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` @@ -61,7 +60,6 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Number[i] = (*hexutil.Big)(h.Number(i)) } enc.UncleHash = h.UncleHash() - enc.Coinbase = h.Coinbase() enc.EVMRoot = h.EVMRoot() enc.UTXORoot = h.UTXORoot() enc.TxHash = h.TxHash() @@ -89,7 +87,6 @@ func (h *Header) UnmarshalJSON(input []byte) error { var dec struct { ParentHash []common.Hash `json:"parentHash" gencodec:"required"` UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase *common.AddressBytes `json:"miner" gencodec:"required"` EVMRoot *common.Hash `json:"evmRoot" gencodec:"required"` UTXORoot *common.Hash `json:"utxoRoot" gencodec:"required"` TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` @@ -123,9 +120,6 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.UncleHash == nil { return errors.New("missing required field 'sha3Uncles' for Header") } - if dec.Coinbase == nil { - return errors.New("missing required field 'miner' for Header") - } if dec.EVMRoot == nil { return errors.New("missing required field 'evmRoot' for Header") } @@ -225,8 +219,6 @@ func (h *Header) UnmarshalJSON(input []byte) error { } h.SetUncleHash(*dec.UncleHash) - coinbase := common.Bytes20ToAddress(*dec.Coinbase, []byte{0,0}) - h.SetCoinbase(coinbase) h.SetEVMRoot(*dec.EVMRoot) h.SetUTXORoot(*dec.UTXORoot) h.SetTxHash(*dec.TxHash) @@ -289,6 +281,7 @@ func (wh *WorkObjectHeader) MarshalJSON() ([]byte, error) { MixHash common.Hash `json:"mixHash" gencoden:"required"` Time hexutil.Uint64 `json:"time" gencoden:"required"` Nonce BlockNonce `json:"nonce" gencoden:"required"` + Coinbase common.Address `json:"coinbase" gencoden:"required"` } enc.HeaderHash = wh.HeaderHash() @@ -299,6 +292,7 @@ func (wh *WorkObjectHeader) MarshalJSON() ([]byte, error) { enc.MixHash = wh.MixHash() enc.Time = hexutil.Uint64(wh.Time()) enc.Nonce = wh.Nonce() + enc.Coinbase = wh.Coinbase() raw, err := json.Marshal(&enc) return raw, err @@ -315,6 +309,7 @@ func (wh *WorkObjectHeader) UnmarshalJSON(input []byte) error { MixHash common.Hash `json:"mixHash" gencoden:"required"` Time hexutil.Uint64 `json:"time" gencoden:"required"` Nonce BlockNonce `json:"nonce" gencoden:"required"` + Coinbase common.Address `json:"coinbase" gencoden:"required"` } err := json.Unmarshal(input, &dec) @@ -334,6 +329,7 @@ func (wh *WorkObjectHeader) UnmarshalJSON(input []byte) error { wh.SetMixHash(dec.MixHash) wh.SetTime(uint64(dec.Time)) wh.SetNonce(dec.Nonce) + wh.SetCoinbase(dec.Coinbase) return nil } diff --git a/core/types/proto_block.pb.go b/core/types/proto_block.pb.go index 4163fb066b..76560f0978 100644 --- a/core/types/proto_block.pb.go +++ b/core/types/proto_block.pb.go @@ -28,34 +28,33 @@ type ProtoHeader struct { ParentHash []*common.ProtoHash `protobuf:"bytes,1,rep,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"` UncleHash *common.ProtoHash `protobuf:"bytes,2,opt,name=uncle_hash,json=uncleHash,proto3,oneof" json:"uncle_hash,omitempty"` - Coinbase []byte `protobuf:"bytes,3,opt,name=coinbase,proto3,oneof" json:"coinbase,omitempty"` - EvmRoot *common.ProtoHash `protobuf:"bytes,4,opt,name=evm_root,json=evmRoot,proto3,oneof" json:"evm_root,omitempty"` - TxHash *common.ProtoHash `protobuf:"bytes,5,opt,name=tx_hash,json=txHash,proto3,oneof" json:"tx_hash,omitempty"` - EtxHash *common.ProtoHash `protobuf:"bytes,6,opt,name=etx_hash,json=etxHash,proto3,oneof" json:"etx_hash,omitempty"` - EtxRollupHash *common.ProtoHash `protobuf:"bytes,7,opt,name=etx_rollup_hash,json=etxRollupHash,proto3,oneof" json:"etx_rollup_hash,omitempty"` - ManifestHash []*common.ProtoHash `protobuf:"bytes,8,rep,name=manifest_hash,json=manifestHash,proto3" json:"manifest_hash,omitempty"` - ReceiptHash *common.ProtoHash `protobuf:"bytes,9,opt,name=receipt_hash,json=receiptHash,proto3,oneof" json:"receipt_hash,omitempty"` - Difficulty []byte `protobuf:"bytes,10,opt,name=difficulty,proto3,oneof" json:"difficulty,omitempty"` - ParentEntropy [][]byte `protobuf:"bytes,11,rep,name=parent_entropy,json=parentEntropy,proto3" json:"parent_entropy,omitempty"` - ParentDeltaS [][]byte `protobuf:"bytes,12,rep,name=parent_delta_s,json=parentDeltaS,proto3" json:"parent_delta_s,omitempty"` - ParentUncledSubDeltaS [][]byte `protobuf:"bytes,13,rep,name=parent_uncled_sub_delta_s,json=parentUncledSubDeltaS,proto3" json:"parent_uncled_sub_delta_s,omitempty"` - UncledS []byte `protobuf:"bytes,14,opt,name=uncled_s,json=uncledS,proto3,oneof" json:"uncled_s,omitempty"` - Number [][]byte `protobuf:"bytes,15,rep,name=number,proto3" json:"number,omitempty"` - GasLimit *uint64 `protobuf:"varint,16,opt,name=gas_limit,json=gasLimit,proto3,oneof" json:"gas_limit,omitempty"` - GasUsed *uint64 `protobuf:"varint,17,opt,name=gas_used,json=gasUsed,proto3,oneof" json:"gas_used,omitempty"` - BaseFee []byte `protobuf:"bytes,18,opt,name=base_fee,json=baseFee,proto3,oneof" json:"base_fee,omitempty"` - Location *common.ProtoLocation `protobuf:"bytes,19,opt,name=location,proto3,oneof" json:"location,omitempty"` - Extra []byte `protobuf:"bytes,20,opt,name=extra,proto3,oneof" json:"extra,omitempty"` - MixHash *common.ProtoHash `protobuf:"bytes,21,opt,name=mix_hash,json=mixHash,proto3,oneof" json:"mix_hash,omitempty"` - Nonce *uint64 `protobuf:"varint,22,opt,name=nonce,proto3,oneof" json:"nonce,omitempty"` - UtxoRoot *common.ProtoHash `protobuf:"bytes,23,opt,name=utxo_root,json=utxoRoot,proto3,oneof" json:"utxo_root,omitempty"` - EtxSetRoot *common.ProtoHash `protobuf:"bytes,24,opt,name=etx_set_root,json=etxSetRoot,proto3,oneof" json:"etx_set_root,omitempty"` - EfficiencyScore *uint64 `protobuf:"varint,25,opt,name=efficiency_score,json=efficiencyScore,proto3,oneof" json:"efficiency_score,omitempty"` - ThresholdCount *uint64 `protobuf:"varint,26,opt,name=threshold_count,json=thresholdCount,proto3,oneof" json:"threshold_count,omitempty"` - ExpansionNumber *uint64 `protobuf:"varint,27,opt,name=expansion_number,json=expansionNumber,proto3,oneof" json:"expansion_number,omitempty"` - EtxEligibleSlices *common.ProtoHash `protobuf:"bytes,28,opt,name=etx_eligible_slices,json=etxEligibleSlices,proto3,oneof" json:"etx_eligible_slices,omitempty"` - PrimeTerminus *common.ProtoHash `protobuf:"bytes,29,opt,name=prime_terminus,json=primeTerminus,proto3,oneof" json:"prime_terminus,omitempty"` - InterlinkRootHash *common.ProtoHash `protobuf:"bytes,30,opt,name=interlink_root_hash,json=interlinkRootHash,proto3,oneof" json:"interlink_root_hash,omitempty"` + EvmRoot *common.ProtoHash `protobuf:"bytes,3,opt,name=evm_root,json=evmRoot,proto3,oneof" json:"evm_root,omitempty"` + TxHash *common.ProtoHash `protobuf:"bytes,4,opt,name=tx_hash,json=txHash,proto3,oneof" json:"tx_hash,omitempty"` + EtxHash *common.ProtoHash `protobuf:"bytes,5,opt,name=etx_hash,json=etxHash,proto3,oneof" json:"etx_hash,omitempty"` + EtxRollupHash *common.ProtoHash `protobuf:"bytes,6,opt,name=etx_rollup_hash,json=etxRollupHash,proto3,oneof" json:"etx_rollup_hash,omitempty"` + ManifestHash []*common.ProtoHash `protobuf:"bytes,7,rep,name=manifest_hash,json=manifestHash,proto3" json:"manifest_hash,omitempty"` + ReceiptHash *common.ProtoHash `protobuf:"bytes,8,opt,name=receipt_hash,json=receiptHash,proto3,oneof" json:"receipt_hash,omitempty"` + Difficulty []byte `protobuf:"bytes,9,opt,name=difficulty,proto3,oneof" json:"difficulty,omitempty"` + ParentEntropy [][]byte `protobuf:"bytes,10,rep,name=parent_entropy,json=parentEntropy,proto3" json:"parent_entropy,omitempty"` + ParentDeltaS [][]byte `protobuf:"bytes,11,rep,name=parent_delta_s,json=parentDeltaS,proto3" json:"parent_delta_s,omitempty"` + ParentUncledSubDeltaS [][]byte `protobuf:"bytes,12,rep,name=parent_uncled_sub_delta_s,json=parentUncledSubDeltaS,proto3" json:"parent_uncled_sub_delta_s,omitempty"` + UncledS []byte `protobuf:"bytes,13,opt,name=uncled_s,json=uncledS,proto3,oneof" json:"uncled_s,omitempty"` + Number [][]byte `protobuf:"bytes,14,rep,name=number,proto3" json:"number,omitempty"` + GasLimit *uint64 `protobuf:"varint,15,opt,name=gas_limit,json=gasLimit,proto3,oneof" json:"gas_limit,omitempty"` + GasUsed *uint64 `protobuf:"varint,16,opt,name=gas_used,json=gasUsed,proto3,oneof" json:"gas_used,omitempty"` + BaseFee []byte `protobuf:"bytes,17,opt,name=base_fee,json=baseFee,proto3,oneof" json:"base_fee,omitempty"` + Location *common.ProtoLocation `protobuf:"bytes,18,opt,name=location,proto3,oneof" json:"location,omitempty"` + Extra []byte `protobuf:"bytes,19,opt,name=extra,proto3,oneof" json:"extra,omitempty"` + MixHash *common.ProtoHash `protobuf:"bytes,20,opt,name=mix_hash,json=mixHash,proto3,oneof" json:"mix_hash,omitempty"` + Nonce *uint64 `protobuf:"varint,21,opt,name=nonce,proto3,oneof" json:"nonce,omitempty"` + UtxoRoot *common.ProtoHash `protobuf:"bytes,22,opt,name=utxo_root,json=utxoRoot,proto3,oneof" json:"utxo_root,omitempty"` + EtxSetRoot *common.ProtoHash `protobuf:"bytes,23,opt,name=etx_set_root,json=etxSetRoot,proto3,oneof" json:"etx_set_root,omitempty"` + EfficiencyScore *uint64 `protobuf:"varint,24,opt,name=efficiency_score,json=efficiencyScore,proto3,oneof" json:"efficiency_score,omitempty"` + ThresholdCount *uint64 `protobuf:"varint,25,opt,name=threshold_count,json=thresholdCount,proto3,oneof" json:"threshold_count,omitempty"` + ExpansionNumber *uint64 `protobuf:"varint,26,opt,name=expansion_number,json=expansionNumber,proto3,oneof" json:"expansion_number,omitempty"` + EtxEligibleSlices *common.ProtoHash `protobuf:"bytes,27,opt,name=etx_eligible_slices,json=etxEligibleSlices,proto3,oneof" json:"etx_eligible_slices,omitempty"` + PrimeTerminus *common.ProtoHash `protobuf:"bytes,28,opt,name=prime_terminus,json=primeTerminus,proto3,oneof" json:"prime_terminus,omitempty"` + InterlinkRootHash *common.ProtoHash `protobuf:"bytes,29,opt,name=interlink_root_hash,json=interlinkRootHash,proto3,oneof" json:"interlink_root_hash,omitempty"` } func (x *ProtoHeader) Reset() { @@ -104,13 +103,6 @@ func (x *ProtoHeader) GetUncleHash() *common.ProtoHash { return nil } -func (x *ProtoHeader) GetCoinbase() []byte { - if x != nil { - return x.Coinbase - } - return nil -} - func (x *ProtoHeader) GetEvmRoot() *common.ProtoHash { if x != nil { return x.EvmRoot @@ -327,6 +319,7 @@ type ProtoTransaction struct { ParentHash *common.ProtoHash `protobuf:"bytes,20,opt,name=parent_hash,json=parentHash,proto3,oneof" json:"parent_hash,omitempty"` MixHash *common.ProtoHash `protobuf:"bytes,21,opt,name=mix_hash,json=mixHash,proto3,oneof" json:"mix_hash,omitempty"` WorkNonce *uint64 `protobuf:"varint,22,opt,name=work_nonce,json=workNonce,proto3,oneof" json:"work_nonce,omitempty"` + IsCoinbase *bool `protobuf:"varint,23,opt,name=is_coinbase,json=isCoinbase,proto3,oneof" json:"is_coinbase,omitempty"` } func (x *ProtoTransaction) Reset() { @@ -515,6 +508,13 @@ func (x *ProtoTransaction) GetWorkNonce() uint64 { return 0 } +func (x *ProtoTransaction) GetIsCoinbase() bool { + if x != nil && x.IsCoinbase != nil { + return *x.IsCoinbase + } + return false +} + type ProtoTransactions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -717,6 +717,7 @@ type ProtoWorkObjectHeader struct { Location *common.ProtoLocation `protobuf:"bytes,7,opt,name=location,proto3,oneof" json:"location,omitempty"` MixHash *common.ProtoHash `protobuf:"bytes,8,opt,name=mix_hash,json=mixHash,proto3,oneof" json:"mix_hash,omitempty"` Time *uint64 `protobuf:"varint,9,opt,name=time,proto3,oneof" json:"time,omitempty"` + Coinbase *common.ProtoAddress `protobuf:"bytes,10,opt,name=coinbase,proto3,oneof" json:"coinbase,omitempty"` } func (x *ProtoWorkObjectHeader) Reset() { @@ -814,6 +815,13 @@ func (x *ProtoWorkObjectHeader) GetTime() uint64 { return 0 } +func (x *ProtoWorkObjectHeader) GetCoinbase() *common.ProtoAddress { + if x != nil { + return x.Coinbase + } + return nil +} + type ProtoWorkObjectHeaders struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2204,471 +2212,476 @@ var file_core_types_proto_block_proto_rawDesc = []byte{ 0x74, 0x6f, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x8f, 0x0e, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x22, 0xe1, 0x0d, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x35, 0x0a, 0x0a, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x09, 0x75, - 0x6e, 0x63, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x63, - 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, - 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, - 0x65, 0x76, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, - 0x68, 0x48, 0x02, 0x52, 0x07, 0x65, 0x76, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x12, - 0x2f, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, - 0x61, 0x73, 0x68, 0x48, 0x03, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, - 0x12, 0x31, 0x0a, 0x08, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x04, 0x52, 0x07, 0x65, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, - 0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x0f, 0x65, 0x74, 0x78, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, - 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, - 0x05, 0x52, 0x0d, 0x65, 0x74, 0x78, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x48, 0x61, 0x73, 0x68, - 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, - 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x39, 0x0a, 0x0c, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x48, 0x61, 0x73, 0x68, 0x48, 0x06, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, - 0x75, 0x6c, 0x74, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x07, 0x52, 0x0a, 0x64, 0x69, - 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x0b, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x6f, - 0x70, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x6c, - 0x74, 0x61, 0x5f, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x53, 0x12, 0x38, 0x0a, 0x19, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x5f, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x64, 0x65, - 0x6c, 0x74, 0x61, 0x5f, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x53, 0x75, 0x62, 0x44, 0x65, 0x6c, 0x74, - 0x61, 0x53, 0x12, 0x1e, 0x0a, 0x08, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0c, 0x48, 0x08, 0x52, 0x07, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x53, 0x88, - 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x09, 0x67, 0x61, - 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x48, 0x09, 0x52, - 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, - 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x48, 0x0a, - 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x0b, - 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x0c, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0c, 0x48, 0x0d, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x88, 0x01, 0x01, 0x12, - 0x31, 0x0a, 0x08, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x15, 0x20, 0x01, 0x28, + 0x6e, 0x63, 0x6c, 0x65, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, 0x65, + 0x76, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, + 0x48, 0x01, 0x52, 0x07, 0x65, 0x76, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2f, + 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, + 0x73, 0x68, 0x48, 0x02, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, + 0x31, 0x0a, 0x08, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x48, 0x61, 0x73, 0x68, 0x48, 0x0e, 0x52, 0x07, 0x6d, 0x69, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, - 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, - 0x04, 0x48, 0x0f, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, - 0x09, 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, + 0x48, 0x61, 0x73, 0x68, 0x48, 0x03, 0x52, 0x07, 0x65, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, + 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x0f, 0x65, 0x74, 0x78, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x04, + 0x52, 0x0d, 0x65, 0x74, 0x78, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x48, 0x61, 0x73, 0x68, 0x88, + 0x01, 0x01, 0x12, 0x36, 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0c, 0x6d, 0x61, + 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x39, 0x0a, 0x0c, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, - 0x61, 0x73, 0x68, 0x48, 0x10, 0x52, 0x08, 0x75, 0x74, 0x78, 0x6f, 0x52, 0x6f, 0x6f, 0x74, 0x88, - 0x01, 0x01, 0x12, 0x38, 0x0a, 0x0c, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x6f, - 0x6f, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x11, 0x52, 0x0a, 0x65, - 0x74, 0x78, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, - 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, - 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x48, 0x12, 0x52, 0x0f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, - 0x65, 0x6e, 0x63, 0x79, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, - 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x1a, 0x20, 0x01, 0x28, 0x04, 0x48, 0x13, 0x52, 0x0e, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, - 0x6c, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x65, 0x78, - 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x1b, - 0x20, 0x01, 0x28, 0x04, 0x48, 0x14, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x13, 0x65, 0x74, - 0x78, 0x5f, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, - 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x15, 0x52, 0x11, 0x65, 0x74, - 0x78, 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x88, - 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x0e, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x75, 0x73, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x16, 0x52, - 0x0d, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x88, 0x01, - 0x01, 0x12, 0x46, 0x0a, 0x13, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x72, - 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, - 0x68, 0x48, 0x17, 0x52, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x6f, - 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x75, 0x6e, - 0x63, 0x6c, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x69, - 0x6e, 0x62, 0x61, 0x73, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x65, 0x76, 0x6d, 0x5f, 0x72, 0x6f, - 0x6f, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0b, - 0x0a, 0x09, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x12, 0x0a, 0x10, 0x5f, - 0x65, 0x74, 0x78, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, - 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, - 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x42, - 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x42, 0x0c, 0x0a, 0x0a, - 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x67, - 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x62, 0x61, 0x73, 0x65, - 0x5f, 0x66, 0x65, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x42, 0x0b, 0x0a, 0x09, 0x5f, - 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6e, 0x6f, 0x6e, - 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x72, 0x6f, 0x6f, 0x74, - 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x6f, 0x6f, - 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x79, - 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, - 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, - 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x42, - 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, - 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x70, 0x72, 0x69, 0x6d, - 0x65, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x22, 0xb3, 0x08, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, - 0x12, 0x13, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x02, - 0x74, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x48, 0x02, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, - 0x12, 0x19, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, - 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x67, - 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x48, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x88, - 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x05, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x06, 0x52, - 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0b, 0x67, - 0x61, 0x73, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x07, 0x52, 0x09, 0x67, 0x61, 0x73, 0x46, 0x65, 0x65, 0x43, 0x61, 0x70, 0x88, 0x01, 0x01, - 0x12, 0x23, 0x0a, 0x0b, 0x67, 0x61, 0x73, 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, 0x70, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x08, 0x52, 0x09, 0x67, 0x61, 0x73, 0x54, 0x69, 0x70, 0x43, - 0x61, 0x70, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, - 0x73, 0x74, 0x48, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x76, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x0a, - 0x52, 0x01, 0x76, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, - 0x0c, 0x48, 0x0b, 0x52, 0x01, 0x72, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x73, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x0c, 0x48, 0x0c, 0x52, 0x01, 0x73, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x13, - 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x0d, 0x52, 0x11, - 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, 0x73, - 0x68, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0e, 0x52, 0x08, 0x65, 0x74, 0x78, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x73, - 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x73, 0x48, 0x0f, 0x52, 0x05, 0x74, 0x78, 0x49, - 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x73, - 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x4f, 0x75, 0x74, 0x73, 0x48, 0x10, 0x52, 0x06, 0x74, 0x78, - 0x4f, 0x75, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x11, 0x52, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x65, 0x74, - 0x78, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x12, - 0x52, 0x09, 0x65, 0x74, 0x78, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x37, - 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x13, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x69, 0x78, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x14, 0x52, 0x07, - 0x6d, 0x69, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x77, 0x6f, - 0x72, 0x6b, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x04, 0x48, 0x15, - 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x07, - 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x74, 0x6f, 0x42, 0x08, - 0x0a, 0x06, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x67, 0x61, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, - 0x61, 0x74, 0x61, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, - 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, - 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, 0x70, - 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, - 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x76, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x72, 0x42, 0x04, 0x0a, 0x02, - 0x5f, 0x73, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, - 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x74, 0x78, 0x5f, - 0x69, 0x6e, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x73, 0x42, - 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x0d, 0x0a, - 0x0b, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x42, 0x0e, 0x0a, 0x0c, - 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0b, 0x0a, 0x09, - 0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x77, 0x6f, - 0x72, 0x6b, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x50, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, 0x0a, - 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3c, 0x0a, 0x0c, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x68, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, - 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3e, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x6d, 0x61, 0x6e, - 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, - 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0d, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x52, 0x0c, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x22, 0x8e, 0x04, 0x0a, 0x15, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x0b, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x48, 0x61, 0x73, 0x68, 0x48, 0x01, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, - 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x88, - 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, - 0x75, 0x6c, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x04, 0x52, 0x06, 0x74, - 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x48, 0x05, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x06, 0x52, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, 0x6d, - 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x61, 0x73, 0x68, 0x48, 0x05, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, + 0x6c, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x06, 0x52, 0x0a, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, + 0x61, 0x5f, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x53, 0x12, 0x38, 0x0a, 0x19, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x5f, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x5f, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x55, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x53, 0x75, 0x62, 0x44, 0x65, 0x6c, 0x74, 0x61, + 0x53, 0x12, 0x1e, 0x0a, 0x08, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x0c, 0x48, 0x07, 0x52, 0x07, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x53, 0x88, 0x01, + 0x01, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x09, 0x67, 0x61, 0x73, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x08, + 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x67, + 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x48, 0x09, 0x52, + 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x62, + 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x0a, 0x52, + 0x07, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x0b, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x0c, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x88, 0x01, 0x01, 0x12, 0x31, + 0x0a, 0x08, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, + 0x61, 0x73, 0x68, 0x48, 0x0d, 0x52, 0x07, 0x6d, 0x69, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, + 0x01, 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, + 0x48, 0x0e, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x09, + 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, + 0x73, 0x68, 0x48, 0x0f, 0x52, 0x08, 0x75, 0x74, 0x78, 0x6f, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, + 0x01, 0x12, 0x38, 0x0a, 0x0c, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x6f, 0x6f, + 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x10, 0x52, 0x0a, 0x65, 0x74, + 0x78, 0x53, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x65, + 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x04, 0x48, 0x11, 0x52, 0x0f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, + 0x6e, 0x63, 0x79, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x74, + 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x19, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x12, 0x52, 0x0e, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x65, 0x78, 0x70, + 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x04, 0x48, 0x13, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x13, 0x65, 0x74, 0x78, + 0x5f, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, + 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x14, 0x52, 0x11, 0x65, 0x74, 0x78, + 0x45, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x88, 0x01, + 0x01, 0x12, 0x3d, 0x0a, 0x0e, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, + 0x6e, 0x75, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x15, 0x52, 0x0d, + 0x70, 0x72, 0x69, 0x6d, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x88, 0x01, 0x01, + 0x12, 0x46, 0x0a, 0x13, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x6f, + 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, - 0x48, 0x07, 0x52, 0x07, 0x6d, 0x69, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x17, - 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x04, - 0x74, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, - 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, - 0x06, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x55, 0x0a, 0x16, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x77, 0x6f, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x09, 0x77, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x73, 0x22, 0xe9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, - 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x01, 0x52, 0x0c, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, - 0x06, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x48, 0x02, 0x52, 0x06, - 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x10, 0x65, 0x78, 0x74, - 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x03, 0x52, - 0x0f, 0x65, 0x78, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x04, 0x52, 0x08, 0x6d, - 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x43, 0x0a, 0x10, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x48, 0x05, 0x52, 0x0f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x88, 0x01, 0x01, 0x42, - 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, - 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, - 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0xda, 0x01, - 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x3e, 0x0a, 0x09, 0x77, 0x6f, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, + 0x48, 0x16, 0x52, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x6f, 0x6f, + 0x74, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x75, 0x6e, 0x63, + 0x6c, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x65, 0x76, 0x6d, 0x5f, + 0x72, 0x6f, 0x6f, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x12, 0x0a, + 0x10, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, + 0x79, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x75, 0x6e, 0x63, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x42, 0x0c, + 0x0a, 0x0a, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x0b, 0x0a, 0x09, + 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x62, 0x61, + 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x42, 0x0b, 0x0a, + 0x09, 0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6e, + 0x6f, 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x72, 0x6f, + 0x6f, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, + 0x63, 0x79, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x74, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x13, 0x0a, 0x11, + 0x5f, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, + 0x6c, 0x65, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x70, 0x72, + 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x42, 0x16, 0x0a, 0x14, + 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x22, 0xe9, 0x08, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, + 0x01, 0x01, 0x12, 0x13, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, + 0x52, 0x02, 0x74, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x48, 0x02, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x88, + 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x48, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, + 0x03, 0x67, 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x48, 0x04, 0x52, 0x03, 0x67, 0x61, + 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x05, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, + 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, + 0x06, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, + 0x0b, 0x67, 0x61, 0x73, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x07, 0x52, 0x09, 0x67, 0x61, 0x73, 0x46, 0x65, 0x65, 0x43, 0x61, 0x70, 0x88, + 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0b, 0x67, 0x61, 0x73, 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, + 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x08, 0x52, 0x09, 0x67, 0x61, 0x73, 0x54, 0x69, + 0x70, 0x43, 0x61, 0x70, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x4c, 0x69, 0x73, 0x74, 0x48, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x76, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x0a, 0x52, 0x01, 0x76, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x72, 0x18, 0x0c, 0x20, + 0x01, 0x28, 0x0c, 0x48, 0x0b, 0x52, 0x01, 0x72, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x73, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x0c, 0x52, 0x01, 0x73, 0x88, 0x01, 0x01, 0x12, 0x46, + 0x0a, 0x13, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x0d, + 0x52, 0x11, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, + 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x74, 0x78, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0e, 0x52, 0x08, 0x65, 0x74, 0x78, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x78, 0x5f, 0x69, + 0x6e, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x73, 0x48, 0x0f, 0x52, 0x05, 0x74, + 0x78, 0x49, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6f, 0x75, + 0x74, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x4f, 0x75, 0x74, 0x73, 0x48, 0x10, 0x52, 0x06, + 0x74, 0x78, 0x4f, 0x75, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x11, 0x52, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, + 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x12, 0x52, 0x09, 0x65, 0x74, 0x78, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, + 0x12, 0x37, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x13, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x69, 0x78, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x14, + 0x52, 0x07, 0x6d, 0x69, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, + 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x04, + 0x48, 0x15, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, + 0x12, 0x24, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x08, 0x48, 0x16, 0x52, 0x0a, 0x69, 0x73, 0x43, 0x6f, 0x69, 0x6e, 0x62, + 0x61, 0x73, 0x65, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, + 0x05, 0x0a, 0x03, 0x5f, 0x74, 0x6f, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x67, + 0x61, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0b, 0x0a, 0x09, 0x5f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x67, 0x61, 0x73, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x63, 0x61, 0x70, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x67, 0x61, 0x73, + 0x5f, 0x74, 0x69, 0x70, 0x5f, 0x63, 0x61, 0x70, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x76, 0x42, 0x04, + 0x0a, 0x02, 0x5f, 0x72, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x73, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, + 0x74, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x73, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, + 0x22, 0x50, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x3c, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x22, 0x3e, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x22, 0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x75, + 0x70, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, + 0x70, 0x6c, 0x65, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, + 0x73, 0x22, 0xd2, 0x04, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0b, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, + 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, + 0x68, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x01, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x64, 0x69, + 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, + 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, + 0x2f, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, + 0x61, 0x73, 0x68, 0x48, 0x04, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, + 0x12, 0x19, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x48, + 0x05, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x06, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x07, 0x52, 0x07, 0x6d, 0x69, 0x78, 0x48, + 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, + 0x35, 0x0a, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, + 0x61, 0x73, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, + 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x69, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, + 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x55, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, + 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x12, 0x3b, 0x0a, 0x0a, 0x77, 0x6f, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x48, 0x00, 0x52, 0x08, 0x77, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, - 0x01, 0x12, 0x38, 0x0a, 0x07, 0x77, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x48, 0x01, - 0x52, 0x06, 0x77, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x02, 0x74, - 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x02, 0x52, 0x02, 0x74, 0x78, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x77, 0x6f, - 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x77, 0x6f, 0x5f, 0x62, - 0x6f, 0x64, 0x79, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x74, 0x78, 0x22, 0x4d, 0x0a, 0x10, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x39, - 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x77, 0x6f, - 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x68, 0x0a, 0x18, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x56, 0x69, 0x65, 0x77, 0x12, 0x3c, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, - 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x22, 0x69, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x69, 0x65, 0x77, - 0x12, 0x3c, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, - 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0e, - 0x0a, 0x0c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x68, - 0x0a, 0x18, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x3c, 0x0a, 0x0b, 0x77, 0x6f, - 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, - 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x77, 0x6f, 0x72, - 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x60, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x22, 0xdf, 0x02, 0x0a, 0x16, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2f, 0x0a, 0x14, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x6f, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x72, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, - 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x47, - 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, - 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, - 0x6f, 0x67, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, - 0x6f, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x04, 0x65, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x04, 0x65, 0x74, 0x78, - 0x73, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x22, 0x54, 0x0a, 0x17, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x46, 0x6f, 0x72, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, - 0x70, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x46, 0x6f, - 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, - 0x74, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x46, - 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x06, 0x74, 0x6f, 0x70, - 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x6f, - 0x70, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x44, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x4c, 0x6f, 0x67, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, - 0x2d, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x46, 0x6f, - 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0x88, - 0x01, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x02, 0x77, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x65, 0x72, 0x52, 0x09, 0x77, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0xe9, 0x03, + 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2f, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x41, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x01, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x06, 0x75, 0x6e, 0x63, + 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x48, 0x02, 0x52, 0x06, 0x75, 0x6e, 0x63, 0x6c, + 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x10, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x03, 0x52, 0x0f, 0x65, 0x78, 0x74, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, + 0x35, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, + 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x48, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, + 0x65, 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x43, 0x0a, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, + 0x69, 0x6e, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x48, 0x05, 0x52, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, + 0x6e, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x75, 0x6e, 0x63, 0x6c, + 0x65, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x61, 0x6e, 0x69, + 0x66, 0x65, 0x73, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, + 0x6e, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0xda, 0x01, 0x0a, 0x0f, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3e, 0x0a, + 0x09, 0x77, 0x6f, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, + 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, + 0x52, 0x08, 0x77, 0x6f, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, + 0x07, 0x77, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x48, 0x01, 0x52, 0x06, 0x77, 0x6f, + 0x42, 0x6f, 0x64, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x02, 0x74, 0x78, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x02, 0x52, 0x02, + 0x74, 0x78, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x77, 0x6f, 0x5f, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x77, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x42, + 0x05, 0x0a, 0x03, 0x5f, 0x74, 0x78, 0x22, 0x4d, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, + 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x77, 0x6f, + 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, + 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x68, 0x0a, 0x18, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, + 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x69, 0x65, + 0x77, 0x12, 0x3c, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, + 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x42, + 0x0e, 0x0a, 0x0c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, + 0x69, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x56, 0x69, 0x65, 0x77, 0x12, 0x3c, 0x0a, 0x0b, + 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, - 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x02, 0x77, 0x6f, 0x88, - 0x01, 0x01, 0x12, 0x32, 0x0a, 0x07, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x48, 0x01, 0x52, 0x07, 0x74, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x69, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x77, 0x6f, 0x42, 0x0a, 0x0a, - 0x08, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x22, 0x76, 0x0a, 0x0c, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x12, 0x32, 0x0a, 0x0b, 0x64, 0x6f, 0x6d, - 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x77, 0x6f, 0x72, + 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x77, + 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x68, 0x0a, 0x18, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x68, 0x61, + 0x72, 0x65, 0x56, 0x69, 0x65, 0x77, 0x12, 0x3c, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x22, 0x60, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4b, 0x65, 0x79, 0x22, 0xdf, 0x02, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x12, 0x2f, 0x0a, 0x14, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x11, 0x70, 0x6f, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x73, 0x55, 0x73, + 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3f, + 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x2e, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x73, 0x46, + 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, + 0x2c, 0x0a, 0x04, 0x65, 0x74, 0x78, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x04, 0x65, 0x74, 0x78, 0x73, 0x12, 0x19, 0x0a, + 0x08, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x07, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x22, 0x54, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x73, 0x22, 0x83, + 0x01, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x46, 0x6f, 0x72, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x44, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, + 0x73, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x6c, + 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x6f, 0x67, 0x46, 0x6f, 0x72, 0x53, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x2b, 0x0a, 0x02, 0x77, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x02, 0x77, 0x6f, 0x88, 0x01, 0x01, 0x12, 0x32, + 0x0a, 0x07, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x69, 0x48, 0x01, 0x52, 0x07, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x88, + 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x77, 0x6f, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x74, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x22, 0x76, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x65, + 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x12, 0x32, 0x0a, 0x0b, 0x64, 0x6f, 0x6d, 0x5f, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x64, + 0x6f, 0x6d, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x12, 0x32, 0x0a, 0x0b, 0x73, 0x75, 0x62, + 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, - 0x68, 0x52, 0x0a, 0x64, 0x6f, 0x6d, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x12, 0x32, 0x0a, - 0x0b, 0x73, 0x75, 0x62, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x48, 0x61, 0x73, 0x68, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, - 0x69, 0x22, 0x40, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x74, 0x78, 0x53, 0x65, 0x74, - 0x12, 0x22, 0x0a, 0x0a, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x09, 0x65, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, - 0x68, 0x65, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x45, 0x74, 0x78, 0x73, 0x12, 0x33, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, - 0x04, 0x65, 0x74, 0x78, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x01, 0x52, 0x04, 0x65, 0x74, 0x78, 0x73, 0x88, 0x01, 0x01, - 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x5f, - 0x65, 0x74, 0x78, 0x73, 0x22, 0xa8, 0x01, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x74, 0x78, 0x73, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x12, - 0x33, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, - 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x0b, 0x65, 0x74, 0x78, 0x73, 0x5f, 0x72, 0x6f, 0x6c, - 0x6c, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x48, 0x01, 0x52, 0x0a, 0x65, 0x74, 0x78, 0x73, 0x52, 0x6f, 0x6c, 0x6c, 0x75, - 0x70, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, - 0x0e, 0x0a, 0x0c, 0x5f, 0x65, 0x74, 0x78, 0x73, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, - 0x35, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x73, 0x12, 0x27, 0x0a, - 0x06, 0x74, 0x78, 0x5f, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x52, - 0x05, 0x74, 0x78, 0x49, 0x6e, 0x73, 0x22, 0x39, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, - 0x78, 0x4f, 0x75, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x4f, 0x75, 0x74, 0x52, 0x06, 0x74, 0x78, 0x4f, 0x75, 0x74, - 0x73, 0x22, 0x95, 0x01, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x12, - 0x47, 0x0a, 0x12, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x6c, + 0x68, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x22, 0x40, 0x0a, + 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x45, 0x74, 0x78, 0x53, 0x65, 0x74, 0x12, 0x22, 0x0a, 0x0a, + 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x09, 0x65, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x88, 0x01, 0x01, + 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x65, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, + 0x8e, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x45, 0x74, 0x78, 0x73, 0x12, 0x33, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x06, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x04, 0x65, 0x74, 0x78, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x48, 0x01, 0x52, 0x04, 0x65, 0x74, 0x78, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, + 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x74, 0x78, 0x73, + 0x22, 0xa8, 0x01, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x45, 0x74, 0x78, 0x73, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x12, 0x33, 0x0a, 0x06, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x57, 0x6f, 0x72, 0x6b, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, + 0x12, 0x3e, 0x0a, 0x0b, 0x65, 0x74, 0x78, 0x73, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, + 0x01, 0x52, 0x0a, 0x65, 0x74, 0x78, 0x73, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x88, 0x01, 0x01, + 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, + 0x65, 0x74, 0x78, 0x73, 0x5f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, 0x35, 0x0a, 0x0a, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x73, 0x12, 0x27, 0x0a, 0x06, 0x74, 0x78, 0x5f, + 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x52, 0x05, 0x74, 0x78, 0x49, + 0x6e, 0x73, 0x22, 0x39, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x4f, 0x75, 0x74, + 0x73, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x6f, 0x75, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x54, 0x78, 0x4f, 0x75, 0x74, 0x52, 0x06, 0x74, 0x78, 0x4f, 0x75, 0x74, 0x73, 0x22, 0x95, 0x01, + 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x49, 0x6e, 0x12, 0x47, 0x0a, 0x12, 0x70, + 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x88, + 0x01, 0x01, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, + 0x6f, 0x75, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x75, + 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x88, + 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x48, 0x01, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, + 0x05, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x22, 0x93, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, 0x4f, 0x75, 0x74, 0x12, + 0x27, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x6c, 0x6f, 0x63, 0x6b, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x04, 0x6c, 0x6f, 0x63, 0x6b, 0x88, 0x01, 0x01, + 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x07, 0x0a, + 0x05, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xb2, 0x01, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x44, 0x65, 0x6e, 0x6f, 0x6d, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, + 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x48, 0x01, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x88, 0x01, 0x01, 0x12, 0x27, + 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x64, + 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc6, 0x01, 0x0a, 0x15, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x75, 0x74, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x75, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x73, 0x1a, 0x61, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x44, 0x65, 0x6e, + 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0xae, 0x01, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x3f, 0x0a, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4f, 0x75, 0x74, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x06, 0x70, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, - 0x6f, 0x75, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0a, 0x0a, - 0x08, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x22, 0x69, 0x0a, 0x0d, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x88, 0x01, - 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x22, 0x93, 0x01, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x78, - 0x4f, 0x75, 0x74, 0x12, 0x27, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x6e, - 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x6c, - 0x6f, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x02, 0x52, 0x04, 0x6c, 0x6f, 0x63, - 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xb2, 0x01, 0x0a, 0x1c, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, 0x64, 0x44, - 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x04, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x48, 0x61, 0x73, 0x68, 0x48, 0x00, 0x52, 0x04, - 0x68, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x88, - 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0c, 0x64, 0x65, 0x6e, 0x6f, - 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, - 0x68, 0x61, 0x73, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0f, - 0x0a, 0x0d, 0x5f, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0xc6, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x4a, 0x0a, 0x0a, 0x6f, 0x75, 0x74, - 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x1a, 0x61, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, - 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x6e, - 0x64, 0x44, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xae, 0x01, 0x0a, 0x11, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x3f, - 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x75, 0x74, - 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x4d, 0x61, 0x70, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, - 0x58, 0x0a, 0x0c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x6e, 0x74, - 0x2d, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x69, 0x65, 0x73, 0x2f, 0x67, 0x6f, 0x2d, 0x71, - 0x75, 0x61, 0x69, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x73, 0x4d, 0x61, 0x70, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x58, 0x0a, 0x0c, 0x45, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x32, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x61, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x69, 0x65, 0x73, 0x2f, 0x67, 0x6f, 0x2d, 0x71, 0x75, 0x61, 0x69, 0x2f, + 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -2721,8 +2734,8 @@ var file_core_types_proto_block_proto_goTypes = []interface{}{ nil, // 33: block.ProtoOutPointsMap.EntriesEntry (*common.ProtoHash)(nil), // 34: common.ProtoHash (*common.ProtoLocation)(nil), // 35: common.ProtoLocation - (*common.ProtoHashes)(nil), // 36: common.ProtoHashes - (*common.ProtoAddress)(nil), // 37: common.ProtoAddress + (*common.ProtoAddress)(nil), // 36: common.ProtoAddress + (*common.ProtoHashes)(nil), // 37: common.ProtoHashes } var file_core_types_proto_block_proto_depIdxs = []int32{ 34, // 0: block.ProtoHeader.parent_hash:type_name -> common.ProtoHash @@ -2755,51 +2768,52 @@ var file_core_types_proto_block_proto_depIdxs = []int32{ 34, // 27: block.ProtoWorkObjectHeader.tx_hash:type_name -> common.ProtoHash 35, // 28: block.ProtoWorkObjectHeader.location:type_name -> common.ProtoLocation 34, // 29: block.ProtoWorkObjectHeader.mix_hash:type_name -> common.ProtoHash - 6, // 30: block.ProtoWorkObjectHeaders.wo_headers:type_name -> block.ProtoWorkObjectHeader - 0, // 31: block.ProtoWorkObjectBody.header:type_name -> block.ProtoHeader - 2, // 32: block.ProtoWorkObjectBody.transactions:type_name -> block.ProtoTransactions - 7, // 33: block.ProtoWorkObjectBody.uncles:type_name -> block.ProtoWorkObjectHeaders - 2, // 34: block.ProtoWorkObjectBody.ext_transactions:type_name -> block.ProtoTransactions - 4, // 35: block.ProtoWorkObjectBody.manifest:type_name -> block.ProtoManifest - 36, // 36: block.ProtoWorkObjectBody.interlink_hashes:type_name -> common.ProtoHashes - 6, // 37: block.ProtoWorkObject.wo_header:type_name -> block.ProtoWorkObjectHeader - 8, // 38: block.ProtoWorkObject.wo_body:type_name -> block.ProtoWorkObjectBody - 1, // 39: block.ProtoWorkObject.tx:type_name -> block.ProtoTransaction - 9, // 40: block.ProtoWorkObjects.work_objects:type_name -> block.ProtoWorkObject - 9, // 41: block.ProtoWorkObjectBlockView.work_object:type_name -> block.ProtoWorkObject - 9, // 42: block.ProtoWorkObjectHeaderView.work_object:type_name -> block.ProtoWorkObject - 9, // 43: block.ProtoWorkObjectShareView.work_object:type_name -> block.ProtoWorkObject - 34, // 44: block.ProtoAccessTuple.storage_key:type_name -> common.ProtoHash - 34, // 45: block.ProtoReceiptForStorage.tx_hash:type_name -> common.ProtoHash - 37, // 46: block.ProtoReceiptForStorage.contract_address:type_name -> common.ProtoAddress - 18, // 47: block.ProtoReceiptForStorage.logs:type_name -> block.ProtoLogsForStorage - 2, // 48: block.ProtoReceiptForStorage.etxs:type_name -> block.ProtoTransactions - 15, // 49: block.ProtoReceiptsForStorage.receipts:type_name -> block.ProtoReceiptForStorage - 37, // 50: block.ProtoLogForStorage.address:type_name -> common.ProtoAddress - 34, // 51: block.ProtoLogForStorage.topics:type_name -> common.ProtoHash - 17, // 52: block.ProtoLogsForStorage.logs:type_name -> block.ProtoLogForStorage - 9, // 53: block.ProtoPendingHeader.wo:type_name -> block.ProtoWorkObject - 20, // 54: block.ProtoPendingHeader.termini:type_name -> block.ProtoTermini - 34, // 55: block.ProtoTermini.dom_termini:type_name -> common.ProtoHash - 34, // 56: block.ProtoTermini.sub_termini:type_name -> common.ProtoHash - 9, // 57: block.ProtoPendingEtxs.header:type_name -> block.ProtoWorkObject - 2, // 58: block.ProtoPendingEtxs.etxs:type_name -> block.ProtoTransactions - 9, // 59: block.ProtoPendingEtxsRollup.header:type_name -> block.ProtoWorkObject - 2, // 60: block.ProtoPendingEtxsRollup.etxs_rollup:type_name -> block.ProtoTransactions - 26, // 61: block.ProtoTxIns.tx_ins:type_name -> block.ProtoTxIn - 28, // 62: block.ProtoTxOuts.tx_outs:type_name -> block.ProtoTxOut - 27, // 63: block.ProtoTxIn.previous_out_point:type_name -> block.ProtoOutPoint - 34, // 64: block.ProtoOutPoint.hash:type_name -> common.ProtoHash - 34, // 65: block.ProtoOutPointAndDenomination.hash:type_name -> common.ProtoHash - 32, // 66: block.ProtoAddressOutPoints.out_points:type_name -> block.ProtoAddressOutPoints.OutPointsEntry - 33, // 67: block.ProtoOutPointsMap.entries:type_name -> block.ProtoOutPointsMap.EntriesEntry - 29, // 68: block.ProtoAddressOutPoints.OutPointsEntry.value:type_name -> block.ProtoOutPointAndDenomination - 30, // 69: block.ProtoOutPointsMap.EntriesEntry.value:type_name -> block.ProtoAddressOutPoints - 70, // [70:70] is the sub-list for method output_type - 70, // [70:70] is the sub-list for method input_type - 70, // [70:70] is the sub-list for extension type_name - 70, // [70:70] is the sub-list for extension extendee - 0, // [0:70] is the sub-list for field type_name + 36, // 30: block.ProtoWorkObjectHeader.coinbase:type_name -> common.ProtoAddress + 6, // 31: block.ProtoWorkObjectHeaders.wo_headers:type_name -> block.ProtoWorkObjectHeader + 0, // 32: block.ProtoWorkObjectBody.header:type_name -> block.ProtoHeader + 2, // 33: block.ProtoWorkObjectBody.transactions:type_name -> block.ProtoTransactions + 7, // 34: block.ProtoWorkObjectBody.uncles:type_name -> block.ProtoWorkObjectHeaders + 2, // 35: block.ProtoWorkObjectBody.ext_transactions:type_name -> block.ProtoTransactions + 4, // 36: block.ProtoWorkObjectBody.manifest:type_name -> block.ProtoManifest + 37, // 37: block.ProtoWorkObjectBody.interlink_hashes:type_name -> common.ProtoHashes + 6, // 38: block.ProtoWorkObject.wo_header:type_name -> block.ProtoWorkObjectHeader + 8, // 39: block.ProtoWorkObject.wo_body:type_name -> block.ProtoWorkObjectBody + 1, // 40: block.ProtoWorkObject.tx:type_name -> block.ProtoTransaction + 9, // 41: block.ProtoWorkObjects.work_objects:type_name -> block.ProtoWorkObject + 9, // 42: block.ProtoWorkObjectBlockView.work_object:type_name -> block.ProtoWorkObject + 9, // 43: block.ProtoWorkObjectHeaderView.work_object:type_name -> block.ProtoWorkObject + 9, // 44: block.ProtoWorkObjectShareView.work_object:type_name -> block.ProtoWorkObject + 34, // 45: block.ProtoAccessTuple.storage_key:type_name -> common.ProtoHash + 34, // 46: block.ProtoReceiptForStorage.tx_hash:type_name -> common.ProtoHash + 36, // 47: block.ProtoReceiptForStorage.contract_address:type_name -> common.ProtoAddress + 18, // 48: block.ProtoReceiptForStorage.logs:type_name -> block.ProtoLogsForStorage + 2, // 49: block.ProtoReceiptForStorage.etxs:type_name -> block.ProtoTransactions + 15, // 50: block.ProtoReceiptsForStorage.receipts:type_name -> block.ProtoReceiptForStorage + 36, // 51: block.ProtoLogForStorage.address:type_name -> common.ProtoAddress + 34, // 52: block.ProtoLogForStorage.topics:type_name -> common.ProtoHash + 17, // 53: block.ProtoLogsForStorage.logs:type_name -> block.ProtoLogForStorage + 9, // 54: block.ProtoPendingHeader.wo:type_name -> block.ProtoWorkObject + 20, // 55: block.ProtoPendingHeader.termini:type_name -> block.ProtoTermini + 34, // 56: block.ProtoTermini.dom_termini:type_name -> common.ProtoHash + 34, // 57: block.ProtoTermini.sub_termini:type_name -> common.ProtoHash + 9, // 58: block.ProtoPendingEtxs.header:type_name -> block.ProtoWorkObject + 2, // 59: block.ProtoPendingEtxs.etxs:type_name -> block.ProtoTransactions + 9, // 60: block.ProtoPendingEtxsRollup.header:type_name -> block.ProtoWorkObject + 2, // 61: block.ProtoPendingEtxsRollup.etxs_rollup:type_name -> block.ProtoTransactions + 26, // 62: block.ProtoTxIns.tx_ins:type_name -> block.ProtoTxIn + 28, // 63: block.ProtoTxOuts.tx_outs:type_name -> block.ProtoTxOut + 27, // 64: block.ProtoTxIn.previous_out_point:type_name -> block.ProtoOutPoint + 34, // 65: block.ProtoOutPoint.hash:type_name -> common.ProtoHash + 34, // 66: block.ProtoOutPointAndDenomination.hash:type_name -> common.ProtoHash + 32, // 67: block.ProtoAddressOutPoints.out_points:type_name -> block.ProtoAddressOutPoints.OutPointsEntry + 33, // 68: block.ProtoOutPointsMap.entries:type_name -> block.ProtoOutPointsMap.EntriesEntry + 29, // 69: block.ProtoAddressOutPoints.OutPointsEntry.value:type_name -> block.ProtoOutPointAndDenomination + 30, // 70: block.ProtoOutPointsMap.EntriesEntry.value:type_name -> block.ProtoAddressOutPoints + 71, // [71:71] is the sub-list for method output_type + 71, // [71:71] is the sub-list for method input_type + 71, // [71:71] is the sub-list for extension type_name + 71, // [71:71] is the sub-list for extension extendee + 0, // [0:71] is the sub-list for field type_name } func init() { file_core_types_proto_block_proto_init() } diff --git a/core/types/proto_block.proto b/core/types/proto_block.proto index 9532c47c7f..73101815cb 100644 --- a/core/types/proto_block.proto +++ b/core/types/proto_block.proto @@ -8,34 +8,33 @@ import "common/proto_common.proto"; message ProtoHeader { repeated common.ProtoHash parent_hash = 1; optional common.ProtoHash uncle_hash = 2; - optional bytes coinbase = 3; - optional common.ProtoHash evm_root = 4; - optional common.ProtoHash tx_hash = 5; - optional common.ProtoHash etx_hash = 6; - optional common.ProtoHash etx_rollup_hash = 7; - repeated common.ProtoHash manifest_hash = 8; - optional common.ProtoHash receipt_hash = 9; - optional bytes difficulty = 10; - repeated bytes parent_entropy = 11; - repeated bytes parent_delta_s = 12; - repeated bytes parent_uncled_sub_delta_s = 13; - optional bytes uncled_s = 14; - repeated bytes number = 15; - optional uint64 gas_limit = 16; - optional uint64 gas_used = 17; - optional bytes base_fee = 18; - optional common.ProtoLocation location = 19; - optional bytes extra = 20; - optional common.ProtoHash mix_hash = 21; - optional uint64 nonce = 22; - optional common.ProtoHash utxo_root = 23; - optional common.ProtoHash etx_set_root = 24; - optional uint64 efficiency_score = 25; - optional uint64 threshold_count = 26; - optional uint64 expansion_number = 27; - optional common.ProtoHash etx_eligible_slices = 28; - optional common.ProtoHash prime_terminus = 29; - optional common.ProtoHash interlink_root_hash = 30; + optional common.ProtoHash evm_root = 3; + optional common.ProtoHash tx_hash = 4; + optional common.ProtoHash etx_hash = 5; + optional common.ProtoHash etx_rollup_hash = 6; + repeated common.ProtoHash manifest_hash = 7; + optional common.ProtoHash receipt_hash = 8; + optional bytes difficulty = 9; + repeated bytes parent_entropy = 10; + repeated bytes parent_delta_s = 11; + repeated bytes parent_uncled_sub_delta_s = 12; + optional bytes uncled_s = 13; + repeated bytes number = 14; + optional uint64 gas_limit = 15; + optional uint64 gas_used = 16; + optional bytes base_fee = 17; + optional common.ProtoLocation location = 18; + optional bytes extra = 19; + optional common.ProtoHash mix_hash = 20; + optional uint64 nonce = 21; + optional common.ProtoHash utxo_root = 22; + optional common.ProtoHash etx_set_root = 23; + optional uint64 efficiency_score = 24; + optional uint64 threshold_count = 25; + optional uint64 expansion_number = 26; + optional common.ProtoHash etx_eligible_slices = 27; + optional common.ProtoHash prime_terminus = 28; + optional common.ProtoHash interlink_root_hash = 29; } message ProtoTransaction { @@ -61,6 +60,7 @@ message ProtoTransaction { optional common.ProtoHash parent_hash = 20; optional common.ProtoHash mix_hash = 21; optional uint64 work_nonce = 22; + optional bool is_coinbase = 23; } message ProtoTransactions { repeated ProtoTransaction transactions = 1; } @@ -81,6 +81,7 @@ message ProtoWorkObjectHeader { optional common.ProtoLocation location = 7; optional common.ProtoHash mix_hash = 8; optional uint64 time = 9; + optional common.ProtoAddress coinbase = 10; } message ProtoWorkObjectHeaders { diff --git a/core/types/qi_tx.go b/core/types/qi_tx.go index bc37598e39..94860b839d 100644 --- a/core/types/qi_tx.go +++ b/core/types/qi_tx.go @@ -127,6 +127,10 @@ func (tx *QiTx) setEcdsaSignatureValues(chainID, v, r, s *big.Int) { panic("Qi TX does not have ECDSA signature values") } +func (tx *QiTx) isCoinbase() bool { + panic("qi TX does not have isCoinbase field") +} + // CalculateQiTxGas calculates the total amount of gas a Qi tx uses (for fee calculation) func CalculateQiTxGas(transaction *Transaction, location common.Location) uint64 { if transaction.Type() != QiTxType { diff --git a/core/types/quai_tx.go b/core/types/quai_tx.go index 61d8cdd689..a19515c409 100644 --- a/core/types/quai_tx.go +++ b/core/types/quai_tx.go @@ -124,6 +124,10 @@ func (tx *QuaiTx) setEcdsaSignatureValues(chainID, v, r, s *big.Int) { tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s } +func (tx *QuaiTx) isCoinbase() bool { + panic("quai TX does not have isCoinbase field") +} + func (tx *QuaiTx) setTo(to common.Address) { tx.To = &to } diff --git a/core/types/transaction.go b/core/types/transaction.go index 491d26a852..a74cf7f990 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -104,6 +104,7 @@ type TxData interface { parentHash() *common.Hash mixHash() *common.Hash workNonce() *BlockNonce + isCoinbase() bool // Schnorr segregated sigs getSchnorrSignature() *schnorr.Signature } @@ -167,6 +168,8 @@ func (tx *Transaction) ProtoEncode() (*ProtoTransaction, error) { etxIndex := uint32(tx.ETXIndex()) protoTx.EtxIndex = &etxIndex protoTx.EtxSender = tx.ETXSender().Bytes() + isCoinbase := tx.IsCoinbase() + protoTx.IsCoinbase = &isCoinbase case QiTxType: var err error protoTx.TxIns, err = tx.TxIn().ProtoEncode() @@ -308,19 +311,22 @@ func (tx *Transaction) ProtoDecode(protoTx *ProtoTransaction, location common.Lo if protoTx.EtxIndex == nil { return errors.New("missing required field 'EtxIndex' in ProtoTransaction") } + if protoTx.IsCoinbase == nil { + return errors.New("missing required field 'IsCoinbase in ProtoTransaction") + } var etx ExternalTx + etx.Sender = common.BytesToAddress(protoTx.GetEtxSender(), location) etx.AccessList = AccessList{} etx.AccessList.ProtoDecode(protoTx.GetAccessList(), location) - to := common.BytesToAddress(protoTx.GetTo(), location) - etx.To = &to - etx.Gas = protoTx.GetGas() etx.Data = protoTx.GetData() - etx.Value = new(big.Int).SetBytes(protoTx.GetValue()) etx.OriginatingTxHash = common.BytesToHash(protoTx.GetOriginatingTxHash().Value) etx.ETXIndex = uint16(protoTx.GetEtxIndex()) - etx.Sender = common.BytesToAddress(protoTx.GetEtxSender(), location) + to := common.BytesToAddress(protoTx.GetTo(), location) + etx.To = &to + etx.Value = new(big.Int).SetBytes(protoTx.GetValue()) + etx.IsCoinbase = protoTx.GetIsCoinbase() tx.SetInner(&etx) @@ -562,6 +568,8 @@ func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() func (tx *Transaction) ETXSender() common.Address { return tx.inner.etxSender() } func (tx *Transaction) OriginatingTxHash() common.Hash { return tx.inner.originatingTxHash() } +func (tx *Transaction) IsCoinbase() bool { return tx.inner.isCoinbase() } + func (tx *Transaction) ETXIndex() uint16 { return tx.inner.etxIndex() } func (tx *Transaction) TxOut() TxOuts { return tx.inner.txOut() } @@ -840,25 +848,32 @@ func (s Transactions) FilterToLocation(l common.Location) Transactions { // FilterToSlice returns the subset of transactions with a 'to' address which // belongs to the given sub location, at or above the given minimum context -func (s Transactions) FilterToSub(slice common.Location, nodeCtx int) Transactions { +func (s Transactions) FilterToSub(slice common.Location, nodeCtx int, order int) Transactions { filteredList := Transactions{} for _, tx := range s { - // check if the tx is a conversion type and filter all the conversion types + // check if the tx is a conversion type and filter all the conversion, coinbase types // that are going into the region in the case of Prime and all the ones // going to the zone in the case of region // In the case of Prime, we will filter all the etxs that are going into // any zone in the given location, but in the case of Region we only send // the relevant etxs down + coinbase := IsCoinBaseTx(tx) + conversion := IsConversionTx(tx) + standardEtx := !coinbase && !conversion switch nodeCtx { case common.PRIME_CTX: - if tx.IsTxAConversionTx(slice) && tx.To().Location().Region() == slice.Region() || - tx.To().Location().Region() == slice.Region() { + if tx.To().Location().Region() == slice.Region() { filteredList = append(filteredList, tx) } case common.REGION_CTX: - if tx.IsTxAConversionTx(slice) && tx.To().Location().Equal(slice) || - tx.To().Location().Equal(slice) { - filteredList = append(filteredList, tx) + if order == common.PRIME_CTX { + if tx.To().Location().Equal(slice) { + filteredList = append(filteredList, tx) + } + } else { + if tx.To().Location().Equal(slice) && standardEtx { + filteredList = append(filteredList, tx) + } } } } @@ -1234,9 +1249,13 @@ func GetInnerForTesting(tx *Transaction) TxData { } // It checks if an tx is a conversion type -func (tx *Transaction) IsTxAConversionTx(nodeLocation common.Location) bool { +func IsConversionTx(tx *Transaction) bool { if tx.Type() != ExternalTxType { return false } - return tx.ETXSender().Location().Equal(*tx.To().Location()) + if !tx.IsCoinbase() { + return tx.ETXSender().Location().Equal(*tx.To().Location()) + } else { + return false + } } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index a3313be548..2569c42d88 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -531,7 +531,7 @@ func etxData() (*Transaction, common.Hash) { func TestEtxHash(t *testing.T) { _, hash := etxData() - correctHash := common.HexToHash("0x56b300ea99355ef39a7e4ccbfdfa9cf081307ec33c6b9c90212d9518763b154b") + correctHash := common.HexToHash("0x569200efce076a61575a3661dcb6f59e77e0407279c8db136ef9b2fa23d361ce") require.Equal(t, hash, correctHash, "Hash not equal to expected hash") } @@ -1022,3 +1022,21 @@ func FuzzQiTxHashingWorkNonce(f *testing.F) { } }) } + +func TestCoinbaseTxEncodeDecode(t *testing.T) { + toAddr := common.HexToAddress("0x0013e45aa16163F2663015b6695894D918866d19", common.Location{0, 0}) + coinbaseTx := NewTx(&ExternalTx{To: &toAddr, Value: big.NewInt(10), Data: []byte{1}, OriginatingTxHash: common.HexToHash("0xa"), Sender: common.HexToAddress("0x0", common.Location{0, 0})}) + + // Encode transaction + protoTx, err := coinbaseTx.ProtoEncode() + require.Equal(t, err, nil) + + // Decode transaction + tx := Transaction{} + err = tx.ProtoDecode(protoTx, common.Location{0, 0}) + require.Equal(t, err, nil) + + reflect.DeepEqual(coinbaseTx, tx) + + require.Equal(t, coinbaseTx.Hash(), tx.Hash()) +} diff --git a/core/types/utxo_validate.go b/core/types/utxo_validate.go index b76d8dea35..4428e424db 100644 --- a/core/types/utxo_validate.go +++ b/core/types/utxo_validate.go @@ -1,11 +1,5 @@ package types -import ( - "bytes" - - "github.com/dominant-strategies/go-quai/common" -) - // IsCoinBaseTx determines whether or not a transaction is a coinbase. A coinbase // is a special transaction created by miners that has no inputs. This is // represented in the block chain by a transaction with a single input that has @@ -14,35 +8,12 @@ import ( // // This function only differs from IsCoinBase in that it works with a raw wire // transaction as opposed to a higher level util transaction. -func IsCoinBaseTx(tx *Transaction, parentHash common.Hash, location common.Location) bool { +func IsCoinBaseTx(tx *Transaction) bool { if tx == nil || tx.inner == nil { return false } - if tx.Type() == QuaiTxType { - // Quai coinbase tx have specific data in the data field - // This transaction must also be the first in the block - // NOTE: A miner must not replace their coinbase with a real transaction without checking this field! - if bytes.Equal(tx.Data(), common.Hex2Bytes("Quai block reward")) { - return true - } else { - return false - } + if tx.Type() == ExternalTxType { + return tx.IsCoinbase() } - // A coin base must only have one transaction input. - if len(tx.inner.txIn()) != 1 { - return false - } - - // The coinbase transaction input must be the parent hash encoded with the proper origin location - origin := (uint8(location[0]) * 16) + uint8(location[1]) - parentHash[0] = origin - parentHash[1] = origin - - // The previous output of a coin base must have a max value index and the parent hash. - prevOut := &tx.inner.txIn()[0].PreviousOutPoint - if prevOut.Index != MaxOutputIndex || prevOut.TxHash != parentHash { - return false - } - - return true + return false } diff --git a/core/types/wo.go b/core/types/wo.go index 3cd19b3ea4..9f05027974 100644 --- a/core/types/wo.go +++ b/core/types/wo.go @@ -41,6 +41,7 @@ type WorkObjectHeader struct { number *big.Int difficulty *big.Int txHash common.Hash + coinbase common.Address location common.Location mixHash common.Hash time uint64 @@ -158,6 +159,10 @@ func (wo *WorkObject) TxHash() common.Hash { return wo.WorkObjectHeader().TxHash() } +func (wo *WorkObject) Coinbase() common.Address { + return wo.WorkObjectHeader().Coinbase() +} + func (wo *WorkObject) MixHash() common.Hash { return wo.WorkObjectHeader().MixHash() } @@ -238,10 +243,6 @@ func (wo *WorkObject) GasLimit() uint64 { return wo.Header().GasLimit() } -func (wo *WorkObject) Coinbase() common.Address { - return wo.Header().Coinbase() -} - func (wo *WorkObject) ManifestHash(nodeCtx int) common.Hash { return wo.Header().ManifestHash(nodeCtx) } @@ -318,21 +319,19 @@ func (wo *WorkObject) InterlinkHashes() common.Hashes { } func (wo *WorkObject) QiTransactions() []*Transaction { - return wo.Body().QiTransactions() -} - -func (wo *WorkObject) QuaiTransactions() []*Transaction { - return wo.Body().QuaiTransactions() + qiTxs := make([]*Transaction, 0) + for _, t := range wo.Transactions() { + if t.Type() == QiTxType { + qiTxs = append(qiTxs, t) + } + } + return qiTxs } func (wo *WorkObject) QiTransactionsWithoutCoinbase() []*Transaction { // TODO: cache the UTXO loop qiTxs := make([]*Transaction, 0) - for i, t := range wo.Transactions() { - if i == 0 && IsCoinBaseTx(t, wo.woHeader.parentHash, wo.woHeader.location) { - // ignore the Qi coinbase tx - continue - } + for _, t := range wo.Transactions() { if t.Type() == QiTxType { qiTxs = append(qiTxs, t) } @@ -342,8 +341,8 @@ func (wo *WorkObject) QiTransactionsWithoutCoinbase() []*Transaction { func (wo *WorkObject) TransactionsWithReceipts() []*Transaction { txs := make([]*Transaction, 0) - for i, t := range wo.Transactions() { - if i == 0 && IsCoinBaseTx(t, wo.woHeader.parentHash, wo.woHeader.location) { + for _, t := range wo.Transactions() { + if IsCoinBaseTx(t) { // ignore the coinbase tx continue } @@ -354,36 +353,48 @@ func (wo *WorkObject) TransactionsWithReceipts() []*Transaction { return txs } -// QuaiTransactionsWithoutCoinbase returns all Quai EVM transactions in the block, excluding the coinbase transaction. -// This also returns all transactions that have an associated receipt. -func (wo *WorkObject) QuaiTransactionsWithoutCoinbase() []*Transaction { - quaiTxs := make([]*Transaction, 0) - for i, t := range wo.Transactions() { - if i == 0 && IsCoinBaseTx(t, wo.woHeader.parentHash, wo.woHeader.location) || t.Type() == QiTxType || (t.Type() == ExternalTxType && t.To().IsInQiLedgerScope()) { - // ignore the Quai coinbase tx and Quai->Qi to comply with prior functionality as it is not a normal transaction - continue - } - if t.Type() == QuaiTxType { - quaiTxs = append(quaiTxs, t) - } - } - return quaiTxs -} - -func (wo *WorkObject) InputsAndOutputsWithoutCoinbase() (uint, uint) { - inputs := 0 - outputs := 0 - for i, tx := range wo.Transactions() { - if i == 0 && IsCoinBaseTx(tx, wo.woHeader.parentHash, wo.woHeader.location) { - // ignore the Qi coinbase tx - continue - } - if tx.Type() == QiTxType { +func (wo *WorkObject) TransactionsInfo() map[string]interface{} { + txInfo := make(map[string]interface{}) + txInfo["hash"] = wo.Hash() + var inputs, outputs int + var quai, qi, etxOutBound, etxInbound, coinbaseOutboundEtx, coinbaseInboundEtx, conversionOutboundEtx, conversionInboundEtx int + var txCount int + for _, tx := range wo.Transactions() { + txCount++ + if tx.Type() == QuaiTxType { + quai++ + } else if tx.Type() == QiTxType { + qi++ inputs += len(tx.TxIn()) outputs += len(tx.TxOut()) + } else if tx.Type() == ExternalTxType { + etxInbound++ + if IsCoinBaseTx(tx) { + coinbaseInboundEtx++ + } else if IsConversionTx(tx) { + conversionInboundEtx++ + } + } + } + for _, etx := range wo.ExtTransactions() { + etxOutBound++ + if IsCoinBaseTx(etx) { + coinbaseOutboundEtx++ + } else if IsConversionTx(etx) { + conversionOutboundEtx++ } } - return uint(inputs), uint(outputs) + txInfo["txs"] = txCount + txInfo["quai"] = quai + txInfo["qi"] = qi + txInfo["net input/outputs"] = outputs - inputs + txInfo["etxInbound"] = etxInbound + txInfo["etxOutbound"] = etxOutBound + txInfo["coinbaseEtxOutbound"] = coinbaseOutboundEtx + txInfo["coinbaseEtxInbound"] = coinbaseInboundEtx + txInfo["conversionEtxOutbound"] = conversionOutboundEtx + txInfo["conversionEtxInbound"] = conversionInboundEtx + return txInfo } func (wo *WorkObject) NumberArray() []*big.Int { @@ -446,6 +457,10 @@ func (wh *WorkObjectHeader) TxHash() common.Hash { return wh.txHash } +func (wh *WorkObjectHeader) Coinbase() common.Address { + return wh.coinbase +} + func (wh *WorkObjectHeader) Location() common.Location { return wh.location } @@ -490,6 +505,10 @@ func (wh *WorkObjectHeader) SetTxHash(txHash common.Hash) { wh.txHash = txHash } +func (wh *WorkObjectHeader) SetCoinbase(coinbase common.Address) { + wh.coinbase = coinbase +} + func (wh *WorkObjectHeader) SetLocation(location common.Location) { wh.location = location } @@ -571,27 +590,6 @@ func (wb *WorkObjectBody) InterlinkHashes() common.Hashes { return wb.interlinkHashes } -func (wb *WorkObjectBody) QiTransactions() []*Transaction { - // TODO: cache the UTXO loop - qiTxs := make([]*Transaction, 0) - for _, t := range wb.Transactions() { - if t.Type() == QiTxType { - qiTxs = append(qiTxs, t) - } - } - return qiTxs -} - -func (wb *WorkObjectBody) QuaiTransactions() []*Transaction { - quaiTxs := make([]*Transaction, 0) - for _, t := range wb.Transactions() { - if t.Type() == QuaiTxType { - quaiTxs = append(quaiTxs, t) - } - } - return quaiTxs -} - func (wb *WorkObjectBody) ExternalTransactions() []*Transaction { etxs := make([]*Transaction, 0) for _, t := range wb.Transactions() { @@ -711,7 +709,7 @@ func NewWorkObjectBody(header *Header, txs []*Transaction, etxs []*Transaction, } func NewWorkObjectWithHeader(header *WorkObject, tx *Transaction, nodeCtx int, woType WorkObjectView) *WorkObject { - woHeader := NewWorkObjectHeader(header.Hash(), header.ParentHash(common.ZONE_CTX), header.Number(common.ZONE_CTX), header.woHeader.difficulty, header.woHeader.txHash, header.woHeader.nonce, header.woHeader.time, header.Location()) + woHeader := NewWorkObjectHeader(header.Hash(), header.ParentHash(common.ZONE_CTX), header.Number(common.ZONE_CTX), header.woHeader.difficulty, header.woHeader.txHash, header.woHeader.nonce, header.woHeader.time, header.Location(), header.Coinbase()) woBody, _ := NewWorkObjectBody(header.Body().Header(), nil, nil, nil, nil, nil, nil, nodeCtx) return NewWorkObject(woHeader, woBody, tx) } @@ -844,7 +842,7 @@ func (wo *WorkObject) ProtoDecode(data *ProtoWorkObject, location common.Locatio switch woType { case PEtxObject: wo.woHeader = new(WorkObjectHeader) - err := wo.woHeader.ProtoDecode(data.GetWoHeader()) + err := wo.woHeader.ProtoDecode(data.GetWoHeader(), location) if err != nil { return err } @@ -854,7 +852,7 @@ func (wo *WorkObject) ProtoDecode(data *ProtoWorkObject, location common.Locatio wo.woBody.SetHeader(bodyHeader) default: wo.woHeader = new(WorkObjectHeader) - err := wo.woHeader.ProtoDecode(data.GetWoHeader()) + err := wo.woHeader.ProtoDecode(data.GetWoHeader(), location) if err != nil { return err } @@ -874,7 +872,7 @@ func (wo *WorkObject) ProtoDecode(data *ProtoWorkObject, location common.Locatio return nil } -func NewWorkObjectHeader(headerHash common.Hash, parentHash common.Hash, number *big.Int, difficulty *big.Int, txHash common.Hash, nonce BlockNonce, time uint64, location common.Location) *WorkObjectHeader { +func NewWorkObjectHeader(headerHash common.Hash, parentHash common.Hash, number *big.Int, difficulty *big.Int, txHash common.Hash, nonce BlockNonce, time uint64, location common.Location, coinbase common.Address) *WorkObjectHeader { return &WorkObjectHeader{ headerHash: headerHash, parentHash: parentHash, @@ -884,6 +882,7 @@ func NewWorkObjectHeader(headerHash common.Hash, parentHash common.Hash, number nonce: nonce, time: time, location: location, + coinbase: coinbase, } } @@ -898,6 +897,7 @@ func CopyWorkObjectHeader(wh *WorkObjectHeader) *WorkObjectHeader { cpy.SetMixHash(wh.MixHash()) cpy.SetLocation(wh.Location()) cpy.SetTime(wh.Time()) + cpy.SetCoinbase(wh.Coinbase()) return &cpy } @@ -912,6 +912,7 @@ func (wh *WorkObjectHeader) RPCMarshalWorkObjectHeader() map[string]interface{} "txHash": wh.TxHash(), "time": hexutil.Uint64(wh.Time()), "mixHash": wh.MixHash(), + "coinbase": wh.Coinbase(), } return result } @@ -952,6 +953,7 @@ func (wh *WorkObjectHeader) SealEncode() *ProtoWorkObjectHeader { difficulty := wh.Difficulty().Bytes() location := wh.Location().ProtoEncode() time := wh.Time() + coinbase := common.ProtoAddress{Value: wh.Coinbase().Bytes()} return &ProtoWorkObjectHeader{ HeaderHash: &hash, @@ -961,6 +963,7 @@ func (wh *WorkObjectHeader) SealEncode() *ProtoWorkObjectHeader { TxHash: &txHash, Location: location, Time: &time, + Coinbase: &coinbase, } } @@ -973,6 +976,7 @@ func (wh *WorkObjectHeader) ProtoEncode() (*ProtoWorkObjectHeader, error) { location := wh.Location().ProtoEncode() nonce := wh.Nonce().Uint64() mixHash := common.ProtoHash{Value: wh.MixHash().Bytes()} + coinbase := common.ProtoAddress{Value: wh.Coinbase().Bytes()} return &ProtoWorkObjectHeader{ HeaderHash: &hash, @@ -984,11 +988,12 @@ func (wh *WorkObjectHeader) ProtoEncode() (*ProtoWorkObjectHeader, error) { Nonce: &nonce, MixHash: &mixHash, Time: &wh.time, + Coinbase: &coinbase, }, nil } -func (wh *WorkObjectHeader) ProtoDecode(data *ProtoWorkObjectHeader) error { - if data.HeaderHash == nil || data.ParentHash == nil || data.Number == nil || data.Difficulty == nil || data.TxHash == nil || data.Nonce == nil || data.Location == nil { +func (wh *WorkObjectHeader) ProtoDecode(data *ProtoWorkObjectHeader, location common.Location) error { + if data.HeaderHash == nil || data.ParentHash == nil || data.Number == nil || data.Difficulty == nil || data.TxHash == nil || data.Nonce == nil || data.Location == nil || data.Time == nil || data.Coinbase == nil { err := errors.New("failed to decode work object header") return err } @@ -1001,6 +1006,7 @@ func (wh *WorkObjectHeader) ProtoDecode(data *ProtoWorkObjectHeader) error { wh.SetLocation(data.GetLocation().GetValue()) wh.SetMixHash(common.BytesToHash(data.GetMixHash().Value)) wh.SetTime(data.GetTime()) + wh.SetCoinbase(common.BytesToAddress(data.GetCoinbase().GetValue(), location)) return nil } @@ -1088,7 +1094,7 @@ func (wb *WorkObjectBody) ProtoDecode(data *ProtoWorkObjectBody, location common wb.uncles = make([]*WorkObjectHeader, len(data.GetUncles().GetWoHeaders())) for i, protoUncle := range data.GetUncles().GetWoHeaders() { uncle := &WorkObjectHeader{} - err = uncle.ProtoDecode(protoUncle) + err = uncle.ProtoDecode(protoUncle, location) if err != nil { return err } @@ -1127,7 +1133,7 @@ func (wb *WorkObjectBody) ProtoDecode(data *ProtoWorkObjectBody, location common wb.uncles = make([]*WorkObjectHeader, len(data.GetUncles().GetWoHeaders())) for i, protoUncle := range data.GetUncles().GetWoHeaders() { uncle := &WorkObjectHeader{} - err = uncle.ProtoDecode(protoUncle) + err = uncle.ProtoDecode(protoUncle, location) if err != nil { return err } diff --git a/core/types/wo_test.go b/core/types/wo_test.go index 3e723a850f..ec4aaba0b9 100644 --- a/core/types/wo_test.go +++ b/core/types/wo_test.go @@ -27,7 +27,7 @@ func woTestData() (*WorkObject, common.Hash) { func TestWoHash(t *testing.T) { _, hash := woTestData() - correctHash := common.HexToHash("0x9ed4ddaec19bbb4a44d9e0ebfda532406667501b44170b9ccebcc33421042ce8") + correctHash := common.HexToHash("0xce1b26f11a4694a6be74e23b92ce133de912799bc7e067fa05f3bb19fb356d2c") require.Equal(t, hash, correctHash, "Hash not equal to expected hash") } diff --git a/core/worker.go b/core/worker.go index 46525f7bfd..ec0e46c9ac 100644 --- a/core/worker.go +++ b/core/worker.go @@ -1,7 +1,6 @@ package core import ( - "crypto/ecdsa" "errors" "fmt" "math/big" @@ -12,7 +11,6 @@ import ( "sync/atomic" "time" - "github.com/btcsuite/btcd/btcec/v2/schnorr" mapset "github.com/deckarep/golang-set" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/dominant-strategies/go-quai/common" @@ -79,6 +77,7 @@ type environment struct { txs []*types.Transaction etxs []*types.Transaction utxoFees *big.Int + quaiFees *big.Int subManifest types.BlockManifest receipts []*types.Receipt uncleMu sync.RWMutex @@ -100,6 +99,7 @@ func (env *environment) copy(processingState bool, nodeCtx int) *environment { wo: types.CopyWorkObject(env.wo), receipts: copyReceipts(env.receipts), utxoFees: new(big.Int).Set(env.utxoFees), + quaiFees: new(big.Int).Set(env.quaiFees), } if env.gasPool != nil { gasPool := *env.gasPool @@ -554,17 +554,37 @@ func (w *worker) GeneratePendingHeader(block *types.WorkObject, fill bool) (*typ return nil, err } + uncles := work.unclelist() if nodeCtx == common.ZONE_CTX && w.hc.ProcessingState() { + // First etx is always the coinbase etx + // If workshares are included that are not uncles(?) + // create a placeholder for the coinbase and create etx for the rest of the workshares if coinbase.IsInQiLedgerScope() { - work.txs = append(work.txs, types.NewTx(&types.QiTx{})) // placeholder + work.etxs = append(work.etxs, types.NewTx(&types.ExternalTx{})) } else if coinbase.IsInQuaiLedgerScope() { - work.txs = append(work.txs, types.NewTx(&types.QuaiTx{})) // placeholder + work.etxs = append(work.etxs, types.NewTx(&types.ExternalTx{})) } + + // Encode the parent hash with the correct origin location and use it in the OriginatingTxHash field for coinbase + origin := block.Hash() + origin[0] = byte(w.hc.NodeLocation().Region()) + origin[1] = byte(w.hc.NodeLocation().Zone()) + + // Add an etx for each workshare for it to be rewarded + for i, uncle := range uncles { + reward := misc.CalculateReward(uncle) + uncleCoinbase := uncle.Coinbase() + work.etxs = append(work.etxs, types.NewTx(&types.ExternalTx{To: &uncleCoinbase, Value: reward, IsCoinbase: true, OriginatingTxHash: origin, ETXIndex: uint16(i) + 1, Sender: uncleCoinbase})) + } + // Fill pending transactions from the txpool w.adjustGasLimit(work, block) work.utxoFees = big.NewInt(0) + work.quaiFees = big.NewInt(0) start := time.Now() - w.fillTransactions(interrupt, work, block, fill) + if err := w.fillTransactions(interrupt, work, block, fill); err != nil { + return nil, fmt.Errorf("error generating pending header: %v", err) + } if fill { w.fillTransactionsRollingAverage.Add(time.Since(start)) w.logger.WithFields(log.Fields{ @@ -573,24 +593,39 @@ func (w *worker) GeneratePendingHeader(block *types.WorkObject, fill bool) (*typ "average": common.PrettyDuration(w.fillTransactionsRollingAverage.Average()), }).Info("Filled and sorted pending transactions") } - if coinbase.IsInQiLedgerScope() { - coinbaseTx, err := createQiCoinbaseTxWithFees(work.wo, work.utxoFees, work.state, work.signer, w.ephemeralKey) - if err != nil { - return nil, err + + // If the current block is a prime block, its a prime terminus + _, order, err := w.engine.CalcOrder(block) + if err != nil { + return nil, err + } + var primeTerminus *types.WorkObject + if order == common.PRIME_CTX { + primeTerminus = block + } else { + // convert the Quai reward into Qi and add it to the utxoFees + primeTerminus = w.hc.GetHeaderByHash(work.wo.PrimeTerminus()) + if primeTerminus == nil { + return nil, fmt.Errorf("could not find prime terminus header %032x", work.wo.PrimeTerminus()) } - work.txs[0] = coinbaseTx + } + if coinbase.IsInQiLedgerScope() { + coinbaseReward := misc.CalculateReward(work.wo.WorkObjectHeader()) + blockFees := new(big.Int).Add(work.utxoFees, misc.QuaiToQi(primeTerminus.WorkObjectHeader(), work.quaiFees)) + blockReward := new(big.Int).Add(coinbaseReward, blockFees) + coinbaseEtx := types.NewTx(&types.ExternalTx{To: &coinbase, Value: blockReward, IsCoinbase: true, OriginatingTxHash: origin, ETXIndex: 0, Sender: coinbase}) + work.etxs[0] = coinbaseEtx } else if coinbase.IsInQuaiLedgerScope() { - coinbaseTx, err := createQuaiCoinbaseTx(work.state, work.wo, w.logger, work.signer, w.ephemeralKey.ToECDSA()) - if err != nil { - return nil, err - } - work.txs[0] = coinbaseTx + coinbaseReward := misc.CalculateReward(work.wo.WorkObjectHeader()) + blockFees := new(big.Int).Add(work.quaiFees, misc.QiToQuai(primeTerminus.WorkObjectHeader(), work.utxoFees)) + blockReward := new(big.Int).Add(coinbaseReward, blockFees) + coinbaseEtx := types.NewTx(&types.ExternalTx{To: &coinbase, Value: blockReward, IsCoinbase: true, OriginatingTxHash: origin, ETXIndex: 0, Sender: coinbase}) + work.etxs[0] = coinbaseEtx } - } // Create a local environment copy, avoid the data race with snapshot state. - newWo, err := w.FinalizeAssemble(w.hc, work.wo, block, work.state, work.txs, work.unclelist(), work.etxs, work.subManifest, work.receipts) + newWo, err := w.FinalizeAssemble(w.hc, work.wo, block, work.state, work.txs, uncles, work.etxs, work.subManifest, work.receipts) if err != nil { return nil, err } @@ -736,16 +771,64 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t if tx == nil { return nil, false, errors.New("nil transaction") } + // coinbase tx + // 1) is a external tx type + // 2) do not consume any gas + // 3) do not produce any receipts/logs + // 4) etx emit threshold numbers + if types.IsCoinBaseTx(tx) { + iAddr, err := tx.To().InternalAddress() + if err != nil { + return nil, false, errors.New("coinbase address is not in the chain scope") + } + if tx.To().IsInQiLedgerScope() { + value := tx.Value() + denominations := misc.FindMinDenominations(value) + outputIndex := uint16(0) + // Iterate over the denominations in descending order + for denomination := types.MaxDenomination; denomination >= 0; denomination-- { + // If the denomination count is zero, skip it + if denominations[uint8(denomination)] == 0 { + continue + } + for j := uint8(0); j < denominations[uint8(denomination)]; j++ { + if outputIndex >= types.MaxOutputIndex { + // No more gas, the rest of the denominations are lost but the tx is still valid + break + } + // the ETX hash is guaranteed to be unique + if err := env.state.CreateUTXO(tx.Hash(), outputIndex, types.NewUtxoEntry(types.NewTxOut(uint8(denomination), tx.To().Bytes(), env.wo.Number(w.hc.NodeCtx())))); err != nil { + return nil, false, err + } + outputIndex++ + } + } + } else if tx.To().IsInQuaiLedgerScope() { + // This includes the value and the fees + env.state.AddBalance(iAddr, tx.Value()) + } + env.txs = append(env.txs, tx) + return []*types.Log{}, false, nil + } if tx.Type() == types.ExternalTxType && tx.To().IsInQiLedgerScope() { gasUsed := env.wo.GasUsed() txGas := tx.Gas() if tx.ETXSender().Location().Equal(*tx.To().Location()) { // Quai->Qi conversion lock := new(big.Int).Add(env.wo.Number(w.hc.NodeCtx()), big.NewInt(params.ConversionLockPeriod)) - primeTerminus := w.hc.GetPrimeTerminus(env.wo) - if primeTerminus == nil { - return nil, false, errors.New("prime terminus not found") + _, parentOrder, err := w.engine.CalcOrder(parent) + if err != nil { + return nil, false, err + } + var primeTerminus *types.WorkObject + if parentOrder == common.PRIME_CTX { + primeTerminus = parent + } else { + primeTerminus = w.hc.GetPrimeTerminus(env.wo) + if primeTerminus == nil { + return nil, false, errors.New("prime terminus not found") + } } - value := misc.QuaiToQi(primeTerminus, tx.Value()) + value := misc.QuaiToQi(primeTerminus.WorkObjectHeader(), tx.Value()) denominations := misc.FindMinDenominations(value) outputIndex := uint16(0) @@ -789,7 +872,7 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t snap := env.state.Snapshot() // retrieve the gas used int and pass in the reference to the ApplyTransaction gasUsed := env.wo.GasUsed() - receipt, err := ApplyTransaction(w.chainConfig, parent, w.hc, &env.coinbase, env.gasPool, env.state, env.wo, tx, &gasUsed, *w.hc.bc.processor.GetVMConfig(), &env.etxRLimit, &env.etxPLimit, w.logger) + receipt, quaiFees, err := ApplyTransaction(w.chainConfig, parent, w.hc, &env.coinbase, env.gasPool, env.state, env.wo, tx, &gasUsed, *w.hc.bc.processor.GetVMConfig(), &env.etxRLimit, &env.etxPLimit, w.logger) if err != nil { w.logger.WithFields(log.Fields{ "err": err, @@ -808,11 +891,12 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t // was possible. env.wo.Header().SetGasUsed(gasUsed) env.txs = append(env.txs, tx) + env.quaiFees = new(big.Int).Add(env.quaiFees, quaiFees) env.receipts = append(env.receipts, receipt) return receipt.Logs, true, nil } -func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, txs *types.TransactionsByPriceAndNonce, interrupt *int32) bool { +func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, txs *types.TransactionsByPriceAndNonce, interrupt *int32) error { qiTxsToRemove := make([]*common.Hash, 0) gasLimit := env.wo.GasLimit if env.gasPool == nil { @@ -820,34 +904,19 @@ func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, } var coalescedLogs []*types.Log minEtxGas := gasLimit() / params.MinimumEtxGasDivisor - oldestIndex, err := env.state.GetOldestIndex() - if err != nil { - w.logger.WithField("err", err).Error("Failed to get oldest index") - return true - } for { - if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { - return atomic.LoadInt32(interrupt) == commitInterruptNewHead - } - if env.gasPool.Gas() < params.TxGas { - w.logger.WithFields(log.Fields{ - "have": env.gasPool, - "want": params.TxGas, - }).Trace("Not enough gas for further transactions") - break - } // Add ETXs until minimum gas is used if env.wo.GasUsed() >= minEtxGas { break } if env.wo.GasUsed() > minEtxGas*params.MaximumEtxGasMultiplier { // sanity check, this should never happen w.logger.WithField("Gas Used", env.wo.GasUsed()).Error("Block uses more gas than maximum ETX gas") - return true + return fmt.Errorf("block uses more gas than maximum ETX gas") } etx, err := env.state.PopETX() if err != nil { w.logger.WithField("err", err).Error("Failed to read ETX") - return true + return fmt.Errorf("failed to read ETX: %w", err) } if etx == nil { break @@ -859,29 +928,17 @@ func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, env.tcount++ } else if err == nil && !receipt { env.tcount++ + } else { + w.logger.WithField("err", err).Error("Failed to commit an etx") } - oldestIndex.Add(oldestIndex, big.NewInt(1)) } for { - // In the following three cases, we will interrupt the execution of the transaction. + // In the following two cases, we will interrupt the execution of the transaction. // (1) new head block event arrival, the interrupt signal is 1 // (2) worker start or restart, the interrupt signal is 1 - // (3) worker recreate the sealing block with any newly arrived transactions, the interrupt signal is 2. - // For the first two cases, the semi-finished work will be discarded. - // For the third case, the semi-finished work will be submitted to the consensus engine. + // For these two cases, the semi-finished work will be discarded. if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { - // Notify resubmit loop to increase resubmitting interval due to too frequent commits. - if atomic.LoadInt32(interrupt) == commitInterruptResubmit { - ratio := float64(gasLimit()-env.gasPool.Gas()) / float64(gasLimit()) - if ratio < 0.1 { - ratio = 0.1 - } - w.resubmitAdjustCh <- &intervalAdjust{ - ratio: ratio, - inc: true, - } - } - return atomic.LoadInt32(interrupt) == commitInterruptNewHead + return nil } // If we don't have enough gas for any further transactions then we're done if env.gasPool.Gas() < params.TxGas { @@ -905,7 +962,12 @@ func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, }).Trace("Not enough gas for further transactions") break } - if err := w.processQiTx(tx, env); err != nil { + if err := w.processQiTx(tx, env, parent); err != nil { + if strings.Contains(err.Error(), "emits too many") { + // This is not an invalid tx, our block is just full of ETXs + txs.PopNoSort() + continue + } hash := tx.Hash() w.logger.WithFields(log.Fields{ "err": err, @@ -1009,7 +1071,7 @@ func (w *worker) commitTransactions(env *environment, parent *types.WorkObject, } w.pendingLogsFeed.Send(cpy) } - return false + return nil } // generateParams wraps various of settings for generating sealing task. @@ -1192,7 +1254,7 @@ func (w *worker) prepareWork(genParams *generateParams, wo *types.WorkObject) (* w.logger.Error("Refusing to mine without etherbase") return nil, errors.New("refusing to mine without etherbase") } - newWo.Header().SetCoinbase(w.coinbase) + newWo.WorkObjectHeader().SetCoinbase(w.coinbase) } // Get the latest transactions to be broadcasted from the pool @@ -1209,7 +1271,7 @@ func (w *worker) prepareWork(genParams *generateParams, wo *types.WorkObject) (* w.logger.WithField("err", err).Error("Failed to prepare header for sealing") return nil, err } - proposedWoHeader := types.NewWorkObjectHeader(newWo.Hash(), newWo.ParentHash(nodeCtx), newWo.Number(nodeCtx), newWo.Difficulty(), newWo.TxHash(), newWo.Nonce(), newWo.Time(), newWo.Location()) + proposedWoHeader := types.NewWorkObjectHeader(newWo.Hash(), newWo.ParentHash(nodeCtx), newWo.Number(nodeCtx), newWo.Difficulty(), newWo.TxHash(), newWo.Nonce(), newWo.Time(), newWo.Location(), newWo.Coinbase()) proposedWoBody, err := types.NewWorkObjectBody(newWo.Header(), nil, nil, nil, nil, nil, nil, nodeCtx) if err != nil { return nil, err @@ -1261,7 +1323,7 @@ func (w *worker) prepareWork(genParams *generateParams, wo *types.WorkObject) (* } return env, nil } else { - proposedWoHeader := types.NewWorkObjectHeader(newWo.Hash(), newWo.ParentHash(nodeCtx), newWo.Number(nodeCtx), newWo.Difficulty(), types.EmptyRootHash, newWo.Nonce(), newWo.Time(), newWo.Location()) + proposedWoHeader := types.NewWorkObjectHeader(newWo.Hash(), newWo.ParentHash(nodeCtx), newWo.Number(nodeCtx), newWo.Difficulty(), types.EmptyRootHash, newWo.Nonce(), newWo.Time(), newWo.Location(), newWo.Coinbase()) proposedWoBody, err := types.NewWorkObjectBody(newWo.Header(), nil, nil, nil, nil, nil, nil, nodeCtx) if err != nil { return nil, err @@ -1275,7 +1337,7 @@ func (w *worker) prepareWork(genParams *generateParams, wo *types.WorkObject) (* // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. -func (w *worker) fillTransactions(interrupt *int32, env *environment, block *types.WorkObject, fill bool) bool { +func (w *worker) fillTransactions(interrupt *int32, env *environment, block *types.WorkObject, fill bool) error { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. etxs := false @@ -1287,13 +1349,13 @@ func (w *worker) fillTransactions(interrupt *int32, env *environment, block *typ oldestIndex, err := env.state.GetOldestIndex() if err != nil { w.logger.WithField("err", err).Error("Failed to get oldest index") - return false + return fmt.Errorf("failed to get oldest index: %w", err) } // Check if there is at least one ETX in the set etx, err := env.state.ReadETX(oldestIndex) if err != nil { w.logger.WithField("err", err).Error("Failed to read ETX") - return false + return fmt.Errorf("failed to read ETX: %w", err) } if etx != nil { etxs = true @@ -1309,13 +1371,13 @@ func (w *worker) fillTransactions(interrupt *int32, env *environment, block *typ if etxs { return w.commitTransactions(env, block, &types.TransactionsByPriceAndNonce{}, interrupt) } - return false + return nil } pending, err := w.txPool.TxPoolPending(false) if err != nil { w.logger.WithField("err", err).Error("Failed to get pending transactions") - return false + return fmt.Errorf("failed to get pending transactions: %w", err) } pendingQiTxs := w.txPool.QiPoolPending() @@ -1324,7 +1386,7 @@ func (w *worker) fillTransactions(interrupt *int32, env *environment, block *typ txs := types.NewTransactionsByPriceAndNonce(env.signer, pendingQiTxs, pending, env.wo.BaseFee(), true) return w.commitTransactions(env, block, txs, interrupt) } - return false + return nil } // fillTransactions retrieves the pending transactions from the txpool and fills them @@ -1388,11 +1450,13 @@ func (w *worker) FinalizeAssemble(chain consensus.ChainHeaderReader, newWo *type etxRollup = append(etxRollup, parent.ExtTransactions()...) } // Only include the etxs that are going cross Prime in the rollup and the - // conversion type + // conversion and the coinbase tx filteredEtxsRollup := types.Transactions{} for _, etx := range etxRollup { to := etx.To().Location() - if to.Region() != w.hc.NodeLocation().Region() || etx.IsTxAConversionTx(w.hc.NodeLocation()) { + coinbase := types.IsCoinBaseTx(etx) + conversion := types.IsConversionTx(etx) + if to.Region() != w.hc.NodeLocation().Region() || conversion || coinbase { filteredEtxsRollup = append(filteredEtxsRollup, etx) } } @@ -1463,12 +1527,12 @@ func (w *worker) CurrentInfo(header *types.WorkObject) bool { return header.NumberU64(w.hc.NodeCtx())+c_startingPrintLimit > w.hc.CurrentHeader().NumberU64(w.hc.NodeCtx()) } -func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { +func (w *worker) processQiTx(tx *types.Transaction, env *environment, parent *types.WorkObject) error { location := w.hc.NodeLocation() if tx.Type() != types.QiTxType { return fmt.Errorf("tx %032x is not a QiTx", tx.Hash()) } - if types.IsCoinBaseTx(tx, env.wo.ParentHash(w.hc.NodeCtx()), location) { + if types.IsCoinBaseTx(tx) { return fmt.Errorf("tx %032x is a coinbase QiTx", tx.Hash()) } if tx.ChainId().Cmp(w.chainConfig.ChainID) != 0 { @@ -1547,7 +1611,6 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { conversion = true convertAddress = toAddr if txOut.Denomination < params.MinQiConversionDenomination { - w.logger.Error(fmt.Errorf("tx %032x emits convert UTXO with value %d less than minimum conversion denomination", tx.Hash(), txOut.Denomination)) return fmt.Errorf("tx %032x emits convert UTXO with value %d less than minimum conversion denomination", tx.Hash(), txOut.Denomination) } totalConvertQitOut.Add(totalConvertQitOut, types.Denominations[txOut.Denomination]) // Add to total conversion output for aggregation @@ -1555,7 +1618,6 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { delete(addresses, toAddr.Bytes20()) continue } else if toAddr.IsInQuaiLedgerScope() { - w.logger.Error(fmt.Errorf("tx %032x emits UTXO with To address not in the Qi ledger scope", tx.Hash())) return fmt.Errorf("tx %032x emits UTXO with To address not in the Qi ledger scope", tx.Hash()) } @@ -1569,15 +1631,12 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { ETXPCount++ } if ETXRCount > env.etxRLimit { - w.logger.Error(fmt.Errorf("tx %032x emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXRCount, env.etxRLimit)) return fmt.Errorf("tx [%v] emits too many cross-region ETXs for block. emitted: %d, limit: %d", tx.Hash().Hex(), ETXRCount, env.etxRLimit) } if ETXPCount > env.etxPLimit { - w.logger.Error(fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, env.etxPLimit)) return fmt.Errorf("tx [%v] emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash().Hex(), ETXPCount, env.etxPLimit) } if !toAddr.IsInQiLedgerScope() { - w.logger.Error(fmt.Errorf("tx %032x emits UTXO with To address not in the Qi ledger scope", tx.Hash())) return fmt.Errorf("tx [%v] emits UTXO with To address not in the Qi ledger scope", tx.Hash().Hex()) } @@ -1587,12 +1646,24 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { if err := env.gasPool.SubGas(params.ETXGas); err != nil { return err } - primeTerminus := w.hc.GetPrimeTerminus(env.wo) + + _, parentOrder, err := w.engine.CalcOrder(parent) + if err != nil { + return err + } + var primeTerminus *types.WorkObject + if parentOrder == common.PRIME_CTX { + primeTerminus = parent + } else { + primeTerminus = w.hc.GetPrimeTerminus(env.wo) + if primeTerminus == nil { + return errors.New("prime terminus not found") + } + } if !w.hc.CheckIfEtxIsEligible(primeTerminus.EtxEligibleSlices(), *toAddr.Location()) { return fmt.Errorf("etx emitted by tx [%v] going to a slice that is not eligible to receive etx %v", tx.Hash().Hex(), *toAddr.Location()) } etxs = append(etxs, &etxInner) - w.logger.Debug("Added UTXO ETX to block") } else { // This output creates a normal UTXO utxo := types.NewUtxoEntry(&txOut) @@ -1614,7 +1685,7 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { return fmt.Errorf("tx %032x has too many ETXs to calculate required gas", tx.Hash()) } minimumFeeInQuai := new(big.Int).Mul(big.NewInt(int64(requiredGas)), env.wo.BaseFee()) - minimumFee := misc.QuaiToQi(env.wo, minimumFeeInQuai) + minimumFee := misc.QuaiToQi(env.wo.WorkObjectHeader(), minimumFeeInQuai) if txFeeInQit.Cmp(minimumFee) < 0 { return fmt.Errorf("tx %032x has insufficient fee for base fee * gas, have %d want %d", tx.Hash(), txFeeInQit.Uint64(), minimumFee.Uint64()) } @@ -1623,7 +1694,7 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { if conversion { // Since this transaction contains a conversion, the rest of the tx gas is given to conversion - remainingTxFeeInQuai := misc.QiToQuai(env.wo, txFeeInQit) + remainingTxFeeInQuai := misc.QiToQuai(env.wo.WorkObjectHeader(), txFeeInQit) // Fee is basefee * gas, so gas remaining is fee remaining / basefee remainingGas := new(big.Int).Div(remainingTxFeeInQuai, env.wo.BaseFee()) if remainingGas.Uint64() > (env.wo.GasLimit() / params.MinimumEtxGasDivisor) { @@ -1632,7 +1703,6 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { } ETXPCount++ // conversion is technically a cross-prime ETX if ETXPCount > env.etxPLimit { - w.logger.Error(fmt.Errorf("tx %032x emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash(), ETXPCount, env.etxPLimit)) return fmt.Errorf("tx [%v] emits too many cross-prime ETXs for block. emitted: %d, limit: %d", tx.Hash().Hex(), ETXPCount, env.etxPLimit) } etxInner := types.ExternalTx{Value: totalConvertQitOut, To: &convertAddress, Sender: common.ZeroAddress(location), OriginatingTxHash: tx.Hash(), Gas: remainingGas.Uint64()} // Value is in Qits not Denomination @@ -1667,86 +1737,3 @@ func (w *worker) processQiTx(tx *types.Transaction, env *environment) error { // We could add signature verification here, but it's already checked in the mempool and the signature can't be changed, so duplication is largely unnecessary return nil } - -// createQiCoinbaseTxWithFees returns a coinbase transaction paying an appropriate subsidy -// based on the passed block height to the provided address. The transaction is signed -// with an ephemeral key generated in the worker. -func createQiCoinbaseTxWithFees(header *types.WorkObject, fees *big.Int, state *state.StateDB, signer types.Signer, ephemeralKey *secp256k1.PrivateKey) (*types.Transaction, error) { - parentHash := header.ParentHash(header.Location().Context()) // all blocks should have zone location and context - - // The coinbase transaction input must be the parent hash encoded with the proper origin location - origin := (uint8(header.Location()[0]) * 16) + uint8(header.Location()[1]) - parentHash[0] = origin - parentHash[1] = origin - in := types.TxIn{ - // Coinbase transaction input is parent hash with max output index - PreviousOutPoint: *types.NewOutPoint(&parentHash, types.MaxOutputIndex), - PubKey: ephemeralKey.PubKey().SerializeUncompressed(), - } - - reward := misc.CalculateReward(header) - reward.Add(reward, fees) - denominations := misc.FindMinDenominations(reward) - outs := make([]types.TxOut, 0, len(denominations)) - - // Iterate over the denominations in descending order (by key) - for i := types.MaxDenomination; i >= 0; i-- { - // If the denomination count is zero, skip it - if denominations[uint8(i)] == 0 { - continue - } - for j := uint8(0); j < denominations[uint8(i)]; j++ { - // Create the output for the denomination - out := types.TxOut{ - Denomination: uint8(i), - Address: header.Coinbase().Bytes(), - } - outs = append(outs, out) - } - } - - qiTx := &types.QiTx{ - TxIn: []types.TxIn{in}, - TxOut: outs, - } - txDigestHash := signer.Hash(types.NewTx(qiTx)) - sig, err := schnorr.Sign(ephemeralKey, txDigestHash[:]) - if err != nil { - return nil, err - } - qiTx.Signature = sig - if !sig.Verify(txDigestHash[:], ephemeralKey.PubKey()) { - return nil, fmt.Errorf("ephemeral key signature verification failed") - } - tx := types.NewTx(qiTx) - for i, out := range qiTx.TxOut { - // this may be unnecessary - if err := state.CreateUTXO(tx.Hash(), uint16(i), types.NewUtxoEntry(&out)); err != nil { - return nil, err - } - } - return tx, nil -} - -// createQuaiCoinbaseTx returns a coinbase transaction paying an appropriate subsidy -// based on the passed block height to the provided address. -func createQuaiCoinbaseTx(state *state.StateDB, header *types.WorkObject, logger *log.Logger, signer types.Signer, key *ecdsa.PrivateKey) (*types.Transaction, error) { - // Select the correct block reward based on chain progression - blockReward := misc.CalculateReward(header) - coinbase := header.Coinbase() - internal, err := coinbase.InternalAndQuaiAddress() - if err != nil { - logger.WithFields(log.Fields{ - "Address": header.Coinbase().String(), - "Hash": header.Hash().String(), - }).Error("Block has out of scope coinbase, skipping block reward") - return nil, fmt.Errorf("block has out of scope coinbase, skipping block reward") - } - tx := types.NewTx(&types.QuaiTx{To: &coinbase, Value: blockReward, Data: common.Hex2Bytes("Quai block reward")}) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return nil, err - } - state.AddBalance(internal, blockReward) - return tx, nil -} diff --git a/internal/quaiapi/api.go b/internal/quaiapi/api.go index 7160a58a32..7649067723 100644 --- a/internal/quaiapi/api.go +++ b/internal/quaiapi/api.go @@ -641,7 +641,11 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash if err != nil { return nil, err } - evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}) + parent, err := b.BlockByHash(ctx, header.ParentHash(b.NodeCtx())) + if err != nil { + return nil, err + } + evm, vmError, err := b.GetEVM(ctx, msg, state, header, parent, &vm.Config{NoBaseFee: true}) if err != nil { return nil, err } @@ -957,7 +961,6 @@ func RPCMarshalETHHeader(head *types.Header) map[string]interface{} { "parentHash": head.ParentHash, "sha3Uncles": head.UncleHash, "evmRoot": head.EVMRoot, - "miner": head.Coinbase, "extraData": hexutil.Bytes(head.Extra()), "size": hexutil.Uint64(head.Size()), "gasLimit": hexutil.Uint64(head.GasLimit()), @@ -1294,7 +1297,11 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := vm.NewAccessListTracer(accessList, args.from(nodeLocation), to, precompiles) config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true} - vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config) + parent, err := b.BlockByHash(ctx, header.ParentHash(b.NodeCtx())) + if err != nil { + return nil, 0, nil, err + } + vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, parent, &config) if err != nil { return nil, 0, nil, err } diff --git a/internal/quaiapi/backend.go b/internal/quaiapi/backend.go index 2b4d26c0ce..573c342323 100644 --- a/internal/quaiapi/backend.go +++ b/internal/quaiapi/backend.go @@ -69,7 +69,7 @@ type Backend interface { AddressOutpoints(ctx context.Context, address common.Address) (map[string]*types.OutpointAndDenomination, error) UTXOsByAddressAtState(ctx context.Context, state *state.StateDB, address common.Address) ([]*types.UtxoEntry, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) - GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.WorkObject, vmConfig *vm.Config) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.WorkObject, parent *types.WorkObject, vmConfig *vm.Config) (*vm.EVM, func() error, error) SetCurrentExpansionNumber(expansionNumber uint8) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription diff --git a/internal/quaiapi/quai_api.go b/internal/quaiapi/quai_api.go index ef32cb963f..270cb83412 100644 --- a/internal/quaiapi/quai_api.go +++ b/internal/quaiapi/quai_api.go @@ -18,7 +18,6 @@ package quaiapi import ( "context" - "encoding/json" "errors" "math/big" "time" @@ -32,6 +31,7 @@ import ( "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/rpc" "github.com/dominant-strategies/go-quai/trie" + "google.golang.org/protobuf/proto" ) // PublicQuaiAPI provides an API to access Quai related information. @@ -496,7 +496,7 @@ func (s *PublicBlockChainQuaiAPI) BaseFee(ctx context.Context, txType bool) (*bi lastPrime = header } quaiBaseFee := misc.CalcBaseFee(chainCfg, header) - qiBaseFee := misc.QuaiToQi(lastPrime, quaiBaseFee) + qiBaseFee := misc.QuaiToQi(lastPrime.WorkObjectHeader(), quaiBaseFee) if qiBaseFee.Cmp(big.NewInt(0)) == 0 { // Minimum base fee is 1 qit or smallest unit return types.Denominations[0], nil @@ -531,7 +531,7 @@ func (s *PublicBlockChainQuaiAPI) EstimateFeeForQi(ctx context.Context, args Tra if lastPrime == nil || err != nil { lastPrime = header } - feeInQi := misc.QuaiToQi(lastPrime, feeInQuai) + feeInQi := misc.QuaiToQi(lastPrime.WorkObjectHeader(), feeInQuai) if feeInQi.Cmp(big.NewInt(0)) == 0 { // Minimum fee is 1 qit or smallest unit return types.Denominations[0], nil @@ -693,14 +693,19 @@ func (s *PublicBlockChainQuaiAPI) fillSubordinateManifest(b *types.WorkObject) ( } // ReceiveMinedHeader will run checks on the block and add to canonical chain if valid. -func (s *PublicBlockChainQuaiAPI) ReceiveMinedHeader(ctx context.Context, raw json.RawMessage) error { +func (s *PublicBlockChainQuaiAPI) ReceiveMinedHeader(ctx context.Context, raw hexutil.Bytes) error { nodeCtx := s.b.NodeCtx() - // Decode header and transactions. - var woHeader *types.WorkObject - if err := json.Unmarshal(raw, &woHeader); err != nil { + protoWorkObject := &types.ProtoWorkObject{} + err := proto.Unmarshal(raw, protoWorkObject) + if err != nil { + return err + } + + woHeader := &types.WorkObject{} + err = woHeader.ProtoDecode(protoWorkObject, s.b.NodeLocation(), types.PEtxObject) + if err != nil { return err } - woHeader.Header().SetCoinbase(common.BytesToAddress(woHeader.Coinbase().Bytes(), s.b.NodeLocation())) block, err := s.b.ConstructLocalMinedBlock(woHeader) if err != nil && err.Error() == core.ErrBadSubManifest.Error() && nodeCtx < common.ZONE_CTX { s.b.Logger().Info("filling sub manifest") @@ -737,15 +742,23 @@ func (s *PublicBlockChainQuaiAPI) ReceiveMinedHeader(ctx context.Context, raw js return nil } -func (s *PublicBlockChainQuaiAPI) ReceiveWorkShare(ctx context.Context, raw json.RawMessage) error { +func (s *PublicBlockChainQuaiAPI) ReceiveWorkShare(ctx context.Context, raw hexutil.Bytes) error { nodeCtx := s.b.NodeCtx() if nodeCtx != common.ZONE_CTX { return errors.New("work shares cannot be broadcasted in non-zone chain") } - var workShare *types.WorkObjectHeader - if err := json.Unmarshal(raw, &workShare); err != nil { + protoWorkShare := &types.ProtoWorkObjectHeader{} + err := proto.Unmarshal(raw, protoWorkShare) + if err != nil { + return err + } + + workShare := &types.WorkObjectHeader{} + err = workShare.ProtoDecode(protoWorkShare, s.b.NodeLocation()) + if err != nil { return err } + if workShare != nil { // check if the workshare is valid before broadcasting as a sanity if !s.b.CheckIfValidWorkShare(workShare) { @@ -757,7 +770,9 @@ func (s *PublicBlockChainQuaiAPI) ReceiveWorkShare(ctx context.Context, raw json txs, err := s.b.GetTxsFromBroadcastSet(workShare.TxHash()) if err != nil { txs = types.Transactions{} - s.b.Logger().Warn("Failed to get txs from the broadcastSetCache", "err", err) + if workShare.TxHash() != types.EmptyRootHash { + s.b.Logger().Warn("Failed to get txs from the broadcastSetCache", "err", err) + } } if pendingBlockBody == nil { s.b.Logger().Warn("Could not get the pending Block body", "err", err) @@ -777,7 +792,7 @@ func (s *PublicBlockChainQuaiAPI) ReceiveWorkShare(ctx context.Context, raw json return nil } -func (s *PublicBlockChainQuaiAPI) GetPendingHeader(ctx context.Context) (map[string]interface{}, error) { +func (s *PublicBlockChainQuaiAPI) GetPendingHeader(ctx context.Context) (hexutil.Bytes, error) { nodeCtx := s.b.NodeCtx() if nodeCtx != common.ZONE_CTX { return nil, errors.New("getPendingHeader can only be called in zone chain") @@ -794,8 +809,15 @@ func (s *PublicBlockChainQuaiAPI) GetPendingHeader(ctx context.Context) (map[str // Only keep the Header in the body pendingHeaderForMining := pendingHeader.WithBody(pendingHeader.Header(), nil, nil, nil, nil, nil) // Marshal the response. - marshaledPh := pendingHeaderForMining.RPCMarshalWorkObject() - return marshaledPh, nil + protoWo, err := pendingHeaderForMining.ProtoEncode(types.PEtxObject) + if err != nil { + return nil, err + } + data, err := proto.Marshal(protoWo) + if err != nil { + return nil, err + } + return data, nil } // ListRunningChains returns the running locations where the node is serving data. @@ -822,7 +844,7 @@ func (s *PublicBlockChainQuaiAPI) QiRateAtBlock(ctx context.Context, blockRef in return nil } - return misc.QiToQuai(header, new(big.Int).SetUint64(qiAmount)) + return misc.QiToQuai(header.WorkObjectHeader(), new(big.Int).SetUint64(qiAmount)) } // Calculate the amount of Qi that Quai can be converted to. Expect the current Header and the Quai amount in "its", returns the Qi amount in "qits" @@ -839,5 +861,5 @@ func (s *PublicBlockChainQuaiAPI) QuaiRateAtBlock(ctx context.Context, blockRef return nil } - return misc.QuaiToQi(header, new(big.Int).SetUint64(quaiAmount)) + return misc.QuaiToQi(header.WorkObjectHeader(), new(big.Int).SetUint64(quaiAmount)) } diff --git a/params/config.go b/params/config.go index 1c074cba2b..dcde70db84 100644 --- a/params/config.go +++ b/params/config.go @@ -26,18 +26,18 @@ import ( // Genesis hashes to enforce below configs on. var ( // Progpow GenesisHashes - ProgpowColosseumGenesisHash = common.HexToHash("0xa97557ce7e5f922f22d22625928e890c64426b55a829c9c60e33919e31d318b2") - ProgpowGardenGenesisHash = common.HexToHash("0xcdd79c31dc472d21ab24e58602a49084646d5ad5c0121624d2a0e59bad236945") - ProgpowOrchardGenesisHash = common.HexToHash("0xcdd79c31dc472d21ab24e58602a49084646d5ad5c0121624d2a0e59bad236945") - ProgpowLocalGenesisHash = common.HexToHash("0x32a405efc6e32b60d666a36aee97634f4e2717538d2ae7f13ed7488f299f17db") - ProgpowLighthouseGenesisHash = common.HexToHash("0xcdd79c31dc472d21ab24e58602a49084646d5ad5c0121624d2a0e59bad236945") + ProgpowColosseumGenesisHash = common.HexToHash("0xb201ee22336b91e09ec1bbfef901e6788cc2e5ee4f4c1cb161cc4c9020fd4045") + ProgpowGardenGenesisHash = common.HexToHash("0x0ecc9be2b10f3b59a4ae854f5ba19171f7d51b2010502dc8d40af06b0a25922b") + ProgpowOrchardGenesisHash = common.HexToHash("0x0ecc9be2b10f3b59a4ae854f5ba19171f7d51b2010502dc8d40af06b0a25922b") + ProgpowLocalGenesisHash = common.HexToHash("0x572d0ec36139708d4c69033cbc3ec5c8dd3469b9bf77827ae8e4c85b439061a7") + ProgpowLighthouseGenesisHash = common.HexToHash("0x0ecc9be2b10f3b59a4ae854f5ba19171f7d51b2010502dc8d40af06b0a25922b") // Blake3GenesisHashes - Blake3PowColosseumGenesisHash = common.HexToHash("0x301114d60dd28adcc51872021d16591e3ed300cbcb0a72f363aeedeef09c2cbb") - Blake3PowGardenGenesisHash = common.HexToHash("0xcc765ce0d79736950aeded81e32bbd55a03c4dcec236c1944da32609a237fadc") - Blake3PowOrchardGenesisHash = common.HexToHash("0x3b9f95bf2e01aa5a9c09b9b2c102e262a77eebf38bd1c36fdab39f97285233be") - Blake3PowLocalGenesisHash = common.HexToHash("0xdb2e0d01d953a3df18eb42c26cf8caeb58a905474ffe391bc21354ead6e2e0b3") - Blake3PowLighthouseGenesisHash = common.HexToHash("0xf5263c69f46cb25c5c82a6e52cbd7b8c504a453ca8a7b44b581e5b1f2d14df9f") + Blake3PowColosseumGenesisHash = common.HexToHash("0x55fc5d1565c8aaf6c1b64779603346fb733a71cc60a6f3d94e44f7502c194a77") + Blake3PowGardenGenesisHash = common.HexToHash("0xdd431b805b0af7c8f8cfd84f9b691eb8c5eb86df29aa786590c56cc61f60601f") + Blake3PowOrchardGenesisHash = common.HexToHash("0x95ef9cea618a0f778cf690dfae67d802b49667c8076b477be78f27be88faa1be") + Blake3PowLocalGenesisHash = common.HexToHash("0x6eac1430f7bbffb51478928e93f40fddb9b39c37f62cc097b36a3ec987f07556") + Blake3PowLighthouseGenesisHash = common.HexToHash("0xc16a57aac1d365c9d262433cd3fe0a044cff3ee640ca1a82710b4a982455e6b4") ) // Different Network names diff --git a/quai/api_backend.go b/quai/api_backend.go index a0ff8a3fa8..d4095fc194 100644 --- a/quai/api_backend.go +++ b/quai/api_backend.go @@ -256,7 +256,7 @@ func (b *QuaiAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*ty return logs, nil } -func (b *QuaiAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.WorkObject, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *QuaiAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.WorkObject, parent *types.WorkObject, vmConfig *vm.Config) (*vm.EVM, func() error, error) { vmError := func() error { return nil } nodeCtx := b.quai.core.NodeCtx() if nodeCtx != common.ZONE_CTX { @@ -266,7 +266,7 @@ func (b *QuaiAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *st vmConfig = b.quai.core.GetVMConfig() } txContext := core.NewEVMTxContext(msg) - context, err := core.NewEVMBlockContext(header, b.quai.Core(), nil) + context, err := core.NewEVMBlockContext(header, parent, b.quai.Core(), nil) if err != nil { return nil, vmError, err } diff --git a/quai/filters/api.go b/quai/filters/api.go index 5884d72223..54e736ac7f 100644 --- a/quai/filters/api.go +++ b/quai/filters/api.go @@ -34,6 +34,7 @@ import ( "github.com/dominant-strategies/go-quai/event" "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/rpc" + "google.golang.org/protobuf/proto" ) const ( @@ -679,8 +680,15 @@ func (api *PublicFilterAPI) PendingHeader(ctx context.Context) (*rpc.Subscriptio // Only keep the Header in the body pendingHeaderForMining := b.WithBody(b.Header(), nil, nil, nil, nil, nil) // Marshal the response. - marshalHeader := pendingHeaderForMining.RPCMarshalWorkObject() - notifier.Notify(rpcSub.ID, marshalHeader) + protoWo, err := pendingHeaderForMining.ProtoEncode(types.PEtxObject) + if err != nil { + return + } + data, err := proto.Marshal(protoWo) + if err != nil { + return + } + notifier.Notify(rpcSub.ID, data) }() case <-rpcSub.Err(): headerSub.Unsubscribe() diff --git a/quaiclient/ethclient/ethclient.go b/quaiclient/ethclient/ethclient.go index 6955d14394..cac5f5d44c 100644 --- a/quaiclient/ethclient/ethclient.go +++ b/quaiclient/ethclient/ethclient.go @@ -333,6 +333,12 @@ func (ec *Client) BalanceAt(ctx context.Context, account common.MixedcaseAddress return (*big.Int)(&result), err } +func (ec *Client) GetOutpointsByAddress(ctx context.Context, address common.MixedcaseAddress) (map[string]*types.OutpointAndDenomination, error) { + var outpoints map[string]*types.OutpointAndDenomination + err := ec.c.CallContext(ctx, &outpoints, "quai_getOutpointsByAddress", address.Original()) + return outpoints, err +} + // StorageAt returns the value of key in the contract storage of the given account. // The block number can be nil, in which case the value is taken from the latest known block. func (ec *Client) StorageAt(ctx context.Context, account common.MixedcaseAddress, key common.Hash, blockNumber *big.Int) ([]byte, error) { diff --git a/quaiclient/quaiclient.go b/quaiclient/quaiclient.go index e354b37c3f..3c4c4a4eca 100644 --- a/quaiclient/quaiclient.go +++ b/quaiclient/quaiclient.go @@ -30,6 +30,7 @@ import ( "github.com/dominant-strategies/go-quai/core/types" "github.com/dominant-strategies/go-quai/log" "github.com/dominant-strategies/go-quai/rpc" + "google.golang.org/protobuf/proto" ) var exponentialBackoffCeilingSecs int64 = 60 // 1 minute @@ -87,7 +88,7 @@ func (ec *Client) Close() { } // SubscribePendingHeader subscribes to notifications about the current pending block on the node. -func (ec *Client) SubscribePendingHeader(ctx context.Context, ch chan<- *types.WorkObject) (quai.Subscription, error) { +func (ec *Client) SubscribePendingHeader(ctx context.Context, ch chan<- []byte) (quai.Subscription, error) { return ec.c.QuaiSubscribe(ctx, ch, "pendingHeader") } @@ -115,23 +116,47 @@ func (ec *Client) HeaderByNumber(ctx context.Context, number string) *types.Head // GetPendingHeader gets the latest pending header from the chain. func (ec *Client) GetPendingHeader(ctx context.Context) (*types.WorkObject, error) { - var pendingHeader *types.WorkObject - err := ec.c.CallContext(ctx, &pendingHeader, "quai_getPendingHeader") + var raw hexutil.Bytes + err := ec.c.CallContext(ctx, &raw, "quai_getPendingHeader") if err != nil { return nil, err } - return pendingHeader, nil + protoWo := &types.ProtoWorkObject{} + err = proto.Unmarshal(raw, protoWo) + if err != nil { + return nil, err + } + wo := &types.WorkObject{} + err = wo.ProtoDecode(protoWo, protoWo.GetWoHeader().GetLocation().Value, types.PEtxObject) + if err != nil { + return nil, err + } + return wo, nil } // ReceiveMinedHeader sends a mined block back to the node func (ec *Client) ReceiveMinedHeader(ctx context.Context, header *types.WorkObject) error { - data := header.RPCMarshalWorkObject() - return ec.c.CallContext(ctx, nil, "quai_receiveMinedHeader", data) + protoWo, err := header.ProtoEncode(types.PEtxObject) + if err != nil { + return err + } + data, err := proto.Marshal(protoWo) + if err != nil { + return err + } + return ec.c.CallContext(ctx, nil, "quai_receiveMinedHeader", hexutil.Bytes(data)) } func (ec *Client) ReceiveWorkShare(ctx context.Context, header *types.WorkObjectHeader) error { - data := header.RPCMarshalWorkObjectHeader() - return ec.c.CallContext(ctx, nil, "quai_receiveWorkShare", data) + protoWs, err := header.ProtoEncode() + if err != nil { + return err + } + data, err := proto.Marshal(protoWs) + if err != nil { + return err + } + return ec.c.CallContext(ctx, nil, "quai_receiveWorkShare", hexutil.Bytes(data)) } // Filters diff --git a/quaistats/quaistats.go b/quaistats/quaistats.go index 01e5a9138d..f49532c943 100644 --- a/quaistats/quaistats.go +++ b/quaistats/quaistats.go @@ -1067,9 +1067,10 @@ type BatchObject struct { func (s *Service) cacheBlock(block *types.WorkObject) cachedBlock { txCount := float64(len(block.Transactions())) - quaiTxCount := float64(len(block.QuaiTransactions())) - qiTxCount := float64(len(block.QiTransactions())) - extTxInCount := float64(len(block.Body().ExternalTransactions())) + txInfo := block.TransactionsInfo() + quaiTxCount := float64(txInfo["quai"].(int)) + qiTxCount := float64(txInfo["qi"].(int)) + extTxInCount := float64(txInfo["etxInbound"].(int)) currentBlock := cachedBlock{ number: block.NumberU64(s.backend.NodeCtx()), @@ -1257,15 +1258,15 @@ func (s *Service) assembleBlockDetailStats(block *types.WorkObject) *blockDetail } qiType := block.Coinbase().IsInQiLedgerScope() difficulty := block.Difficulty().String() - quaiPerQi := misc.QiToQuai(block, big.NewInt(1)).String() + quaiPerQi := misc.QiToQuai(block.WorkObjectHeader(), big.NewInt(1)).String() var quaiReward *big.Int var qiReward *big.Int if qiType { - qiReward = misc.CalculateReward(block) - quaiReward = misc.QiToQuai(block, qiReward) + qiReward = misc.CalculateReward(block.WorkObjectHeader()) + quaiReward = misc.QiToQuai(block.WorkObjectHeader(), qiReward) } else { - quaiReward = misc.CalculateReward(block) - qiReward = misc.QuaiToQi(block, quaiReward) + quaiReward = misc.CalculateReward(block.WorkObjectHeader()) + qiReward = misc.QuaiToQi(block.WorkObjectHeader(), quaiReward) } // Assemble and return the block stats