Skip to content

Commit 24af464

Browse files
committed
it compiles i guess
1 parent b02d1b1 commit 24af464

File tree

2 files changed

+87
-30
lines changed

2 files changed

+87
-30
lines changed

src/discof/forest/fd_forest.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,13 +1073,13 @@ fd_forest_publish( fd_forest_t * forest, ulong new_root_slot ) {
10731073
#define SLOT_INSERT 1
10741074

10751075
int
1076-
fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
1076+
fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
10771077
FD_LOG_NOTICE(( "fd_forest_eviction_time" ));
10781078
fd_forest_ancestry_t * ancestry = fd_forest_ancestry( forest );
10791079
fd_forest_frontier_t * frontier = fd_forest_frontier( forest );
10801080
fd_forest_subtlist_t * subtlist = fd_forest_subtlist( forest );
1081+
fd_forest_orphaned_t * orphaned = fd_forest_orphaned( forest );
10811082
fd_forest_blk_t * pool = fd_forest_pool( forest );
1082-
ulong null = fd_forest_pool_idx_null( pool );
10831083

10841084

10851085
int has_orphans = !fd_forest_subtlist_is_empty( subtlist, pool );
@@ -1088,42 +1088,50 @@ fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
10881088
/* During regular operation there's usually no orphans, but if eviction
10891089
is called then it's likely we have orphans. */
10901090
if( FD_LIKELY( has_orphans ) ) {
1091+
10911092
/* We'll keep it if it's older than all of our orphans, or if it's
10921093
parent is part of the main tree. */
1093-
1094-
ulong evict_orphan_slot = ULONG_MAX; /* best orphan candidate for eviction is the newest subtree. */
1094+
fd_forest_blk_t * evict_orphan = NULL; /* best orphan candidate for eviction is the newest subtree. */
10951095
for( fd_forest_subtlist_iter_t iter = fd_forest_subtlist_iter_fwd_init( subtlist, pool );
10961096
!fd_forest_subtlist_iter_done( iter, subtlist, pool );
10971097
iter = fd_forest_subtlist_iter_fwd_next( iter, subtlist, pool ) ) {
10981098
fd_forest_blk_t * ele = fd_forest_subtlist_iter_ele( iter, subtlist, pool );
1099-
if( FD_LIKELY( evict_orphan_slot == ULONG_MAX ) ) evict_orphan_slot = ele->slot;
1100-
else evict_orphan_slot = fd_ulong_max( evict_orphan_slot, ele->slot );
1099+
if( FD_LIKELY( evict_orphan == NULL ) ) evict_orphan = ele;
1100+
else evict_orphan = fd_ptr_if( evict_orphan->slot < ele->slot, ele, evict_orphan );
1101+
}
11011102

1103+
for( fd_forest_orphaned_iter_t iter = fd_forest_orphaned_iter_init( orphaned, pool );
1104+
!fd_forest_orphaned_iter_done( iter, orphaned, pool );
1105+
iter = fd_forest_orphaned_iter_next( iter, orphaned, pool ) ) {
1106+
fd_forest_blk_t * ele = fd_forest_orphaned_iter_ele( iter, orphaned, pool );
1107+
evict_orphan = fd_ptr_if( evict_orphan->slot < ele->slot, ele, evict_orphan );
11021108
}
1103-
/* We are connecting to the main tree. Nuke the orphan. */
1109+
/* Now we have the max of all subtrees and orphans. This is our best candidate for eviction. */
1110+
1111+
/* If are connecting to the main tree. Nuke the best candidate orphan. */
11041112
if( fd_forest_ancestry_ele_query( ancestry, &parent_slot, NULL, pool ) ||
11051113
fd_forest_frontier_ele_query( frontier, &parent_slot, NULL, pool ) ) {
1106-
// evict_orphan_slot
1107-
1114+
subtrees_orphaned_remove( forest, evict_orphan->slot );
1115+
requests_remove( forest, fd_forest_orphreqs( forest ), fd_forest_orphlist( forest ), &forest->orphiter, fd_forest_pool_idx( pool, evict_orphan ) );
1116+
fd_forest_pool_ele_release( pool, evict_orphan );
11081117
return SLOT_INSERT;
11091118
}
11101119

1111-
1112-
/* We ourselves are an orphan. Should we evict something else or just evict ourselves?
1120+
/* The new slot an orphan. Should we evict the candidate orphan or insert ourselves?
11131121
We'll keep it if it's older than all of our orphans */
1114-
for( fd_forest_subtlist_iter_t iter = fd_forest_subtlist_iter_fwd_init( subtlist, pool );
1115-
!fd_forest_subtlist_iter_done ( iter, subtlist, pool );
1116-
iter = fd_forest_subtlist_iter_fwd_next( iter, subtlist, pool ) ) {
1117-
fd_forest_blk_t * ele = fd_forest_subtlist_iter_ele( iter, subtlist, pool );
1118-
if( FD_LIKELY( new_slot > ele->slot ) ) {
1119-
return SLOT_IGNORE;
1120-
}
1122+
1123+
if( evict_orphan->slot < new_slot ) {
1124+
return SLOT_IGNORE;
1125+
} else {
1126+
subtrees_orphaned_remove( forest, evict_orphan->slot );
1127+
requests_remove( forest, fd_forest_orphreqs( forest ), fd_forest_orphlist( forest ), &forest->orphiter, fd_forest_pool_idx( pool, evict_orphan ) );
1128+
fd_forest_pool_ele_release( pool, evict_orphan );
1129+
return SLOT_INSERT;
11211130
}
11221131

1123-
// choose something to evict from orphans
1124-
return SLOT_INSERT;
11251132
} else {
1126-
/* Have no orphans. */
1133+
/* Have no orphans. Considering the most extreme case where someone
1134+
has DoSed us with 10000 slots that chain to the root. */
11271135

11281136
if( FD_LIKELY( parent_exists ) ) {
11291137
/* Parent exists. This slot chains to the main tree. From oldest to newest,
@@ -1157,18 +1165,16 @@ fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
11571165
else return SLOT_IGNORE;
11581166
} else {
11591167
/* evict slot found. EVICT IT. */
1160-
1168+
fd_forest_blk_t * evict_ele = fd_forest_frontier_ele_remove( frontier, &evict_slot, NULL, pool );
1169+
requests_remove( forest, fd_forest_requests( forest ), fd_forest_reqslist( forest ), &forest->iter, fd_forest_pool_idx( pool, evict_ele ) );
1170+
fd_forest_pool_ele_release( pool, evict_ele );
11611171
return SLOT_INSERT;
11621172
}
11631173
} else {
11641174
/* Parent does not exist. This new slot would've been added as an orphan. */
11651175
return SLOT_IGNORE;
11661176
}
11671177
}
1168-
1169-
1170-
1171-
11721178
}
11731179

