@@ -2,24 +2,12 @@ package price
22
33import (
44 "context"
5- "encoding/base64"
6- "encoding/hex"
75 "errors"
8- "fmt"
9- "log/slog"
106 "math"
11- "slices"
127 "strings"
138 "time"
14- "vsc-node/lib/dids"
15- "vsc-node/modules/common"
16- "vsc-node/modules/db/vsc/elections"
179 "vsc-node/modules/oracle/p2p"
1810 "vsc-node/modules/oracle/price/api"
19- stateEngine "vsc-node/modules/state-processing"
20- transactionpool "vsc-node/modules/transaction-pool"
21-
22- blsu "github.com/protolambda/bls12-381-util"
2311)
2412
2513type CollectedPricePoint struct {
@@ -81,7 +69,6 @@ func (o *PriceOracle) HandleBlockTick(
8169 }
8270 }
8371
84- // make transaction
8572 var handler interface {
8673 handle (map [string ]api.PricePoint ) error
8774 }
@@ -167,284 +154,4 @@ func (o *PriceOracle) collectAveragePricePoints(
167154 }
168155}
169156
170- // block producer
171- type Producer struct {
172- p2p.OracleP2PSpec
173- ctx context.Context
174- logger * slog.Logger
175- blockTickSignal p2p.BlockTickSignal
176- signatureChannel * SignatureResponseChannel
177- }
178-
179- func (p * Producer ) handle (medianPriceMap map [string ]api.PricePoint ) error {
180- p .logger .Debug ("making block" , "median-prices" , medianPriceMap )
181-
182- tx , err := makeTx (medianPriceMap )
183- if err != nil {
184- return fmt .Errorf ("failed to create tx: %w" , err )
185- }
186-
187- // broadcast signature request
188- sigRequestMsg := SignatureRequestMessage {
189- SigHash : tx .String (),
190- MedianPrice : medianPriceMap ,
191- }
192-
193- msg , err := makePriceOracleMessage (signatureRequestCode , & sigRequestMsg )
194- if err != nil {
195- return fmt .Errorf ("failed to make message: %w" , err )
196- }
197-
198- if err := p .Broadcast (p2p .MsgPriceOracle , msg ); err != nil {
199- return fmt .Errorf ("failed to broadcast signature request: %w" , err )
200- }
201- p .logger .Debug (
202- "signature request broadcasted" ,
203- "sig-hash" , sigRequestMsg .SigHash ,
204- "median-price" , sigRequestMsg .MedianPrice ,
205- )
206-
207- // make bls circuit
208- txCid := tx .Cid ()
209-
210- witnessDIDs := make ([]dids.Member , len (p .blockTickSignal .ElectedMembers ))
211- for i := range p .blockTickSignal .ElectedMembers {
212- witnessDIDs [i ] = dids .BlsDID (p .blockTickSignal .ElectedMembers [i ].Key )
213- }
214-
215- circuit , err := dids .NewBlsCircuitGenerator (witnessDIDs ).Generate (txCid )
216- if err != nil {
217- return fmt .Errorf ("failed to generate bls circuit: %w" , err )
218- }
219-
220- // collect and verify signatures with bls circuit
221-
222- ctx , cancel := context .WithTimeout (p .ctx , 15 * time .Second )
223- defer cancel ()
224-
225- if err := p .collectSignature (ctx , circuit ); err != nil {
226- return fmt .Errorf ("failed to collect signatures: %w" , err )
227- }
228-
229- // make transaction + submit to contract
230- blsCircuit , err := circuit .Finalize ()
231- if err != nil {
232- return fmt .Errorf ("failed to finalize circuit: %w" , err )
233- }
234-
235- serializedCircuit , err := blsCircuit .Serialize ()
236- if err != nil {
237- return fmt .Errorf ("failed to finalize circuit: %w" , err )
238- }
239-
240- sigPackage := stateEngine.TransactionSig {
241- Type : "vsc-sig" ,
242- Sigs : []common.Sig {{
243- Algo : "bls-agg" ,
244- Sig : serializedCircuit .Signature ,
245- Bv : serializedCircuit .BitVector ,
246- Kid : "" ,
247- }},
248- }
249-
250- sigBytes , err := common .EncodeDagCbor (sigPackage )
251- if err != nil {
252- return fmt .Errorf ("failed encode DagCbor: %w" , err )
253- }
254-
255- // submit contract
256- vscTx := transactionpool.SerializedVSCTransaction {
257- Tx : txCid .Bytes (),
258- Sig : sigBytes ,
259- }
260-
261- if err := p .submitToContract (vscTx ); err != nil {
262- return fmt .Errorf ("failed to submit to contract: %w" , err )
263- }
264-
265- return nil
266- }
267-
268- func (p * Producer ) collectSignature (
269- ctx context.Context ,
270- circuit dids.PartialBlsCircuit ,
271- ) error {
272- signatureThreshold := (p .blockTickSignal .TotalElectionWeight * 2 ) / 3
273- signedWeight := uint64 (0 )
274-
275- p .logger .Debug (
276- "collecting signatures" ,
277- "signature-threshold" , signatureThreshold ,
278- )
279-
280- receiver := p .signatureChannel .Open ()
281- defer p .signatureChannel .Close ()
282-
283- for signedWeight < signatureThreshold {
284- select {
285- case <- ctx .Done ():
286- if err := ctx .Err (); err != nil {
287- return fmt .Errorf ("context error: %w" , err )
288- } else {
289- return errors .New ("signature collection timed out" )
290- }
291-
292- case msg := <- receiver :
293- memberIndex := slices .IndexFunc (
294- p .blockTickSignal .ElectedMembers ,
295- func (e elections.ElectionMember ) bool {
296- return e .Account == msg .Signer
297- },
298- )
299-
300- if memberIndex == - 1 {
301- p .logger .Debug (
302- "invalid witness signature, dropping." ,
303- "signer" , msg .Signer ,
304- )
305- continue
306- }
307-
308- member := & p .blockTickSignal .ElectedMembers [memberIndex ]
309- memberDID := dids .BlsDID (member .Key )
310-
311- added , err := circuit .AddAndVerify (memberDID , msg .Signature )
312- if err != nil {
313- p .logger .Error ("failed to verify signature" , "err" , err )
314- continue
315- }
316-
317- if ! added {
318- p .logger .Debug ("invalid signature, signature not added to circuit" )
319- continue
320- }
321-
322- signedWeight += p .blockTickSignal .WeightMap [memberIndex ]
323- p .logger .Debug (
324- "received witness signature, appending to witnessSigned" ,
325- "signer" , member .Account , "signature" , msg .Signature ,
326- )
327- }
328- }
329-
330- return nil
331- }
332-
333- // TODO: implement this function
334- func (p * Producer ) submitToContract (transactionpool.SerializedVSCTransaction ) error {
335- p .logger .Error ("submit to contract not implemented" )
336- return nil
337- }
338-
339157// witness
340- type Witness struct {
341- p2p.OracleP2PSpec
342- ctx context.Context
343- logger * slog.Logger
344- blockTickSignal p2p.BlockTickSignal
345- signatureRequestChannel * SignatureRequestChannel
346- identity common.IdentityConfig
347- }
348-
349- func (w * Witness ) handle (medianPriceMap map [string ]api.PricePoint ) error {
350- w .logger .Debug (
351- "witness median prices" ,
352- "median-prices" , medianPriceMap ,
353- )
354-
355- // receiving median price
356- receiver := w .signatureRequestChannel .Open ()
357- defer w .signatureRequestChannel .Close ()
358-
359- ctx , cancel := context .WithTimeout (w .ctx , 30 * time .Second )
360- defer cancel ()
361-
362- var signatureRequest SignatureRequestMessage
363- select {
364- case <- ctx .Done ():
365- return ctx .Err ()
366-
367- case signatureRequest = <- receiver :
368- w .logger .Debug ("signature request received" )
369- }
370-
371- w .logger .Debug ("signature request received" ,
372- "median-price" , signatureRequest .MedianPrice ,
373- "signature-hash" , signatureRequest .SigHash ,
374- )
375-
376- // compare broadcasted vs local median price
377- for sym , pricePoint := range signatureRequest .MedianPrice {
378- localPricePoint , ok := medianPriceMap [sym ]
379- if ! ok {
380- return fmt .Errorf ("failed to verify median price point for ticker %s" , sym )
381- }
382-
383- priceOk := floatEqual (pricePoint .Price , localPricePoint .Price )
384- if ! priceOk {
385- return fmt .Errorf ("failed to verify median price for ticker %s" , sym )
386- }
387-
388- volumeOk := floatEqual (pricePoint .Volume , localPricePoint .Volume )
389- if ! volumeOk {
390- return fmt .Errorf ("failed to verify median volume for ticker %s" , sym )
391- }
392- }
393-
394- w .logger .Debug ("median price verified" , "broadcasted-median-price" , signatureRequest .MedianPrice )
395-
396- // make tx + verify incoming sig hash
397- tx , err := makeTx (signatureRequest .MedianPrice )
398- if err != nil {
399- return fmt .Errorf ("failed to create transaction: %w" , err )
400- }
401-
402- txCid := tx .Cid ()
403- sigHashOk := signatureRequest .SigHash == txCid .String ()
404- if ! sigHashOk {
405- return fmt .Errorf ("invalid signature hash" )
406- }
407-
408- w .logger .Debug ("signature hash verified" , "sig-hash" , signatureRequest .SigHash )
409-
410- // sign data
411- blsKeyDecoded , err := hex .DecodeString (w .identity .Get ().BlsPrivKeySeed )
412- if err != nil {
413- return fmt .Errorf ("failed to decode BLS private key seed: %w" , err )
414- }
415-
416- if len (blsKeyDecoded ) != 32 {
417- return errors .New ("bls priv seed must be 32 bytes" )
418- }
419-
420- var blsKeyBuf [32 ]byte
421- copy (blsKeyBuf [:], blsKeyDecoded )
422-
423- blsSecretKey := & blsu.SecretKey {}
424- if err := blsSecretKey .Deserialize (& blsKeyBuf ); err != nil {
425- return fmt .Errorf ("failed to deserialize bls priv key: %w" , err )
426- }
427-
428- sigBytes := blsu .Sign (blsSecretKey , txCid .Bytes ()).Serialize ()
429-
430- // broadcast signature
431- signatureResponse := & SignatureResponseMessage {
432- Signer : w .identity .Get ().HiveUsername ,
433- Signature : base64 .RawURLEncoding .EncodeToString (sigBytes [:]),
434- }
435-
436- msg , err := makePriceOracleMessage (signatureResponseCode , signatureResponse )
437- if err != nil {
438- return fmt .Errorf ("failed to make price oracle message: %w" , err )
439- }
440-
441- if err := w .Broadcast (p2p .MsgPriceOracle , msg ); err != nil {
442- return fmt .Errorf ("failed to broadcast signature response: %w" , err )
443- }
444- w .logger .Debug (
445- "signature response broadcasted" ,
446- "signature" , signatureResponse .Signature ,
447- )
448-
449- return nil
450- }
0 commit comments