Line data Source code
1 : /**
2 :
3 : export RUST_LOG=solana_gossip=TRACE
4 : cargo run --bin solana-test-validator
5 :
6 : **/
7 :
8 : #define _GNU_SOURCE /* See feature_test_macros(7) */
9 :
10 : #include "fd_gossip.h"
11 : #include "../../util/fd_util.h"
12 : #include "../../ballet/base58/fd_base58.h"
13 : #include "../types/fd_types_yaml.h"
14 : #include "../../util/net/fd_eth.h"
15 : #include <stdio.h>
16 : #include <unistd.h>
17 : #include <signal.h>
18 : #include <sys/socket.h>
19 : #include <netinet/in.h>
20 : #include <arpa/inet.h>
21 : #include <sys/random.h>
22 : #include <errno.h>
23 : #include <netdb.h>
24 : #include <stdlib.h>
25 :
26 0 : static void print_data(fd_crds_data_t* data, void* arg) {
27 0 : fd_flamenco_yaml_t * yamldump = (fd_flamenco_yaml_t *)arg;
28 0 : FILE * dumpfile = (FILE *)fd_flamenco_yaml_file(yamldump);
29 0 : fd_crds_data_walk(yamldump, data, fd_flamenco_yaml_walk, NULL, 1U);
30 :
31 0 : if (data->discriminant == fd_crds_data_enum_vote) {
32 0 : fd_gossip_vote_t * v = &data->inner.vote;
33 0 : fd_txn_t * txn = v->txn.txn;
34 0 : for ( ushort i = 0; i < txn->instr_cnt; ++i ) {
35 0 : fd_txn_instr_t const * txn_instr = &txn->instr[i];
36 0 : uchar * data = v->txn.raw + txn_instr->data_off;
37 0 : ushort data_sz = txn_instr->data_sz;
38 0 : fd_bincode_decode_ctx_t decode_ctx = {
39 0 : .data = data,
40 0 : .dataend = data + data_sz
41 0 : };
42 :
43 0 : ulong total_sz = 0UL;
44 0 : if( FD_UNLIKELY( fd_vote_instruction_decode_footprint( &decode_ctx, &total_sz ) ) ) {
45 0 : FD_LOG_WARNING(( "failed to decode vote instruction" ));
46 0 : return;
47 0 : }
48 :
49 0 : uchar * mem = malloc( total_sz );
50 :
51 0 : fd_vote_instruction_t * vinsn = fd_vote_instruction_decode( mem, &decode_ctx );
52 0 : if( FD_UNLIKELY( decode_ctx.data != decode_ctx.dataend ) ) {
53 0 : FD_LOG_WARNING(("failed to decode vote instruction"));
54 0 : return;
55 0 : }
56 :
57 0 : fd_vote_instruction_walk( yamldump, vinsn, fd_flamenco_yaml_walk, NULL, 1U );
58 0 : }
59 0 : }
60 :
61 0 : fflush( dumpfile );
62 0 : }
63 :
64 : // SIGINT signal handler
65 : volatile int stopflag = 0;
66 0 : static void stop(int sig) { (void)sig; stopflag = 1; }
67 :
68 : static int sockfd = -1;
69 :
70 : /* Convert my style of address to UNIX style */
71 : static int
72 0 : gossip_to_sockaddr( uchar * dst, fd_gossip_peer_addr_t const * src ) {
73 0 : fd_memset(dst, 0, sizeof(struct sockaddr_in));
74 0 : struct sockaddr_in * t = (struct sockaddr_in *)dst;
75 0 : t->sin_family = AF_INET;
76 0 : t->sin_addr.s_addr = src->addr;
77 0 : t->sin_port = src->port;
78 0 : return sizeof(struct sockaddr_in);
79 0 : }
80 :
81 : /* Convert my style of address from UNIX style */
82 : static int
83 0 : gossip_from_sockaddr( fd_gossip_peer_addr_t * dst, uchar const * src ) {
84 0 : FD_STATIC_ASSERT(sizeof(fd_gossip_peer_addr_t) == sizeof(ulong),"messed up size");
85 0 : dst->l = 0;
86 0 : const struct sockaddr_in * sa = (const struct sockaddr_in *)src;
87 0 : dst->addr = sa->sin_addr.s_addr;
88 0 : dst->port = sa->sin_port;
89 0 : return 0;
90 0 : }
91 :
92 : static void
93 0 : send_packet( uchar const * data, size_t sz, fd_gossip_peer_addr_t const * addr, void * arg ) {
94 0 : (void)arg;
95 0 : uchar saddr[sizeof(struct sockaddr_in)];
96 0 : int saddrlen = gossip_to_sockaddr(saddr, addr);
97 0 : if ( sendto(sockfd, data, sz, MSG_DONTWAIT,
98 0 : (const struct sockaddr *)saddr, (socklen_t)saddrlen) < 0 ) {
99 0 : FD_LOG_WARNING(("sendto failed: %s", strerror(errno)));
100 0 : }
101 0 : }
102 :
103 : static int
104 0 : main_loop( fd_gossip_t * glob, fd_gossip_config_t * config, volatile int * stopflag ) {
105 0 : int fd;
106 0 : if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
107 0 : FD_LOG_ERR(("socket failed: %s", strerror(errno)));
108 0 : return -1;
109 0 : }
110 0 : sockfd = fd;
111 0 : int optval = 1<<20;
112 0 : if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&optval, sizeof(int)) < 0) {
113 0 : FD_LOG_ERR(("setsocketopt failed: %s", strerror(errno)));
114 0 : return -1;
115 0 : }
116 0 : if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&optval, sizeof(int)) < 0) {
117 0 : FD_LOG_ERR(("setsocketopt failed: %s", strerror(errno)));
118 0 : return -1;
119 0 : }
120 0 : uchar saddr[sizeof(struct sockaddr_in6)];
121 0 : int saddrlen = gossip_to_sockaddr(saddr, &config->my_addr);
122 0 : if (saddrlen < 0 || bind(fd, (struct sockaddr*)saddr, (uint)saddrlen) < 0) {
123 0 : FD_LOG_ERR(("bind failed: %s", strerror(errno)));
124 0 : return -1;
125 0 : }
126 0 : if( getsockname( fd, (struct sockaddr *)saddr, (uint*)&saddrlen ) < 0 ) {
127 0 : FD_LOG_ERR( ( "getsockname failed: %s", strerror( errno ) ) );
128 0 : return -1;
129 0 : }
130 0 : gossip_from_sockaddr( &config->my_addr, saddr );
131 0 : fd_gossip_update_addr( glob, &config->my_addr );
132 :
133 0 : fd_gossip_settime(glob, fd_log_wallclock());
134 0 : fd_gossip_start(glob);
135 :
136 0 : #define VLEN 32U
137 0 : struct mmsghdr msgs[VLEN];
138 0 : struct iovec iovecs[VLEN];
139 0 : uchar bufs[VLEN][FD_ETH_PAYLOAD_MAX];
140 0 : uchar sockaddrs[VLEN][sizeof(struct sockaddr_in6)]; /* sockaddr is smaller than sockaddr_in6 */
141 :
142 0 : while ( !*stopflag ) {
143 0 : fd_gossip_settime(glob, fd_log_wallclock());
144 0 : fd_gossip_continue(glob);
145 :
146 0 : fd_memset(msgs, 0, sizeof(msgs));
147 0 : for (uint i = 0; i < VLEN; i++) {
148 0 : iovecs[i].iov_base = bufs[i];
149 0 : iovecs[i].iov_len = FD_ETH_PAYLOAD_MAX;
150 0 : msgs[i].msg_hdr.msg_iov = &iovecs[i];
151 0 : msgs[i].msg_hdr.msg_iovlen = 1;
152 0 : msgs[i].msg_hdr.msg_name = sockaddrs[i];
153 0 : msgs[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
154 0 : }
155 :
156 : /* Read more packets */
157 0 : long retval = recvmmsg(fd, msgs, VLEN, MSG_DONTWAIT, NULL);
158 0 : if (retval < 0) {
159 0 : if (errno == EINTR || errno == EWOULDBLOCK)
160 0 : continue;
161 0 : FD_LOG_ERR(("recvmmsg failed: %s", strerror(errno)));
162 0 : return -1;
163 0 : }
164 0 : if (retval == 0)
165 0 : continue;
166 :
167 0 : for (uint i = 0; i < (uint)retval; ++i) {
168 0 : fd_gossip_peer_addr_t from;
169 0 : gossip_from_sockaddr( &from, msgs[i].msg_hdr.msg_name );
170 0 : fd_gossip_recv_packet(glob, bufs[i], (ulong)msgs[i].msg_len, &from);
171 0 : }
172 0 : }
173 :
174 0 : close(fd);
175 0 : return 0;
176 0 : }
177 :
178 : /* Convert a host:port string to a gossip network address. If host is
179 : * missing, it assumes the local hostname. */
180 : static fd_gossip_peer_addr_t *
181 0 : resolve_hostport(const char* str /* host:port */, fd_gossip_peer_addr_t * res) {
182 0 : fd_memset(res, 0, sizeof(fd_gossip_peer_addr_t));
183 :
184 : /* Find the : and copy out the host */
185 0 : char buf[128];
186 0 : uint i;
187 0 : for (i = 0; ; ++i) {
188 0 : if (str[i] == '\0' || i > sizeof(buf)-1U) {
189 0 : FD_LOG_ERR(("missing colon"));
190 0 : return NULL;
191 0 : }
192 0 : if (str[i] == ':') {
193 0 : buf[i] = '\0';
194 0 : break;
195 0 : }
196 0 : buf[i] = str[i];
197 0 : }
198 0 : if (i == 0)
199 : /* :port means $HOST:port */
200 0 : gethostname(buf, sizeof(buf));
201 :
202 0 : struct hostent * host = gethostbyname( buf );
203 0 : if (host == NULL) {
204 0 : FD_LOG_WARNING(("unable to resolve host %s", buf));
205 0 : return NULL;
206 0 : }
207 : /* Convert result to gossip address */
208 0 : res->l = 0;
209 0 : res->addr = ((struct in_addr *)host->h_addr)->s_addr;
210 0 : int port = atoi(str + i + 1);
211 0 : if ((port > 0 && port < 1024) || port > (int)USHORT_MAX) {
212 0 : FD_LOG_ERR(("invalid port number"));
213 0 : return NULL;
214 0 : }
215 0 : res->port = htons((ushort)port);
216 :
217 0 : return res;
218 0 : }
219 :
220 : int
221 : main( int argc,
222 : char ** argv ) {
223 : fd_boot( &argc, &argv );
224 :
225 : fd_valloc_t valloc = fd_libc_alloc_virtual();
226 :
227 : fd_gossip_config_t config;
228 : fd_memset(&config, 0, sizeof(config));
229 :
230 : uchar private_key[32];
231 : FD_TEST( 32UL==getrandom( private_key, 32UL, 0 ) );
232 : fd_sha512_t sha[1];
233 : fd_pubkey_t public_key;
234 : FD_TEST( fd_ed25519_public_from_private( public_key.uc, private_key, sha ) );
235 :
236 : config.public_key = &public_key;
237 : config.node_outset = fd_log_wallclock() / 1000000;
238 :
239 : char hostname[64];
240 : gethostname(hostname, sizeof(hostname));
241 :
242 : FD_TEST( resolve_hostport(":0", &config.my_addr) );
243 :
244 : config.shred_version = 4274;
245 :
246 : fd_flamenco_yaml_t * yamldump =
247 : fd_flamenco_yaml_init( fd_flamenco_yaml_new(
248 : fd_valloc_malloc( valloc, fd_flamenco_yaml_align(), fd_flamenco_yaml_footprint() ) ),
249 : stdout );
250 : config.deliver_fun = print_data;
251 : config.deliver_arg = yamldump;
252 : config.send_fun = send_packet;
253 : config.send_arg = NULL;
254 :
255 : ulong seed = fd_hash(0, hostname, strnlen(hostname, sizeof(hostname)));
256 :
257 : void * shm = fd_valloc_malloc(valloc, fd_gossip_align(), fd_gossip_footprint());
258 : fd_gossip_t * glob = fd_gossip_join(fd_gossip_new(shm, seed));
259 :
260 : if ( fd_gossip_set_config(glob, &config) )
261 : return 1;
262 :
263 : fd_gossip_peer_addr_t peeraddr;
264 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint.mainnet-beta.solana.com:8001", &peeraddr)) )
265 : // return 1;
266 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint2.mainnet-beta.solana.com:8001", &peeraddr)) )
267 : // return 1;
268 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint3.mainnet-beta.solana.com:8001", &peeraddr)) )
269 : // return 1;
270 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint4.mainnet-beta.solana.com:8001", &peeraddr)) )
271 : // return 1;
272 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint5.mainnet-beta.solana.com:8001", &peeraddr)) )
273 : // return 1;
274 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint.testnet.solana.com:8001", &peeraddr)) )
275 : // return 1;
276 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint2.testnet.solana.com:8001", &peeraddr)) )
277 : // return 1;
278 : // if ( fd_gossip_add_active_peer(glob, resolve_hostport("entrypoint3.testnet.solana.com:8001", &peeraddr)) )
279 : // return 1;
280 : if ( fd_gossip_add_active_peer(glob, resolve_hostport(":1024", &peeraddr)) )
281 : return 1;
282 :
283 : signal(SIGINT, stop);
284 : signal(SIGPIPE, SIG_IGN);
285 :
286 : if ( main_loop(glob, &config, &stopflag) )
287 : return 1;
288 :
289 : fd_valloc_free(valloc, fd_flamenco_yaml_delete(yamldump));
290 :
291 : fd_valloc_free(valloc, fd_gossip_delete(fd_gossip_leave(glob)));
292 :
293 : fd_halt();
294 : return 0;
295 : }
|