github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/sequencesender/datacommittee.go (about)

     1  package sequencesender
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/0xPolygon/supernets2-data-availability/batch"
    11  	"github.com/0xPolygon/supernets2-data-availability/client"
    12  	"github.com/0xPolygon/supernets2-data-availability/sequence"
    13  	ethman "github.com/0xPolygon/supernets2-node/etherman"
    14  	"github.com/0xPolygon/supernets2-node/etherman/types"
    15  	jTypes "github.com/0xPolygon/supernets2-node/jsonrpc/types"
    16  	"github.com/0xPolygon/supernets2-node/log"
    17  	"github.com/ethereum/go-ethereum/common"
    18  )
    19  
    20  type signatureMsg struct {
    21  	addr      common.Address
    22  	signature []byte
    23  	err       error
    24  }
    25  
    26  func (s *SequenceSender) getSignaturesAndAddrsFromDataCommittee(ctx context.Context, sequences []types.Sequence) ([]byte, error) {
    27  	// Get current committee
    28  	committee, err := s.etherman.GetCurrentDataCommittee()
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	// Get last accInputHash
    34  	var accInputHash common.Hash
    35  	if sequences[0].BatchNumber != 0 {
    36  		prevBatch, err := s.state.GetBatchByNumber(ctx, sequences[0].BatchNumber-1, nil)
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  		accInputHash = prevBatch.AccInputHash
    41  	}
    42  
    43  	// Authenticate as trusted sequencer by signing the sequences
    44  	sequence := sequence.Sequence{
    45  		Batches:         []batch.Batch{},
    46  		OldAccInputHash: accInputHash,
    47  	}
    48  	for _, seq := range sequences {
    49  		sequence.Batches = append(sequence.Batches, batch.Batch{
    50  			Number:         jTypes.ArgUint64(seq.BatchNumber),
    51  			GlobalExitRoot: seq.GlobalExitRoot,
    52  			Timestamp:      jTypes.ArgUint64(seq.Timestamp),
    53  			Coinbase:       common.HexToAddress(s.cfg.SenderAddress),
    54  			L2Data:         seq.BatchL2Data,
    55  		})
    56  	}
    57  	signedSequence, err := sequence.Sign(s.privKey)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	// Request signatures to all members in parallel
    63  	ch := make(chan signatureMsg, len(committee.Members))
    64  	signatureCtx, cancelSignatureCollection := context.WithCancel(ctx)
    65  	for _, member := range committee.Members {
    66  		go requestSignatureFromMember(signatureCtx, *signedSequence, member, ch)
    67  	}
    68  
    69  	// Collect signatures
    70  	msgs := []signatureMsg{}
    71  	var collectedSignatures uint64
    72  	var failedToCollect uint64
    73  	for collectedSignatures < committee.RequiredSignatures {
    74  		msg := <-ch
    75  		if msg.err != nil {
    76  			log.Errorf("error when trying to get signature from %s: %s", msg.addr, msg.err)
    77  			failedToCollect++
    78  			if len(committee.Members)-int(failedToCollect) < int(committee.RequiredSignatures) {
    79  				cancelSignatureCollection()
    80  				return nil, errors.New("too many members failed to send their signature")
    81  			}
    82  		} else {
    83  			log.Infof("received signature from %s", msg.addr)
    84  			collectedSignatures++
    85  		}
    86  		msgs = append(msgs, msg)
    87  	}
    88  
    89  	// Stop requesting as soon as we have N valid signatures
    90  	cancelSignatureCollection()
    91  
    92  	return buildSignaturesAndAddrs(signatureMsgs(msgs), committee.Members), nil
    93  }
    94  
    95  func requestSignatureFromMember(ctx context.Context, signedSequence sequence.SignedSequence, member ethman.DataCommitteeMember, ch chan signatureMsg) {
    96  	// request
    97  	c := client.New(member.URL)
    98  	log.Infof("sending request to sign the sequence to %s at %s", member.Addr.Hex(), member.URL)
    99  	signature, err := c.SignSequence(signedSequence)
   100  	if err != nil {
   101  		ch <- signatureMsg{
   102  			addr: member.Addr,
   103  			err:  err,
   104  		}
   105  		return
   106  	}
   107  	// verify returned signature
   108  	signedSequence.Signature = signature
   109  	signer, err := signedSequence.Signer()
   110  	if err != nil {
   111  		ch <- signatureMsg{
   112  			addr: member.Addr,
   113  			err:  err,
   114  		}
   115  		return
   116  	}
   117  	if signer != member.Addr {
   118  		ch <- signatureMsg{
   119  			addr: member.Addr,
   120  			err:  fmt.Errorf("invalid signer. Expected %s, actual %s", member.Addr.Hex(), signer.Hex()),
   121  		}
   122  		return
   123  	}
   124  	ch <- signatureMsg{
   125  		addr:      member.Addr,
   126  		signature: signature,
   127  	}
   128  }
   129  
   130  func buildSignaturesAndAddrs(msgs signatureMsgs, members []ethman.DataCommitteeMember) []byte {
   131  	res := []byte{}
   132  	sort.Sort(msgs)
   133  	for _, msg := range msgs {
   134  		log.Debugf("adding signature %s from %s", common.Bytes2Hex(msg.signature), msg.addr.Hex())
   135  		res = append(res, msg.signature...)
   136  	}
   137  	for _, member := range members {
   138  		log.Debugf("adding addr %s", common.Bytes2Hex(member.Addr.Bytes()))
   139  		res = append(res, member.Addr.Bytes()...)
   140  	}
   141  	log.Debugf("full res %s", common.Bytes2Hex(res))
   142  	return res
   143  }
   144  
   145  type signatureMsgs []signatureMsg
   146  
   147  func (s signatureMsgs) Len() int { return len(s) }
   148  func (s signatureMsgs) Less(i, j int) bool {
   149  	return strings.ToUpper(s[i].addr.Hex()) < strings.ToUpper(s[j].addr.Hex())
   150  }
   151  func (s signatureMsgs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }