github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/hotstuff/api.go (about) 1 package hotstuff 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 8 "github.com/bigzoro/my_simplechain/common/hexutil" 9 "github.com/bigzoro/my_simplechain/consensus" 10 bls "github.com/bigzoro/my_simplechain/consensus/hotstuff/bls12-381" 11 "github.com/bigzoro/my_simplechain/consensus/hotstuff/common" 12 "github.com/bigzoro/my_simplechain/rpc" 13 ) 14 15 type replica struct { 16 ID uint32 17 Pubkey hexutil.Bytes 18 } 19 20 // API is a user facing RPC API to send requests for replicas joining/removing to the 21 // Hotstuff network 22 type API struct { 23 chain consensus.ChainReader 24 council *Council 25 } 26 27 func (api *API) Add(expire rpc.BlockNumber, id uint32, pkbytes hexutil.Bytes, sigbytes hexutil.Bytes) error { 28 if header := api.chain.CurrentHeader(); uint64(expire) <= header.Number.Uint64() { 29 return fmt.Errorf("expired event for %d/%d", expire, header.Number.Uint64()) 30 } 31 32 ev := &event{ 33 kind: replicaJoined, 34 expire: uint64(expire), 35 } 36 ev.id.SetUint32(id) 37 ev.pubkey = new(bls.PublicKey) 38 if err := ev.pubkey.FromBytes(pkbytes); err != nil { 39 return err 40 } 41 ev.sig = new(bls.AggregateSignature) 42 if err := ev.sig.FromBytes(sigbytes); err != nil { 43 return err 44 } 45 return api.council.navigation.add(ev) 46 } 47 48 func (api *API) Remove(expire rpc.BlockNumber, id uint32, sigbytes hexutil.Bytes) error { 49 if header := api.chain.CurrentHeader(); uint64(expire) <= header.Number.Uint64() { 50 return fmt.Errorf("expired event for %d/%d", expire, header.Number.Uint64()) 51 } 52 53 ev := &event{ 54 kind: replicaRemoved, 55 expire: uint64(expire), 56 } 57 ev.id.SetUint32(id) 58 ev.sig = new(bls.AggregateSignature) 59 if err := ev.sig.FromBytes(sigbytes); err != nil { 60 return err 61 } 62 return api.council.navigation.add(ev) 63 } 64 65 func (api *API) ProposeAdd(expire rpc.BlockNumber, id uint32, pkbytes hexutil.Bytes) (hexutil.Bytes, error) { 66 raw := make([]byte, 8) 67 binary.LittleEndian.PutUint64(raw, uint64(expire)) 68 69 hotsid := new(common.ID) 70 hotsid.SetUint32(id) 71 72 sig, err := api.council.Sign(legacyCypherDigest([]byte{replicaJoined}, raw, hotsid.Bytes(), pkbytes).Bytes()) 73 if err != nil { 74 return nil, err 75 } 76 return sig.ToBytes() 77 } 78 79 func (api *API) ProposeRemove(expire rpc.BlockNumber, id uint32) (hexutil.Bytes, error) { 80 raw := make([]byte, 8) 81 binary.LittleEndian.PutUint64(raw, uint64(expire)) 82 83 hotsid := new(common.ID) 84 hotsid.SetUint32(id) 85 86 sig, err := api.council.Sign(legacyCypherDigest([]byte{replicaRemoved}, raw, hotsid.Bytes()).Bytes()) 87 if err != nil { 88 return nil, err 89 } 90 return sig.ToBytes() 91 } 92 93 func (api *API) GetReplicaInfo(expire rpc.BlockNumber) ([]replica, error) { 94 header := api.chain.GetHeaderByNumber(uint64(expire)) 95 if header == nil { 96 return nil, errors.New("unknown block") 97 } 98 99 snaphash, err := extractSnapshot(header, true) 100 if err != nil { 101 return nil, err 102 } 103 snap, err := api.council.snapshot(snaphash) 104 if err != nil { 105 return nil, err 106 } 107 108 reps := make([]replica, 0, len(snap.Idset)) 109 for i := range snap.Idset { 110 reps = append(reps, replica{ 111 ID: snap.Idset[i].Uint32(), 112 Pubkey: hexutil.Bytes(snap.Pubkeys[snap.Idset[i]].ToBytes()), 113 }) 114 } 115 116 return reps, nil 117 } 118 119 func (api *API) Aggregate(mulSigbytes []hexutil.Bytes) (hexutil.Bytes, error) { 120 sigs := make([]*bls.PartialSignature, 0, len(mulSigbytes)) 121 for _, sigbytes := range mulSigbytes { 122 sig := new(bls.PartialSignature) 123 if err := sig.FromBytes(sigbytes); err != nil { 124 return nil, err 125 } 126 sigs = append(sigs, sig) 127 } 128 129 aggr, err := bls.Combine(sigs...) 130 if err != nil { 131 return nil, err 132 } 133 return aggr.ToBytes() 134 }