From 3ca4ff703dc617d31029b3dfbc9930301a3cf3a1 Mon Sep 17 00:00:00 2001 From: lukechampine Date: Thu, 14 Sep 2023 22:13:25 -0400 Subject: [PATCH] gateway: Refactor outlining --- gateway/encoding.go | 24 +++++++++----- gateway/gateway.go | 76 +++++++++++++++++++++++++++++++-------------- gateway/peer.go | 4 +-- 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/gateway/encoding.go b/gateway/encoding.go index d4950240..fa8ab506 100644 --- a/gateway/encoding.go +++ b/gateway/encoding.go @@ -84,24 +84,32 @@ func (h *V2BlockHeader) decodeFrom(d *types.Decoder) { } func (ot *OutlineTransaction) encodeTo(e *types.Encoder) { - ot.Hash.EncodeTo(e) if ot.Transaction != nil { - e.WriteBool(true) + e.WriteUint8(0) ot.Transaction.EncodeTo(e) - } else { - e.WriteBool(false) + } else if ot.V2Transaction != nil { + e.WriteUint8(1) ot.V2Transaction.EncodeTo(e) + } else { + e.WriteUint8(2) + ot.Hash.EncodeTo(e) } } func (ot *OutlineTransaction) decodeFrom(d *types.Decoder) { - ot.Hash.DecodeFrom(d) - if d.ReadBool() { + switch t := d.ReadUint8(); t { + case 0: ot.Transaction = new(types.Transaction) ot.Transaction.DecodeFrom(d) - } else { + ot.Hash = ot.Transaction.FullHash() + case 1: ot.V2Transaction = new(types.V2Transaction) ot.V2Transaction.DecodeFrom(d) + ot.Hash = ot.V2Transaction.FullHash() + case 2: + ot.Hash.DecodeFrom(d) + default: + d.SetErr(fmt.Errorf("invalid outline transaction type (%d)", t)) } } @@ -484,6 +492,8 @@ func objectForID(id types.Specifier) object { case idSendTransactions: return new(RPCSendTransactions) case idRelayV2Header: + return new(RPCRelayV2Header) + case idRelayV2BlockOutline: return new(RPCRelayV2BlockOutline) case idRelayV2TransactionSet: return new(RPCRelayV2TransactionSet) diff --git a/gateway/gateway.go b/gateway/gateway.go index 8edc1806..0f2f2855 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -130,26 +130,26 @@ type V2BlockOutline struct { Transactions []OutlineTransaction } -func (pb V2BlockOutline) commitment(cs consensus.State) types.Hash256 { +func (bo V2BlockOutline) commitment(cs consensus.State) types.Hash256 { var acc blake2b.Accumulator - for _, txn := range pb.Transactions { + for _, txn := range bo.Transactions { acc.AddLeaf(txn.Hash) } - return cs.Commitment(acc.Root(), pb.MinerAddress) + return cs.Commitment(acc.Root(), bo.MinerAddress) } // ID returns a hash that uniquely identifies the block. -func (pb V2BlockOutline) ID(cs consensus.State) types.BlockID { +func (bo V2BlockOutline) ID(cs consensus.State) types.BlockID { return (&types.Block{ - Nonce: pb.Nonce, - Timestamp: pb.Timestamp, - V2: &types.V2BlockData{Commitment: pb.commitment(cs)}, + Nonce: bo.Nonce, + Timestamp: bo.Timestamp, + V2: &types.V2BlockData{Commitment: bo.commitment(cs)}, }).ID() } // Missing returns the hashes of transactions that are missing from the block. -func (pb V2BlockOutline) Missing() (missing []types.Hash256) { - for _, txn := range pb.Transactions { +func (bo V2BlockOutline) Missing() (missing []types.Hash256) { + for _, txn := range bo.Transactions { if txn.Transaction == nil && txn.V2Transaction == nil { missing = append(missing, txn.Hash) } @@ -160,7 +160,7 @@ func (pb V2BlockOutline) Missing() (missing []types.Hash256) { // Complete attempts to reconstruct the original block using the supplied // transactions. If the block cannot be fully reconstructed, it returns the // hashes of the missing transactions. -func (pb *V2BlockOutline) Complete(cs consensus.State, txns []types.Transaction, v2txns []types.V2Transaction) (types.Block, []types.Hash256) { +func (bo *V2BlockOutline) Complete(cs consensus.State, txns []types.Transaction, v2txns []types.V2Transaction) (types.Block, []types.Hash256) { var v1hashes map[types.Hash256]types.Transaction var v2hashes map[types.Hash256]types.V2Transaction completeTxn := func(ptxn *OutlineTransaction) { @@ -190,17 +190,17 @@ func (pb *V2BlockOutline) Complete(cs consensus.State, txns []types.Transaction, } b := types.Block{ - ParentID: pb.ParentID, - Nonce: pb.Nonce, - Timestamp: pb.Timestamp, - MinerPayouts: []types.SiacoinOutput{{Address: pb.MinerAddress, Value: cs.BlockReward()}}, + ParentID: bo.ParentID, + Nonce: bo.Nonce, + Timestamp: bo.Timestamp, + MinerPayouts: []types.SiacoinOutput{{Address: bo.MinerAddress, Value: cs.BlockReward()}}, V2: &types.V2BlockData{ - Height: pb.Height, - Commitment: pb.commitment(cs), + Height: bo.Height, + Commitment: bo.commitment(cs), }, } - for i := range pb.Transactions { - ptxn := &pb.Transactions[i] + for i := range bo.Transactions { + ptxn := &bo.Transactions[i] completeTxn(ptxn) if ptxn.Transaction != nil { b.Transactions = append(b.Transactions, *ptxn.Transaction) @@ -212,11 +212,11 @@ func (pb *V2BlockOutline) Complete(cs consensus.State, txns []types.Transaction, b.MinerPayouts[0].Value = b.MinerPayouts[0].Value.Add(ptxn.V2Transaction.MinerFee) } } - return b, pb.Missing() + return b, bo.Missing() } // RemoveTransactions removes the specified transactions from the block. -func (pb *V2BlockOutline) RemoveTransactions(txns []types.Transaction, v2txns []types.V2Transaction) { +func (bo *V2BlockOutline) RemoveTransactions(txns []types.Transaction, v2txns []types.V2Transaction) { remove := make(map[types.Hash256]bool) for _, txn := range txns { remove[txn.FullHash()] = true @@ -224,14 +224,42 @@ func (pb *V2BlockOutline) RemoveTransactions(txns []types.Transaction, v2txns [] for _, txn := range v2txns { remove[txn.FullHash()] = true } - for i := range pb.Transactions { - if remove[pb.Transactions[i].Hash] { - pb.Transactions[i].Transaction = nil - pb.Transactions[i].V2Transaction = nil + for i := range bo.Transactions { + if remove[bo.Transactions[i].Hash] { + bo.Transactions[i].Transaction = nil + bo.Transactions[i].V2Transaction = nil } } } +// OutlineBlock returns a block outline for b that omits the specified +// transactions. +func OutlineBlock(b types.Block, txns []types.Transaction, v2txns []types.V2Transaction) V2BlockOutline { + var otxns []OutlineTransaction + for _, txn := range b.Transactions { + otxns = append(otxns, OutlineTransaction{ + Hash: txn.FullHash(), + Transaction: &txn, + }) + } + for _, txn := range b.V2Transactions() { + otxns = append(otxns, OutlineTransaction{ + Hash: txn.FullHash(), + V2Transaction: &txn, + }) + } + bo := V2BlockOutline{ + Height: b.V2.Height, + ParentID: b.ParentID, + Nonce: b.Nonce, + Timestamp: b.Timestamp, + MinerAddress: b.MinerPayouts[0].Address, + Transactions: otxns, + } + bo.RemoveTransactions(txns, v2txns) + return bo +} + // Dial initiates the gateway handshake with a peer. func Dial(conn net.Conn, ourHeader Header) (*Peer, error) { p := &Peer{ diff --git a/gateway/peer.go b/gateway/peer.go index 96915a0b..33cf7ac5 100644 --- a/gateway/peer.go +++ b/gateway/peer.go @@ -104,7 +104,7 @@ type RPCHandler interface { // v2 Transactions(index types.ChainIndex, txns []types.Hash256) ([]types.Transaction, []types.V2Transaction, error) Checkpoint(index types.ChainIndex) (types.Block, consensus.State, error) - RelayV2BlockHeader(h V2BlockHeader, origin *Peer) + RelayV2Header(h V2BlockHeader, origin *Peer) RelayV2BlockOutline(b V2BlockOutline, origin *Peer) RelayV2TransactionSet(txns []types.V2Transaction, origin *Peer) } @@ -196,7 +196,7 @@ func (p *Peer) HandleRPC(id types.Specifier, stream net.Conn, h RPCHandler) erro if err := p.withDecoder(stream, r.maxRequestLen(), r.decodeRequest); err != nil { return err } - h.RelayV2BlockHeader(r.Header, p) + h.RelayV2Header(r.Header, p) return nil case *RPCRelayV2BlockOutline: if err := p.withDecoder(stream, r.maxRequestLen(), r.decodeRequest); err != nil {