11741180
ulong

src/discof/forest/fd_forest.h

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -809,11 +809,12 @@ fd_forest_merkle_last_incorrect_idx( fd_forest_blk_t * ele ) {
809809
fd_forest_blk_t const *
810810
fd_forest_publish( fd_forest_t * forest, ulong slot );
811811

812-
/* fd_forest_eviction is called when the forest has no more free elements,
813-
but we are trying to insert a new block. When this happens, forest
814-
begins evicting in the following order:
812+
/* fd_forest_evict is called when the forest has no more free elements,
813+
but we are trying to insert a new block. ts is fucked up tbh.
814+
When this happens, forest begins evicting in the following order:
815815
816816
1. Orphaned slots
817+
2. TODO: maybe we will want to process confirmations on orphans as well - in that case we evict unconfirmed orphans first.
817818
2. Connected, unconfirmed blocks
818819
3. Connected, confirmed blocks
819820
@@ -839,8 +840,58 @@ fd_forest_publish( fd_forest_t * forest, ulong slot );
839840
and again, and we never make progress towards completing catchup.
840841
841842
So we need to evict orphans ONLY if the slot being added is closer to
842-
the root. Thus the eviction unfortunately depends on what's being
843+
the root. Thus the eviction is stateful and depends on what's being
843844
added.
845+
846+
NO ORPHANS. EVEN MORE UNFORTUNATE CASE. SAD.
847+
848+
Now if we don't have orphans, we need to evict the newest unconfirmed leaf.
849+
I.e. start by trimming from the tip of the tree, but ideally on a
850+
fork that is a minority.
851+
852+
i.e best case:
853+
854+
1 ── 2 ── 4 ── 6 ── 7 ── 8 ...... ── 1000 <- 1001 would like to be added to the rree
855+
└── 3 ── 5
856+
857+
If 1000 is confirmed, and 5 is not, we should evict 5 first, and then add 1001.
858+
859+
1 ── 2 ── 4 ── 6 ── 7 ── 8 ...... ── 1000 ── 1001 <- 1002 would like to be added to the rree
860+
└── 3
861+
862+
Similarly, after 1002 arrives:
863+
1 ── 2 ── 4 ── 6 ── 7 ── 8 ...... ── 1000 ── 1001 ── 1002 <- 1003 would like to be added to the rree
864+
865+
Now we have one fork, with 1003 chaining to 1002. If 1002 is
866+
confirmed, then it's truly unfortunate... We (and most likely the
867+
cluster) hasn't rooted in max_live_slots! As long as 2 is also
868+
confirmed, then we are just going to optimistically publish forward to
869+
slot 2 and make it our new root. Note 2 MUST have undergone
870+
fec_chain_verify before it can be confirmed. If 2 is still not
871+
confirmed, we could still be in the process of evicting + repairing
872+
duplicates, so we must wait for 2 to be confirmed before we can
873+
publish forward.
874+
875+
If 1002 is NOT confirmed, we cannot evict it and add 1003. This just
876+
puts us in an infinite loop of evicting slots + adding newer slots. TODO: don't know what to do in this case.
877+
878+
If 1003 is chaining to 1001, i.e., it's creating a new fork.
879+
880+
TODO idk actually
881+
882+
This also works in the degenerate DoS case, where we have an extremely
883+
wide tree. Imagine someone someone with leader slots 1001 thru 1995 is
884+
doing the following attck:
885+
886+
1 ── 2 ── 3 ── 4 ── 5 ── <-- when we try to add 6, we run into eviction policy
887+
├── 1001'
888+
├── 1003'
889+
...
890+
└── 1995'
891+
Even if the confirmation for 5 is lagging coming in (or it requires us
892+
to replay 6 to see it), we can follow a general policy of evicting the
893+
newest unconfirmed leaf. Newest implies furthest from the root. So we
894+
would evict 1995' first, and then add 6.
844895
*/
845896

846897
int

0 commit comments

Comments
 (0)