-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat staker v2 no fp and subpointers #67
Open
baitcode
wants to merge
37
commits into
EkuboProtocol:main
Choose a base branch
from
baitcode:feat-staker-v2-no-fp-and-subpointers
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
cb3e4dd
Initial implementation of staked seconds calculation
baitcode 01b3f73
a bit of naming
baitcode 924aef3
added upgrade method. NOTE: constructor changed. Staker now requires …
baitcode 88f8db8
fix import
baitcode 9553035
TODO: removal
baitcode aedb403
remove todo
baitcode 9ee9324
test
baitcode c3c0244
local settings
baitcode 692c36a
revert upgrade code for now
baitcode 349919e
removed upgrade due to cyclic dependency with governor
baitcode d6504e9
finalise
baitcode 5f32326
typo
baitcode b5ac50b
Added UFixedPoint type for unsigned FixedPoint operations. Currently …
baitcode 2f9516a
removed old tests
baitcode bb4f99a
* debugged fixed point math. added tests
baitcode 1a2d6fc
some comment fixes
baitcode b18d702
Extracted staker storage into separate file due to large amount of bo…
baitcode 7fdfb19
rename staker_storage -> staker_log. moved all relevant logic there
baitcode b82953f
Simplified Fixed Point operations library. Reduced internal storage s…
baitcode 80cf041
simplified more. better naming
baitcode f507631
clean up bitshifts from tests
baitcode 164f64f
overflow checks
baitcode 6e931c6
old tests did not respect overflow. had to create new ones.
baitcode fafba15
Debugging, cleaning up, fixing missed issues
baitcode b55b320
final fix
baitcode a28971c
final debugging
baitcode aa07801
cleanup
baitcode 61f085c
cleanup
baitcode f52fff1
removing UFixedPoint124x128 struct
baitcode 4cc807e
BugFix for a case when fetl252 is overflown
baitcode 7e35137
remove fixed point lib
baitcode 815d539
small fix
baitcode 284ae39
lost deletions
baitcode c6102a1
Review fixes
baitcode e3067ab
scarb fmt
baitcode f622f34
Review fixes
baitcode 56ec424
scarb format
baitcode File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
.env | ||
.vscode | ||
.starkli | ||
.DS_Store | ||
####### | ||
Scarb | ||
####### | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
use starknet::storage::MutableVecTrait; | ||
use starknet::storage::{ | ||
Mutable, StorageAsPath, StorageBase, StoragePointerReadAccess, StoragePointerWriteAccess, | ||
}; | ||
|
||
use starknet::storage::{Vec, VecTrait}; | ||
use starknet::storage_access::{StorePacking}; | ||
use starknet::{get_block_timestamp}; | ||
|
||
pub type StakingLog = Vec<StakingLogRecord>; | ||
|
||
const TWO_POW_32: u64 = 0x100000000_u64; | ||
const MASK_32_BITS: u128 = 0x100000000_u128 - 1; | ||
const TWO_POW_160: u256 = 0x10000000000000000000000000000000000000000; | ||
pub const MAX_FP: u128 = 0x8000000000000110000000000000000_u128; | ||
|
||
#[derive(Drop, Serde, Copy)] | ||
pub(crate) struct StakingLogRecord { | ||
pub(crate) timestamp: u64, | ||
// Only 128+32=160 bits are used | ||
pub(crate) cumulative_total_staked: u256, | ||
pub(crate) cumulative_seconds_per_total_staked: u256, | ||
} | ||
|
||
#[generate_trait] | ||
pub impl StakingLogOperations of LogOperations { | ||
fn get_total_staked(self: @StorageBase<StakingLog>, timestamp: u64) -> Option<u128> { | ||
Option::Some(0) | ||
} | ||
|
||
fn find_in_change_log( | ||
self: @StorageBase<StakingLog>, timestamp: u64, | ||
) -> Option<(StakingLogRecord, u64)> { | ||
let log = self.as_path(); | ||
if log.len() == 0 { | ||
return Option::None; | ||
} | ||
let mut left = 0; | ||
let mut right = log.len() - 1; | ||
|
||
// To avoid reading from the storage multiple times. | ||
let mut result_ptr: Option<(StakingLogRecord, u64)> = Option::None; | ||
|
||
while (left <= right) { | ||
let center = (right + left) / 2; | ||
let record_ptr = log.at(center); | ||
let record = record_ptr.read(); | ||
|
||
if record.timestamp <= timestamp { | ||
result_ptr = Option::Some((record, center)); | ||
left = center + 1; | ||
} else { | ||
right = center - 1; | ||
}; | ||
}; | ||
|
||
if let Option::Some((result, idx)) = result_ptr { | ||
return Option::Some((result, idx)); | ||
} | ||
|
||
return Option::None; | ||
} | ||
|
||
fn log_change(self: StorageBase<Mutable<StakingLog>>, amount: u128, total_staked: u128) { | ||
let log = self.as_path(); | ||
|
||
let block_timestamp = get_block_timestamp(); | ||
|
||
if log.len() == 0 { | ||
log | ||
.append() | ||
.write( | ||
StakingLogRecord { | ||
timestamp: block_timestamp, | ||
cumulative_total_staked: 0_u256, | ||
cumulative_seconds_per_total_staked: 0_u64.into(), | ||
}, | ||
); | ||
|
||
return; | ||
} | ||
|
||
let last_record_ptr = log.at(log.len() - 1); | ||
|
||
let mut last_record = last_record_ptr.read(); | ||
|
||
let mut record = if last_record.timestamp == block_timestamp { | ||
// update record | ||
last_record_ptr | ||
} else { | ||
// create new record | ||
log.append() | ||
}; | ||
|
||
// Might be zero | ||
let seconds_diff = block_timestamp - last_record.timestamp; | ||
|
||
let total_staked_by_elapsed_seconds = total_staked.into() * seconds_diff.into(); | ||
|
||
let staked_seconds_per_total_staked: u256 = if total_staked == 0 { | ||
0_u64.into() | ||
} else { | ||
let res = u256 { low: 0, high: seconds_diff.into() } / total_staked.into(); | ||
assert(res.high < MAX_FP, 'FP_OVERFLOW'); | ||
res | ||
}; | ||
|
||
// Add a new record. | ||
record | ||
.write( | ||
StakingLogRecord { | ||
timestamp: block_timestamp, | ||
cumulative_total_staked: last_record.cumulative_total_staked | ||
+ total_staked_by_elapsed_seconds, | ||
cumulative_seconds_per_total_staked: last_record | ||
.cumulative_seconds_per_total_staked | ||
+ staked_seconds_per_total_staked, | ||
}, | ||
); | ||
} | ||
} | ||
|
||
// | ||
// Storage layout for StakingLogRecord | ||
// | ||
|
||
pub(crate) impl StakingLogRecordStorePacking of StorePacking<StakingLogRecord, (felt252, felt252)> { | ||
fn pack(value: StakingLogRecord) -> (felt252, felt252) { | ||
let packed_ts_cumulative_total_staked: felt252 = pack_u64_u256_tuple( | ||
value.timestamp, value.cumulative_total_staked, | ||
); | ||
|
||
let cumulative_seconds_per_total_staked: felt252 = value | ||
.cumulative_seconds_per_total_staked | ||
.try_into() | ||
.unwrap(); | ||
|
||
(packed_ts_cumulative_total_staked, cumulative_seconds_per_total_staked) | ||
} | ||
|
||
fn unpack(value: (felt252, felt252)) -> StakingLogRecord { | ||
let (packed_ts_cumulative_total_staked, cumulative_seconds_per_total_staked) = value; | ||
let (timestamp, cumulative_total_staked) = unpack_u64_u256_tuple( | ||
packed_ts_cumulative_total_staked, | ||
); | ||
|
||
StakingLogRecord { | ||
timestamp: timestamp, | ||
cumulative_total_staked: cumulative_total_staked, | ||
cumulative_seconds_per_total_staked: cumulative_seconds_per_total_staked | ||
.try_into() | ||
.unwrap(), | ||
} | ||
} | ||
} | ||
|
||
pub(crate) fn pack_u64_u256_tuple(val1: u64, val2: u256) -> felt252 { | ||
let cumulative_total_staked_high_32_bits: u128 = val2.high & MASK_32_BITS; | ||
u256 { | ||
high: val1.into() * TWO_POW_32.into() + cumulative_total_staked_high_32_bits.into(), | ||
low: val2.low, | ||
} | ||
.try_into() | ||
.unwrap() | ||
} | ||
|
||
pub(crate) fn unpack_u64_u256_tuple(value: felt252) -> (u64, u256) { | ||
let packed_ts_total_staked_u256: u256 = value.into(); | ||
|
||
let cumulative_total_staked = u256 { | ||
high: packed_ts_total_staked_u256.high & MASK_32_BITS, low: packed_ts_total_staked_u256.low, | ||
}; | ||
|
||
return ( | ||
(packed_ts_total_staked_u256.high / TWO_POW_32.into()).try_into().unwrap(), | ||
cumulative_total_staked, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use crate::staker_log::{pack_u64_u256_tuple, unpack_u64_u256_tuple}; | ||
|
||
const MASK_32_BITS: u128 = 0x100000000_u128 - 1; | ||
const MASK_64_BITS: u128 = 0x10000000000000000_u128 - 1; | ||
const MASK_160_BITS: u256 = 0x10000000000000000000000000000000000000000 - 1; | ||
|
||
|
||
fn assert_packs_and_unpacks(timestamp: u64, total_staked: u256) { | ||
let packed: u256 = pack_u64_u256_tuple(timestamp, total_staked).into(); | ||
|
||
let first_160_bits: u256 = packed & MASK_160_BITS; | ||
|
||
let shifted_160_bits_right: u128 = packed.high / (MASK_32_BITS + 1); | ||
|
||
let last_64_bits: u64 = (shifted_160_bits_right & MASK_64_BITS).try_into().unwrap(); | ||
assert_eq!(first_160_bits, total_staked); | ||
assert_eq!(last_64_bits, timestamp); | ||
|
||
let (unpacked_timestamp, unpacked_cumulative_total_staked) = unpack_u64_u256_tuple( | ||
packed.try_into().unwrap(), | ||
); | ||
assert_eq!(unpacked_timestamp, timestamp); | ||
assert_eq!(unpacked_cumulative_total_staked, total_staked); | ||
} | ||
|
||
#[test] | ||
fn test_staking_log_packing() { | ||
assert_packs_and_unpacks(0_u64, 0_u256); | ||
assert_packs_and_unpacks(10_u64, 50_u256); | ||
assert_packs_and_unpacks( | ||
0xffffffffffffffff_u64, 0xffffffffffffffffffffffffffffffffffffffff_u256, | ||
) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maximum value that can be store in felt252 is MAX_V = 0x800000000000011000000000000000000000000000000000000000000000000.
MAX_FP = MAX_V >> 128 (maximum value of highest 123 bit of felt252).