Skip to content

Commit 98640e9

Browse files
committed
it compiles i guess
1 parent 71e95da commit 98640e9

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
@@ -1074,13 +1074,13 @@ fd_forest_publish( fd_forest_t * forest, ulong new_root_slot ) {
10741074
#define SLOT_INSERT 1
10751075

10761076
int
1077-
fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
1077+
fd_forest_evict( fd_forest_t * forest, ulong new_slot, ulong parent_slot ) {
10781078
FD_LOG_NOTICE(( "fd_forest_eviction_time" ));
10791079
fd_forest_ancestry_t * ancestry = fd_forest_ancestry( forest );
10801080
fd_forest_frontier_t * frontier = fd_forest_frontier( forest );
10811081
fd_forest_subtlist_t * subtlist = fd_forest_subtlist( forest );
1082+
fd_forest_orphaned_t * orphaned = fd_forest_orphaned( forest );
10821083
fd_forest_blk_t * pool = fd_forest_pool( forest );
1083-
ulong null = fd_forest_pool_idx_null( pool );
10841084

10851085

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

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

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

1124-
// choose something to evict from orphans
1125-
return SLOT_INSERT;
11261133
} else {
1127-
/* Have no orphans. */
1134+
/* Have no orphans. Considering the most extreme case where someone
1135+
has DoSed us with 10000 slots that chain to the root. */
11281136

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

11751181
ulong

src/discof/forest/fd_forest.h

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

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

848899
int

0 commit comments

Comments
 (0)