The demo agent’s withdrawal reverted. To find it in Jaeger, you don’t read through spans. You search for blockchain.tx.status=reverted and get the span. That works because the status is an attribute.
What is an attribute?
A key-value pair on a span that describes the operation it tracks (OpenTelemetry traces). The rules are short:
| Rule | |
|---|---|
| Key | A non-empty string. Case matters. |
| Value | String, boolean, integer, floating point, or an array of one of these |
| Same key twice | The new value overwrites the old one |
| How many | 128 per span by default; the SDK drops new keys after that |
The full definitions are in the common spec. Attributes that are set when the span starts are also visible to the sampler, which decides whether to keep the span.
Why are fees strings?
Because wei doesn’t fit. A JavaScript number is a double, exact only up to 2^53, which is about 0.009 ETH in wei. A signed 64-bit integer stops at about 9.22 ETH. A fee or a transfer can be larger than either.
The JavaScript API’s type checker rejects a bigint, and at runtime the SDK drops it with “Invalid attribute value set”. Converting with Number() silently rounds:
const fee = 1234567890123456789n; // wei, about 1.23 ETH
const span = tracer.startSpan('confirm 8453');span.setAttributes({ 'blockchain.chain.id': 8453, 'blockchain.tx.hash': '0x41837fea9c6d02d542c8fd48e32b26bd4ffd0e4762568884f34afbf66ae2b3ce', 'blockchain.tx.gas.used': 21000, 'fee.as_number': Number(fee), // precision lost 'blockchain.tx.fee': fee.toString(), // exact});span.end();'blockchain.tx.gas.used': 21000,'fee.as_number': 1234567890123456800,'blockchain.tx.fee': '1234567890123456789'The last three digits changed. The string keeps every one.
Which key names?
Use a standard name when one exists, such as error.type. Otherwise pick a namespace so your keys can’t collide with anyone else’s. OpenTelemetry has no conventions for blockchains yet, so hashspan uses blockchain.*, modelled on db.* and rpc.*.