33
44interface IOracle :
55 def get (systemid: uint8 , cid: uint64 , typ: uint16 ) -> (uint256 , uint64 , uint48 ): view
6- #def storeValues(dat: DynArray[uint8, 256]): nonpayable
76 def storeValues (dat: Bytes[16384 ]): nonpayable
7+ def storeValuesWithReceipt (dat: Bytes[16384 ]) -> DynArray[RecordReceipt, MAX_PAYLOADS]: nonpayable
88
99event OracleUpdated:
1010 updater: address
1111 chain_id: uint64
12- new_value: uint256
12+ new_value: uint240
1313 deviation: uint256
1414 time_since: uint256
1515 time_reward: uint256
@@ -35,12 +35,19 @@ struct Reward:
3535 time_reward: uint256
3636 deviation_reward: uint256
3737
38+ struct EnhancedReward :
39+ chain_id: uint64
40+ height: uint64
41+ gas_price: uint240
42+ time_reward: uint256
43+ deviation_reward: uint256
44+
3845struct TotalRewards :
3946 updater: address
4047 total_rewards: uint256
4148
4249BASEFEE_REWARD_TYPE: public (constant (uint16 )) = 107
43- MAX_PAYLOADS: public (constant (uint16 )) = 64
50+ MAX_PAYLOADS: public (constant (uint256 )) = 32
4451MAX_UPDATERS: public (constant (uint32 )) = 2 ** 16
4552MAX_PAYLOAD_SIZE: public (constant (uint256 )) = 16384
4653
@@ -67,12 +74,8 @@ n_updaters: public(uint32)
6774frozen: public (bool )
6875oracle: public (IOracle)
6976
70- #error_integral: public(int256)
7177error_integral: public (HashMap[uint64 , int256 ])
7278last_output: public (HashMap[uint64 , int256 ])
73- #last_p_output: public(HashMap[uint64, int256])
74- #last_i_output: public(HashMap[uint64, int256])
75- #last_update_time: public(HashMap[uint64, uint256])
7679
7780rewards: public (HashMap[address , uint256 ])
7881total_rewards: public (uint256 )
@@ -83,7 +86,6 @@ index: HashMap[uint64, uint256] # Pointer to next insert position (0 to N-1)
8386count: HashMap[uint64 , uint256 ] # Number of elements inserted so far, up to N
8487rolling_sum: HashMap[uint64 , uint256 ] # Sum of last N values for efficient averaging
8588
86- #coeff: public(int96[4])
8789coeff: public (Coefficients)
8890intercept: public (int256 )
8991
@@ -260,7 +262,6 @@ def _decode(dat: Bytes[MAX_PAYLOAD_SIZE], tip_typ: uint16) -> (uint8, uint64, ui
260262
261263 return sid, cid, basefee_val, tip_val, ts, h
262264
263-
264265@internal
265266@view
266267def _riemann_sum (x: int256 , y: int256 )-> int256 :
@@ -397,130 +398,120 @@ def get_updaters_chunk(start: uint256, count: uint256) -> (address[256], uint256
397398
398399 return result_updaters, result_rewards
399400
400- @external
401- def update_oracles (dat_many: Bytes[MAX_PAYLOAD_SIZE], n: uint256 )-> Reward[MAX_PAYLOADS]:
402- return self ._update_oracles (dat_many, n)
403-
404- @internal
405- def _update_oracles (dat_many: Bytes[MAX_PAYLOAD_SIZE], n: uint256 )-> Reward[MAX_PAYLOADS]:
406- assert not self .frozen, "rewards contract is frozen "
407- self ._add_updater (msg .sender )
408- offset: uint256 = 0
409- plen: uint16 = 0
410-
411- time_reward: uint256 = 0
412- deviation_reward: uint256 = 0
413-
414- rewards: Reward[MAX_PAYLOADS] = empty (Reward[MAX_PAYLOADS])
415-
416- dat_p: Bytes[MAX_PAYLOAD_SIZE] = b""
417- l: uint256 = len (dat_many)
418-
419- for i: uint256 in range (n, bound= 16 ):
420- dat_p = slice (dat_many, offset, l- offset)
421- plen = self ._decode_plen (dat_p)
422- if plen == 0 :
423- assert i == n - 1 , "plen is zero before n is reached "
424- break
425-
426- payload_size: uint256 = 32 + convert (plen, uint256 )* 32 + 65
427- time_reward, deviation_reward = self ._update_oracle (dat_p, payload_size)
428- #time_reward, deviation_reward = self._update_oracle(slice(dat_p, offset, offset + payload_size), payload_size)
429- rewards[i] = Reward (time_reward= time_reward, deviation_reward= deviation_reward)
430-
431- # add full payload size
432- offset += 32 + convert (plen, uint256 )* 32 + 65
433-
434- return rewards
401+ struct RecordReceipt :
402+ systemid: uint8
403+ cid: uint64
404+ typ: uint16
405+ old_height: uint64
406+ old_timestamp: uint48
407+ old_value: uint240
408+ new_height: uint64
409+ new_timestamp: uint48
410+ new_value: uint240
435411
436412@external
437- def update_oracle (dat: Bytes[MAX_PAYLOAD_SIZE])-> Reward:
438- assert not self .frozen, "rewards contract is frozen "
439- self ._add_updater (msg .sender )
440- return self ._update_oracles (dat, 1 )[0 ]
441-
442- @internal
443- def copy_bytes_to_dynarray (src: Bytes[MAX_PAYLOAD_SIZE], start: uint256 , length: uint256 ) -> DynArray[uint8 , MAX_PAYLOAD_SIZE]:
444- assert start + length <= len (src), "out of bounds "
445-
446- result: DynArray[uint8 , MAX_PAYLOAD_SIZE] = []
447- for i: uint256 in range (length, bound= MAX_PAYLOAD_SIZE):
448- b: uint8 = convert (slice (src, start + i, 1 ), uint8 )
449- result.append (b)
450-
451- return result
452-
453- @internal
454- def _update_oracle_stub (dat: Bytes[MAX_PAYLOAD_SIZE], l: uint256 )-> (uint256 , uint256 ):
455- tip_typ: uint16 = self .tip_reward_type
456- return 0 , 0
457-
458- @internal
459- def _update_oracle (dat: Bytes[MAX_PAYLOAD_SIZE], l: uint256 )-> (uint256 , uint256 ):
460- tip_typ: uint16 = self .tip_reward_type
461- sid: uint8 = 0
413+ def update_many (dat: Bytes[MAX_PAYLOAD_SIZE])-> EnhancedReward[MAX_PAYLOADS]:
414+ receipts: DynArray[RecordReceipt, MAX_PAYLOADS] = extcall self .oracle.storeValuesWithReceipt (dat)
415+ rewards: EnhancedReward[MAX_PAYLOADS] = empty (EnhancedReward[MAX_PAYLOADS])
462416 cid: uint64 = 0
463417 typ: uint16 = 0
464- new_basefee_value: uint240 = 0
465- new_tip_value: uint240 = 0
466- new_ts: uint48 = 0
467- new_height: uint64 = 0
468-
469- # decode data and get new values
470- sid, cid, new_basefee_value, new_tip_value, new_ts, new_height = self ._decode (dat, tip_typ)
471-
472- new_tip_value_u: uint256 = convert (new_tip_value, uint256 )
473- new_basefee_value_u: uint256 = convert (new_basefee_value, uint256 )
474- new_gasprice_value: uint256 = new_basefee_value_u + new_tip_value_u
475-
476- current_gasprice_value: uint256 = 0
477- current_basefee_value: uint256 = 0
478- current_tip_value: uint256 = 0
479- current_height: uint64 = 0
480- current_ts: uint48 = 0
481-
482- # current oracle values
483- (current_basefee_value, current_height, current_ts) = staticcall self .oracle.get (sid, cid, BASEFEE_REWARD_TYPE)
484- (current_tip_value, current_height, current_ts) = staticcall self .oracle.get (sid, cid, tip_typ)
485- current_gasprice_value = current_basefee_value + current_tip_value
486-
487- if not (new_height > current_height or (new_height == current_height and new_ts > current_ts)):
488- return 0 , 0
489-
490- # calculate deviation and staleness(time_since) for new values
491- deviation: uint256 = self ._calc_deviation (cid, new_gasprice_value, current_gasprice_value)
492- time_since: uint256 = convert (new_ts - current_ts, uint256 ) * EIGHTEEN_DECIMAL_NUMBER_U
493-
494- # calculate reward
418+ rec: RecordReceipt = empty (RecordReceipt)
419+ old_tip_val: uint240 = 0
420+ old_bf_val: uint240 = 0
421+ new_tip_val: uint240 = 0
422+ new_bf_val: uint240 = 0
423+
424+ bf_found: bool = False
425+ tip_found: bool = False
426+
427+ current_gasprice: uint240 = 0
428+ new_gasprice: uint240 = 0
429+ deviation: uint256 = 0
430+ time_since: uint256 = 0
495431 time_reward: int256 = 0
496432 deviation_reward: int256 = 0
497- time_reward, deviation_reward = self ._calc_reward (convert (time_since, int256 )// 1000 , convert (deviation, int256 ))
498-
499- # calculate reward multiplier
500- reward_mult: int256 = self ._calc_reward_mult (cid, time_since// 1000 )
501-
502- # adjust rewards with multiplier
503- time_reward_adj: int256 = reward_mult * time_reward // EIGHTEEN_DECIMAL_NUMBER
504- deviation_reward_adj: int256 = reward_mult * deviation_reward // EIGHTEEN_DECIMAL_NUMBER
505-
506- time_reward_adj_u: uint256 = convert (time_reward_adj, uint256 )
507- deviation_reward_adj_u: uint256 = convert (deviation_reward_adj, uint256 )
508-
509- # store rewards
510- self .rewards[msg .sender ] += time_reward_adj_u + deviation_reward_adj_u
511- self .total_rewards += time_reward_adj_u + deviation_reward_adj_u
512-
513- log OracleUpdated (updater= msg .sender , chain_id= cid, new_value= new_gasprice_value,
514- deviation= deviation, time_since= time_since,
515- time_reward= time_reward_adj_u, deviation_reward= deviation_reward_adj_u,
516- reward_mult= reward_mult)
433+ reward_mult: int256 = 0
434+ time_reward_adj: int256 = 0
435+ deviation_reward_adj: int256 = 0
436+ time_reward_adj_u: uint256 = 0
437+ deviation_reward_adj_u: uint256 = 0
438+
439+ # self.tip_reward_type
440+ # BASEFEE_REWARD_TYPE
441+ idx: uint256 = 0
442+ for i: uint256 in range (len (receipts), bound= MAX_PAYLOADS):
443+ rec = receipts[i]
444+
445+ if rec.typ == self .tip_reward_type:
446+ old_tip_val = rec.old_value
447+ new_tip_val = rec.new_value
448+ tip_found = True
449+ elif rec.typ == BASEFEE_REWARD_TYPE:
450+ old_bf_val = rec.old_value
451+ new_bf_val = rec.new_value
452+ bf_found = True
453+
454+ # tip and bf found for this cid, time to process
455+ if not (tip_found and bf_found):
456+ continue
457+
458+ # reset these
459+ tip_found = False
460+ bf_found = False
461+
462+ current_gasprice = old_tip_val + old_bf_val
463+
464+ # no update
465+ if rec.old_timestamp == rec.new_timestamp:
466+ rewards[idx] = EnhancedReward (chain_id= rec.cid,
467+ height= rec.old_height,
468+ gas_price= current_gasprice,
469+ time_reward= 0 ,
470+ deviation_reward= 0 )
471+ continue
472+
473+ new_gasprice = new_tip_val + new_bf_val
474+
475+ # calculate deviation and staleness(time_since) for new values
476+ deviation = self ._calc_deviation (rec.cid, convert (new_gasprice, uint256 ), convert (current_gasprice, uint256 ))
477+
478+ time_since = convert (rec.new_timestamp - rec.old_timestamp, uint256 ) * EIGHTEEN_DECIMAL_NUMBER_U
479+
480+ # calculate reward
481+ time_reward, deviation_reward = self ._calc_reward (convert (time_since, int256 )// 1000 , convert (deviation, int256 ))
482+
483+ # calculate reward multiplier
484+ reward_mult = self ._calc_reward_mult (rec.cid, time_since// 1000 )
485+
486+ # adjust rewards with multiplier
487+ time_reward_adj = reward_mult * time_reward // EIGHTEEN_DECIMAL_NUMBER
488+ deviation_reward_adj = reward_mult * deviation_reward // EIGHTEEN_DECIMAL_NUMBER
489+
490+ time_reward_adj_u = convert (time_reward_adj, uint256 )
491+ deviation_reward_adj_u = convert (deviation_reward_adj, uint256 )
492+
493+ # store rewards
494+ self .rewards[msg .sender ] += time_reward_adj_u + deviation_reward_adj_u
495+ self .total_rewards += time_reward_adj_u + deviation_reward_adj_u
496+
497+ log OracleUpdated (updater= msg .sender , chain_id= rec.cid, new_value= new_gasprice,
498+ deviation= deviation, time_since= time_since,
499+ time_reward= time_reward_adj_u, deviation_reward= deviation_reward_adj_u,
500+ reward_mult= reward_mult)
501+
502+ rewards[idx] = EnhancedReward (chain_id= rec.cid,
503+ height= rec.old_height,
504+ gas_price= current_gasprice,
505+ time_reward= time_reward_adj_u,
506+ deviation_reward= deviation_reward_adj_u)
507+ idx += 1
517508
518- # send new values to oracle
519- #extcall self.oracle.storeValues(dat)
520- extcall self .oracle.storeValues (slice (dat, 0 , l))
521- #extcall self.oracle.storeValues(self.copy_bytes_to_dynarray(dat, 0, l))
509+ return rewards
522510
523- return time_reward_adj_u, deviation_reward_adj_u
511+ @internal
512+ def _update_oracle_stub (dat: Bytes[MAX_PAYLOAD_SIZE], l: uint256 )-> (uint256 , uint256 ):
513+ tip_typ: uint16 = self .tip_reward_type
514+ return 0 , 0
524515
525516@external
526517@view
@@ -575,10 +566,6 @@ def _get_window_size(chain_id: uint64) -> uint256:
575566 return self .default_window_size
576567 return value
577568
578- #@external
579- #def add_value(chain_id: uint64, new_value: uint256, count: uint256, window_size: uint256):
580- # self._add_value(chain_id, new_value, count, window_size)
581-
582569@internal
583570def _add_value (chain_id: uint64 , new_value: uint256 , count: uint256 , window_size: uint256 ):
584571 #Add a new value to the circular buffer and update rolling sum.
@@ -666,22 +653,12 @@ def _update(cid: uint64, error: int256) -> (int256, int256, int256):
666653
667654 bounded_pi_output: int256 = self ._bound_pi_output (pi_output)
668655
669- #self.error_integral[cid] = self._clamp_error_integral(cid, bounded_pi_output, new_error_integral, new_area)
670656 self .error_integral[cid] = self ._clamp_error_integral (bounded_pi_output, error_integral, new_error_integral, error)
671657
672- # could maybe remove these to save gas
673- #self.last_update_time[cid] = block.timestamp
674658 self .last_output[cid] = bounded_pi_output
675- #self.last_p_output[cid] = p_output
676- #self.last_i_output[cid] = i_output
677659
678660 return (bounded_pi_output, p_output, i_output)
679661
680- #@external
681- #@view
682- #def last_update(cid: uint64) -> (uint256, int256, int256, int256):
683- # return (self.last_update_time[cid], self.last_output[cid], self.last_p_output[cid], self.last_i_output[cid])
684-
685662@external
686663@view
687664def get_new_pi_output (cid: uint64 , error: int256 ) -> (int256 , int256 , int256 ):
@@ -702,8 +679,3 @@ def _get_new_pi_output(cid: uint64, error: int256) -> (int256, int256, int256):
702679 bounded_pi_output: int256 = self ._bound_pi_output (pi_output)
703680
704681 return (bounded_pi_output, p_output, i_output)
705-
706- #@external
707- #@view
708- #def elapsed(cid: uint64) -> uint256:
709- # return block.timestamp - self.last_update_time[cid]
0 commit comments