extend explorer api with block.ID() and optional hexblock field#2418
extend explorer api with block.ID() and optional hexblock field#2418petabytestorage wants to merge 6 commits intoNebulousLabs:masterfrom
Conversation
0bcd834 to
d8e7ae0
Compare
api/explorer.go
Outdated
| panic("incorrect request to buildExplorerBlock - block does not exist") | ||
| } | ||
|
|
||
| hex_block := "" |
There was a problem hiding this comment.
more idiomatic to do var hex_block string
Project consistently and strictly uses camel case throughout for variable names, need to do the same here.
|
hex_block_enabled -> hexBlockEnabled and hex_block -> hexBlock ty @DavidVorick |
| WriteJSON(w, ExplorerBlockGET{ | ||
| Block: api.buildExplorerBlock(height, block), | ||
| Block: api.buildExplorerBlock(height, block, | ||
| req.FormValue("hexblock") == "true"), |
There was a problem hiding this comment.
Sorry I didn't comment on this in the first pass. Wasn't sure what we wanted here, but after discussing with Luke, we agree that the call should return an error if hexblock is set to anything besides "true" or "false" - strict api reduces the liklihood of dev mistakes, and coherent errors around incorrect input make it easier to find the source of the mistake.
There was a problem hiding this comment.
Makes sense to me and I will do it. I copied this pattern from api/wallet.go where it appears twice and does only look for "true". I also guessed that the wallet.go would be more strict/secure than an explorer module. So I'm going to suggest the wallet.go "force" field should be considered as well if you want to use this pattern for example to avoid misleading other devs into copying around or learning a bad pattern. @DavidVorick
There was a problem hiding this comment.
Can you give me an example of the new pattern you and luke want in the pre-existing source code please? I'm looking through all the boolean flags in the system and not finding one "good" one according to your description.
There was a problem hiding this comment.
as per our discord discussion, we'll punt this to a follow-up PR
| HashType: "blockid", | ||
| Block: api.buildExplorerBlock(height, block), | ||
| Block: api.buildExplorerBlock(height, block, | ||
| req.FormValue("hexblock") == "true"), |
|
LGTM except for the final comments. Looking for review from @lukechampine |
api/explorer.go
Outdated
|
|
||
| var hexBlock string | ||
| if hexBlockEnable { | ||
| hexBlock = fmt.Sprintf("%x", encoding.Marshal(block)[:]) |
There was a problem hiding this comment.
encoding.Marshal returns a []byte so the [:] slicing is unnecessary
There was a problem hiding this comment.
also, I think we slightly prefer:
import "encoding/hex"
hex.EncodeToString(encoding.Marshal(block))
api/explorer.go
Outdated
| Transactions: etxns, | ||
| RawBlock: block, | ||
| HexBlock: hexBlock, | ||
| BlockId: fmt.Sprintf("%x", encoding.Marshal(block.ID())[:]), |
api/explorer.go
Outdated
| Transactions []ExplorerTransaction `json:"transactions"` | ||
| RawBlock types.Block `json:"rawblock"` | ||
| HexBlock string `json:"hexblock"` | ||
| BlockId string `json:"blockid"` |
api/explorer.go
Outdated
| var hexBlock string | ||
| if hexBlockEnable { | ||
| hexBlock = hex.EncodeToString(encoding.Marshal(block)) | ||
| } |
There was a problem hiding this comment.
for structs with optional fields, I generally prefer:
b := ExplorerBlock{
// required fields here...
}
if hexBlockEnable {
b.HexBlock = hex.EncodeToString(encoding.Marshal(block))
}
return b7414741 to
88a7a5c
Compare
|
all done @DavidVorick and @lukechampine thanks for the idiomatic go |
| HexBlock string `json:"hexblock"` | ||
| BlockID string `json:"blockid"` | ||
|
|
||
| modules.BlockFacts |
There was a problem hiding this comment.
hmm, changing to BlockID actually caused tests to start failing, because modules.BlockFacts has an embedded BlockID field.
Is it necessary to have a BlockID string field if we already have it as a [32]byte? If so, maybe call it HexBlockID?
There was a problem hiding this comment.
@lukechampine when i remove the field i get:
➜ Sia git:(explorer-patch) ✗ make
go install -tags 'netgo' -ldflags='-s -w' ./api ./build ./compatibility ./crypto ./encoding ./modules ./modules/consensus ./modules/explorer ./modules/gateway ./modules/host ./modules/host/contractmanager ./modules/renter ./modules/renter/contractor ./modules/renter/hostdb ./modules/renter/hostdb/hosttree ./modules/renter/proto ./modules/miner ./modules/wallet ./modules/transactionpool ./persist ./siac ./siad ./sync ./types
# github.com/NebulousLabs/Sia/api
api/explorer.go:201: unknown field 'BlockID' in struct literal of type ExplorerBlock
Makefile:75: recipe for target 'release-std' failed
make: *** [release-std] Error 2
therefore i renamed it to HexBlockID however i left the json named the standard way because to me it seems cleaner. please feel free to adjust again if you think there is a cleaner way to handle this.
ChrisSchinnerl
left a comment
There was a problem hiding this comment.
Looks pretty good to me. I'd only like to see a few minor changes that centralize the encoding of the types a bit more.
| @@ -188,13 +194,18 @@ func (api *API) buildExplorerBlock(height types.BlockHeight, block types.Block) | |||
| panic("incorrect request to buildExplorerBlock - block does not exist") | |||
There was a problem hiding this comment.
In my opinion we shouldn't crash if a user supplies an invalid height but return an error we write to the http response. What do you think @lukechampine @DavidVorick
| Transactions []ExplorerTransaction `json:"transactions"` | ||
| RawBlock types.Block `json:"rawblock"` | ||
| HexBlock string `json:"hexblock"` | ||
| HexBlockID string `json:"blockid"` |
There was a problem hiding this comment.
HexBlockID can probably be BlockID and have types.BlockID as a type.
types.BlockID implements String and MarshalJSON which should implicitly convert it to a hex string in WriteJSON.
| MinerPayoutIDs: mpoids, | ||
| Transactions: etxns, | ||
| RawBlock: block, | ||
| HexBlockID: hex.EncodeToString(encoding.Marshal(block.ID())), |
There was a problem hiding this comment.
As mentioned above this can probably just be a type.BlockID instead of having to encode yourself. That means it would be BlockID: block.ID(),
| BlockFacts: facts, | ||
| } | ||
| if hexBlockEnable { | ||
| b.HexBlock = hex.EncodeToString(encoding.Marshal(block)) |
There was a problem hiding this comment.
Could you implement something like the following in types/block.go?
// String returns a hex encoded marshalled Block.
func (b Block) String() string {
return hex.EncodeToString(encoding.Marshal(b))
}
That way you can simply do b.HexBlock = block.String() here.
block.ID() fixes "missing block" explorer issue with blocks with no transaction. "hexblock" optional return field (with "hexblock"="true" optional form parameter) provides verbatim hex encoded binary block to enable external applications and developer scaffolding.