The Hook
"Go is good at concurrency" is a sentence I'd read a dozen times before it meant anything to me. This week, building the one real piece of Web3 Shield that exists so far β a Go worker that listens to a blockchain in real time β it finally clicked. Sharing the moment, not a lecture.
This is a learning-notes post, part of a series where I'm figuring out this project's architecture mostly in public, including the parts I get wrong.
What I Was Actually Trying to Do
Listen to a blockchain node, react the instant a new block is mined, and also notice if the connection itself drops β all without a pile of manual thread management I definitely don't know how to do well yet.
The Piece That Clicked
headers := make(chan *types.Header)
sub, err := client.SubscribeNewHead(context.Background(), headers)
if err != nil {
log.Fatal(err)
}
SubscribeNewHead hands back a channel. A new block header shows up on it whenever one's mined β no polling loop asking "anything yet?" on repeat.
for {
select {
case err := <-sub.Err():
log.Fatal("π¨ Erro na inscriΓ§Γ£o:", err)
case header := <-headers:
block, err := client.BlockByHash(context.Background(), header.Hash())
if err != nil {
continue
}
// ...process block
}
}
One goroutine. One select. Two channels. It waits until either has something, reacts, loops. I'd seen this pattern in tutorials before and nodded along without really getting why it mattered. Watching it hold a real WebSocket connection open, live, was different β I could actually feel what "non-blocking" meant instead of just repeating the word.
The Reasoning I'm Testing (Not Proving Yet)
I learned that a goroutine blocked on a channel costs kilobytes, not a whole OS thread. My working theory is that this means listening to more chains later is just "spawn more goroutines," not "redesign the whole thing." I like that idea a lot. I also haven't tested it at any real scale, so take it as a hypothesis I'm holding, not a claim I've proven.
What I Kept Out of This Piece on Purpose
This worker doesn't judge anything β no "this looks suspicious," no scoring. It captures three fields (hash, destination, function signature) and writes them to Postgres:
insertQuery := `
INSERT INTO raw_transactions (tx_hash, to_address, function_signature)
VALUES ($1, $2, $3)
ON CONFLICT (tx_hash) DO NOTHING;`
I don't know enough yet to build the "is this suspicious" logic well, so I'm deliberately not trying to right now. That part comes later, once I've learned more.
What's Next
Trying to get a Python service reading this raw data and attempting an actual risk score β where I find out how much of the architecture reasoning from the last post actually survives being built.
Let's Discuss! π
If you remember the moment something about Go's concurrency model actually clicked for you (goroutines, channels, select, whatever it was) β what was the thing that made it click? Genuinely curious what other people's version of this moment looked like.

Top comments (0)