Skip to content

Commit ae8120e

Browse files
committed
feat(tower): integrate with gossip v2 and rework serdes
1 parent fc6e350 commit ae8120e

File tree

23 files changed

+1018
-708
lines changed

23 files changed

+1018
-708
lines changed

src/app/firedancer/topology.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,8 @@ fd_topo_initialize( config_t * config ) {
523523
single out link, over which all the writer tiles round-robin. */
524524
FOR(writer_tile_cnt) for( ulong j=0UL; j<exec_tile_cnt; j++ )
525525
fd_topob_tile_in( topo, "writer", i, "metric_in", "exec_writer", j, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
526-
/**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
526+
/**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
527+
/**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
527528
/**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "replay_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
528529
if( snapshots_enabled ) {
529530
fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "snap_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
@@ -951,8 +952,8 @@ fd_topo_configure_tile( fd_topo_tile_t * tile,
951952

952953
} else if( FD_UNLIKELY( !strcmp( tile->name, "tower" ) ) ) {
953954

954-
strncpy( tile->tower.identity_key_path, config->paths.identity_key, sizeof(tile->tower.identity_key_path) );
955-
strncpy( tile->tower.vote_acc_path, config->paths.vote_account, sizeof(tile->tower.vote_acc_path) );
955+
strncpy( tile->tower.identity_key, config->paths.identity_key, sizeof(tile->tower.identity_key) );
956+
strncpy( tile->tower.vote_account, config->paths.vote_account, sizeof(tile->tower.vote_account) );
956957
strncpy( tile->tower.ledger_path, config->paths.ledger, sizeof(tile->tower.ledger_path) );
957958

958959
} else if( FD_UNLIKELY( !strcmp( tile->name, "send" ) ) ) {

src/choreo/ghost/fd_ghost.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ fd_ghost_is_ancestor( fd_ghost_t const * ghost, fd_hash_t const * ancestor, fd_h
570570
}
571571

572572
int
573-
fd_ghost_invalid( fd_ghost_t const * ghost, fd_ghost_ele_t const * ele ) {
573+
fd_ghost_is_valid_fork( fd_ghost_t const * ghost, fd_ghost_ele_t const * ele ) {
574574
fd_ghost_ele_t const * anc = ele;
575575
while( FD_LIKELY( anc ) ) {
576576
if( FD_UNLIKELY( ( !anc->valid ) ) ) return 1;

src/choreo/ghost/fd_ghost.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,6 @@ typedef struct fd_dup_seen fd_dup_seen_t;
200200
#define FD_GHOST_MAGIC (0xf17eda2ce7940570UL) /* firedancer ghost version 0 */
201201

202202
struct __attribute__((aligned(128UL))) fd_ghost {
203-
204-
/* Metadata */
205-
206203
ulong magic; /* ==FD_GHOST_MAGIC */
207204
ulong ghost_gaddr; /* wksp gaddr of this in the backing wksp, non-zero gaddr */
208205
ulong seed; /* seed for various hashing function used under the hood, arbitrary */
@@ -387,7 +384,7 @@ fd_ghost_is_ancestor( fd_ghost_t const * ghost, fd_hash_t const * ancestor, fd_h
387384
/* fd_ghost_anc_eqvoc. */
388385

389386
int
390-
fd_ghost_invalid( fd_ghost_t const * ghost, fd_ghost_ele_t const * ele );
387+
fd_ghost_is_valid_fork( fd_ghost_t const * ghost, fd_ghost_ele_t const * ele );
391388

392389
/* Operations */
393390

src/choreo/notar/fd_notar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
commitment status of blocks (queryable via RPC) to determine that
3030
their transaction has landed on a block that will not rollback. */
3131

32-
/* TODO duplicate confirmed / optimistc confirmed currently not
32+
/* TODO duplicate confirmed / optimistic confirmed currently not
3333
implemented through this API */
3434

3535
/* FD_NOTAR_PARANOID: Define this to non-zero at compile time

src/choreo/tower/Local.mk

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
ifdef FD_HAS_INT128
22
ifdef FD_HAS_SECP256K1
3-
$(call add-hdrs,fd_tower.h)
3+
$(call add-hdrs,fd_tower.h fd_tower_serde.h)
44
$(call add-objs,fd_tower,fd_choreo)
5+
$(call add-objs,fd_tower_serde,fd_choreo)
56
ifdef FD_HAS_HOSTED
67
$(call make-unit-test,test_tower,test_tower,fd_choreo fd_flamenco fd_tango fd_ballet fd_util,$(SECP256K1_LIBS))
8+
$(call make-unit-test,test_tower_serde,test_tower_serde,fd_choreo fd_flamenco fd_tango fd_ballet fd_util,$(SECP256K1_LIBS))
79
$(call run-unit-test,test_tower)
10+
$(call run-unit-test,test_tower_serde)
811
endif
912
endif
1013
endif

src/choreo/tower/fd_tower.c

Lines changed: 315 additions & 415 deletions
Large diffs are not rendered by default.

src/choreo/tower/fd_tower.h

Lines changed: 33 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -459,57 +459,6 @@ typedef struct fd_tower_vote fd_tower_vote_t;
459459

460460
typedef fd_tower_vote_t fd_tower_t;
461461

462-
/* fd_tower_sync_serde describes a serialization / deserialization
463-
schema for a bincode-encoded TowerSync transaction. The serde is
464-
structured for zero-copy access ie. x-raying individual fields. */
465-
466-
struct fd_tower_sync_serde /* CompactTowerSync */ {
467-
ulong const * root;
468-
struct /* short_vec */ {
469-
ushort lockouts_cnt; /* variable-length so copied (ShortU16) */
470-
struct /* Lockout */ {
471-
ulong offset; /* variable-length so copied (VarInt) */
472-
uchar const * confirmation_count;
473-
} lockouts[31];
474-
};
475-
fd_hash_t const * hash;
476-
struct /* Option<UnixTimestamp> */ {
477-
uchar const * timestamp_option;
478-
long const * timestamp;
479-
};
480-
fd_hash_t const * block_id;
481-
};
482-
typedef struct fd_tower_sync_serde fd_tower_sync_serde_t;
483-
484-
/* fd_tower_file_serde describes a serialization / deserialization
485-
schema for checkpointing / restoring tower from a file. This
486-
corresponds exactly with the binary layout of a tower file that Agave
487-
uses during boot, set-identity, and voting.
488-
489-
The serde is structured for zero-copy access ie. x-raying individual
490-
fields. */
491-
492-
struct fd_tower_file_serde /* SavedTowerVersions::Current */ {
493-
uint const * kind;
494-
fd_ed25519_sig_t const * signature;
495-
ulong const * data_sz; /* serialized sz of data field below */
496-
struct /* Tower1_14_11 */ {
497-
fd_pubkey_t const * node_pubkey;
498-
ulong const * threshold_depth;
499-
double const * threshold_size;
500-
fd_voter_v2_serde_t vote_state;
501-
struct {
502-
uint const * last_vote_kind;
503-
fd_tower_sync_serde_t last_vote;
504-
};
505-
struct /* BlockTimestamp */ {
506-
ulong const * slot;
507-
long const * timestamp;
508-
} last_timestamp;
509-
} /* data */;
510-
};
511-
typedef struct fd_tower_file_serde fd_tower_file_serde_t;
512-
513462
/* fd_tower_sign_fn is the signing callback used for signing tower
514463
checkpoints after serialization. */
515464

@@ -771,24 +720,24 @@ fd_tower_vote( fd_tower_t * tower, ulong slot );
771720

772721
/* Misc */
773722

774-
/* fd_tower_sync_serde populates serde using the provided tower and args
775-
to create a zero-copy view of a TowerSync vote transaction payload
776-
ready for serialization. */
723+
// /* fd_tower_sync_serde populates serde using the provided tower and args
724+
// to create a zero-copy view of a TowerSync vote transaction payload
725+
// ready for serialization. */
777726

778-
fd_tower_sync_serde_t *
779-
fd_tower_to_tower_sync( fd_tower_t const * tower, ulong root, fd_hash_t * bank_hash, fd_hash_t * block_id, long ts, fd_tower_sync_serde_t * ser );
727+
// fd_tower_sync_serde_t *
728+
// fd_tower_to_tower_sync( fd_tower_t const * tower, ulong root, fd_hash_t * bank_hash, fd_hash_t * block_id, long ts, fd_tower_sync_serde_t * ser );
780729

781-
/* fd_tower_sync_serde populates serde using the provided tower and args
782-
to create a zero-copy view of an Agave-compatible serialized Tower
783-
ready for serialization. */
730+
// /* fd_tower_sync_serde populates serde using the provided tower and args
731+
// to create a zero-copy view of an Agave-compatible serialized Tower
732+
// ready for serialization. */
784733

785-
fd_tower_file_serde_t *
786-
fd_tower_serde( fd_tower_t const * tower,
787-
ulong root,
788-
fd_tower_sync_serde_t * last_vote,
789-
uchar const pvtkey[static 32],
790-
uchar const pubkey[static 32],
791-
fd_tower_file_serde_t * ser );
734+
// fd_tower_file_serde_t *
735+
// fd_tower_serde( fd_tower_t const * tower,
736+
// ulong root,
737+
// fd_tower_sync_serde_t * last_vote,
738+
// uchar const pvtkey[static 32],
739+
// uchar const pubkey[static 32],
740+
// fd_tower_file_serde_t * ser );
792741

793742
/* fd_tower_to_vote_txn writes tower into a fd_tower_sync_t vote
794743
instruction and serializes it into a Solana transaction. Assumes
@@ -822,15 +771,15 @@ fd_tower_to_vote_txn( fd_tower_t const * tower,
822771
the memory pointed by tower or the file pointed to by path while
823772
fd_tower_checkpt is in progress. */
824773

825-
int
826-
fd_tower_checkpt( fd_tower_t const * tower,
827-
ulong root,
828-
fd_tower_sync_serde_t * last_vote,
829-
uchar const pubkey[static 32],
830-
fd_tower_sign_fn * sign_fn,
831-
int fd,
832-
uchar * buf,
833-
ulong buf_max );
774+
// int
775+
// fd_tower_checkpt( fd_tower_t const * tower,
776+
// ulong root,
777+
// fd_tower_sync_serde_t * last_vote,
778+
// uchar const pubkey[static 32],
779+
// fd_tower_sign_fn * sign_fn,
780+
// int fd,
781+
// uchar * buf,
782+
// ulong buf_max );
834783

835784
/* fd_tower_restore restores tower from the bytes pointed to by restore.
836785
Returns 0 on success, -1 on error. Assumes tower is a valid local
@@ -870,11 +819,11 @@ fd_tower_restore( fd_tower_t * tower,
870819
serde is a zero-copy view of the Agave-compatible bincode-encoding of
871820
a tower. See also the struct definition of fd_tower_serde_t. */
872821

873-
int
874-
fd_tower_serialize( fd_tower_file_serde_t * ser,
875-
uchar * buf,
876-
ulong buf_max,
877-
ulong * buf_sz );
822+
// int
823+
// fd_tower_serialize( fd_tower_file_serde_t * ser,
824+
// uchar * buf,
825+
// ulong buf_max,
826+
// ulong * buf_sz );
878827

879828
/* fd_tower_deserialize deserializes buf into serde. Returns 0 on
880829
success, -1 if an error is encountered during deserialization. buf
@@ -884,10 +833,10 @@ fd_tower_serialize( fd_tower_file_serde_t * ser,
884833
serde is a zero-copy view of the Agave-compatible bincode-encoding of
885834
a tower. See also the struct definition of fd_tower_serde_t. */
886835

887-
int
888-
fd_tower_deserialize( uchar * buf,
889-
ulong buf_sz,
890-
fd_tower_file_serde_t * de );
836+
// int
837+
// fd_tower_deserialize( uchar * buf,
838+
// ulong buf_sz,
839+
// fd_tower_file_serde_t * de );
891840

892841
/* fd_tower_verify checks tower is in a valid state. Valid iff:
893842
- cnt < FD_TOWER_VOTE_MAX

src/choreo/tower/fd_tower_serde.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include "fd_tower_serde.h"
2+
#include "fd_tower.h"
3+
4+
#define SHORTVEC 0
5+
6+
#define SER( T, name ) do { \
7+
if( FD_UNLIKELY( off+sizeof(T)>buf_max ) ) { \
8+
FD_LOG_WARNING(( "ser %s: overflow (off %lu > buf_max: %lu)", #name, off, buf_max )); \
9+
return -1; \
10+
} \
11+
FD_STORE( T, buf+off, serde->name ); \
12+
off += sizeof(T); \
13+
} while(0)
14+
15+
#define DE( T, name ) do { \
16+
if( FD_UNLIKELY( off+sizeof(T)>buf_sz ) ) { \
17+
FD_LOG_WARNING(( "de %s: overflow (off %lu > buf_sz: %lu)", #name, off, buf_sz )); \
18+
return -1; \
19+
} \
20+
serde->name = *(T const *)fd_type_pun_const( buf+off ); \
21+
off += sizeof(T); \
22+
} while(0)
23+
24+
static ulong
25+
ser_short_u16( uchar * dst, ushort src ) {
26+
if ( FD_LIKELY( src < 0x80UL ) ) { *dst = (uchar) src; return 1; }
27+
else if( FD_LIKELY( src < 0x4000UL ) ) { *dst++ = (uchar)((src&0x7FUL)|0x80UL); *dst++ = (uchar)( src>>7); return 2; }
28+
else { *dst++ = (uchar)((src&0x7FUL)|0x80UL); *dst++ = (uchar)(((src>>7)&0x7FUL)|0x80UL); *dst++ = (uchar)(src>>14UL); return 3; }
29+
}
30+
31+
static ulong
32+
ser_var_int( uchar * dst, ulong src ) {
33+
ulong off = 0;
34+
while( FD_LIKELY( 1 ) ) {
35+
if( FD_LIKELY( src < 0x80UL ) ) {
36+
*(dst) = (uchar)src;
37+
off += 1;
38+
return off;
39+
}
40+
*(dst+off) = (uchar)((src&0x7FUL)|0x80UL);
41+
off += 1;
42+
src >>= 7;
43+
}
44+
}
45+
46+
static ulong
47+
de_short_u16( ushort * dst, uchar const * src ) {
48+
if ( FD_LIKELY( !(0x80U & src[0]) ) ) { *dst = (ushort)src[0]; return 1; }
49+
else if( FD_LIKELY( !(0x80U & src[1]) ) ) { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)src[1])<<7)); return 2; }
50+
else { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)(src[1]&0x7FUL))<<7) + (((ulong)src[2])<<14)); return 3; }
51+
}
52+
53+
static ulong
54+
de_var_int( ulong * dst, uchar const * src ) {
55+
*dst = 0;
56+
ulong off = 0;
57+
ulong bit = 0;
58+
while( FD_LIKELY( bit < 64 ) ) {
59+
uchar byte = *(uchar const *)(src+off);
60+
off += 1;
61+
*dst |= (byte & 0x7FUL) << bit;
62+
if( FD_LIKELY( (byte & 0x80U) == 0U ) ) {
63+
if( FD_UNLIKELY( (*dst>>bit) != byte ) ) FD_LOG_CRIT(( "de_varint" ));
64+
if( FD_UNLIKELY( byte==0U && (bit!=0U || *dst!=0UL) ) ) FD_LOG_CRIT(( "de_varint" ));
65+
return off;
66+
}
67+
bit += 7;
68+
}
69+
FD_LOG_CRIT(( "de_varint" ));
70+
}
71+
72+
// fd_tower_sync_serde_t *
73+
// fd_tower_sync_to( fd_tower_sync_serde_t * serde, uchar * buf, ulong buf_max, ulong * buf_sz ) {
74+
// ser->root = &root;
75+
// ser->lockouts_cnt = (ushort)fd_tower_votes_cnt( tower );
76+
// ushort i = 0;
77+
// ulong prev = root;
78+
// for( fd_tower_votes_iter_t iter = fd_tower_votes_iter_init( tower );
79+
// !fd_tower_votes_iter_done( tower, iter );
80+
// iter = fd_tower_votes_iter_next( tower, iter ) ) {
81+
// fd_tower_vote_t const * vote = fd_tower_votes_iter_ele_const( tower, iter );
82+
// ser->lockouts[i].offset = vote->slot - prev;
83+
// ser->lockouts[i].confirmation_count = (uchar const *)fd_type_pun_const( &vote->conf );
84+
// i++;
85+
// }
86+
// ser->hash = bank_hash;
87+
// ser->timestamp_option = &option_some;
88+
// ser->timestamp = &ts;
89+
// ser->block_id = block_id;
90+
// return ser;
91+
// }
92+
93+
int
94+
fd_tower_sync_serialize( fd_tower_sync_serde_t * serde,
95+
uchar * buf,
96+
ulong buf_max,
97+
ulong * buf_sz ) {
98+
ulong off = 0;
99+
SER( ulong, root );
100+
off += ser_short_u16( buf+off, serde->lockouts_cnt );
101+
if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) {
102+
FD_LOG_WARNING(( "lockouts_cnt > 31: %u", serde->lockouts_cnt ));
103+
return -1;
104+
}
105+
for( ulong i = 0; i < fd_ulong_min( serde->lockouts_cnt, 31 ); i++ ) {
106+
off += ser_var_int( buf+off, serde->lockouts[i].offset );
107+
SER( uchar, lockouts[i].confirmation_count );
108+
}
109+
SER( fd_hash_t, hash );
110+
SER( uchar, timestamp_option );
111+
if( FD_LIKELY( serde->timestamp_option ) ) {
112+
SER( long, timestamp );
113+
}
114+
SER( fd_hash_t, block_id );
115+
*buf_sz = off;
116+
return 0;
117+
}
118+
119+
int
120+
fd_tower_sync_deserialize( fd_tower_sync_serde_t * serde,
121+
uchar const * buf,
122+
ulong buf_sz ) {
123+
ulong off = 0;
124+
DE( ulong, root );
125+
off += de_short_u16( &serde->lockouts_cnt, buf+off );
126+
if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) {
127+
FD_LOG_WARNING(( "lockouts_cnt > 31: %u", serde->lockouts_cnt ));
128+
return -1;
129+
}
130+
for( ulong i = 0; i < fd_ulong_min( serde->lockouts_cnt, 31 ); i++ ) {
131+
off += de_var_int( &serde->lockouts[i].offset, buf+off );
132+
DE( uchar, lockouts[i].confirmation_count );
133+
}
134+
DE( fd_hash_t, hash );
135+
DE( uchar, timestamp_option );
136+
if( FD_LIKELY( serde->timestamp_option ) ) {
137+
DE( long, timestamp );
138+
}
139+
DE( fd_hash_t, block_id );
140+
return 0;
141+
}

0 commit comments

Comments
 (0)