-
Notifications
You must be signed in to change notification settings - Fork 440
extend explorer api with block.ID() and optional hexblock field #2418
base: master
Are you sure you want to change the base?
extend explorer api with block.ID() and optional hexblock field #2418
Conversation
0bcd834
to
d8e7ae0
Compare
api/explorer.go
Outdated
@@ -188,10 +193,17 @@ func (api *API) buildExplorerBlock(height types.BlockHeight, block types.Block) | |||
panic("incorrect request to buildExplorerBlock - block does not exist") | |||
} | |||
|
|||
hex_block := "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
@@ -214,7 +226,8 @@ func (api *API) explorerBlocksHandler(w http.ResponseWriter, req *http.Request, | |||
return | |||
} | |||
WriteJSON(w, ExplorerBlockGET{ | |||
Block: api.buildExplorerBlock(height, block), | |||
Block: api.buildExplorerBlock(height, block, | |||
req.FormValue("hexblock") == "true"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as per our discord discussion, we'll punt this to a follow-up PR
@@ -271,7 +284,8 @@ func (api *API) explorerHashHandler(w http.ResponseWriter, req *http.Request, ps | |||
if exists { | |||
WriteJSON(w, ExplorerHashGET{ | |||
HashType: "blockid", | |||
Block: api.buildExplorerBlock(height, block), | |||
Block: api.buildExplorerBlock(height, block, | |||
req.FormValue("hexblock") == "true"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
LGTM except for the final comments. Looking for review from @lukechampine |
api/explorer.go
Outdated
@@ -188,10 +193,17 @@ func (api *API) buildExplorerBlock(height types.BlockHeight, block types.Block) | |||
panic("incorrect request to buildExplorerBlock - block does not exist") | |||
} | |||
|
|||
var hexBlock string | |||
if hexBlockEnable { | |||
hexBlock = fmt.Sprintf("%x", encoding.Marshal(block)[:]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
encoding.Marshal
returns a []byte
so the [:]
slicing is unnecessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, I think we slightly prefer:
import "encoding/hex"
hex.EncodeToString(encoding.Marshal(block))
api/explorer.go
Outdated
return ExplorerBlock{ | ||
MinerPayoutIDs: mpoids, | ||
Transactions: etxns, | ||
RawBlock: block, | ||
HexBlock: hexBlock, | ||
BlockId: fmt.Sprintf("%x", encoding.Marshal(block.ID())[:]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
api/explorer.go
Outdated
@@ -20,6 +22,8 @@ type ( | |||
MinerPayoutIDs []types.SiacoinOutputID `json:"minerpayoutids"` | |||
Transactions []ExplorerTransaction `json:"transactions"` | |||
RawBlock types.Block `json:"rawblock"` | |||
HexBlock string `json:"hexblock"` | |||
BlockId string `json:"blockid"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be BlockID
api/explorer.go
Outdated
var hexBlock string | ||
if hexBlockEnable { | ||
hexBlock = hex.EncodeToString(encoding.Marshal(block)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for structs with optional fields, I generally prefer:
b := ExplorerBlock{
// required fields here...
}
if hexBlockEnable {
b.HexBlock = hex.EncodeToString(encoding.Marshal(block))
}
return b
7414741
to
88a7a5c
Compare
all done @DavidVorick and @lukechampine thanks for the idiomatic go |
api/explorer.go
Outdated
@@ -20,6 +22,8 @@ type ( | |||
MinerPayoutIDs []types.SiacoinOutputID `json:"minerpayoutids"` | |||
Transactions []ExplorerTransaction `json:"transactions"` | |||
RawBlock types.Block `json:"rawblock"` | |||
HexBlock string `json:"hexblock"` | |||
BlockID string `json:"blockid"` | |||
|
|||
modules.BlockFacts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
@@ -20,6 +22,8 @@ type ( | |||
MinerPayoutIDs []types.SiacoinOutputID `json:"minerpayoutids"` | |||
Transactions []ExplorerTransaction `json:"transactions"` | |||
RawBlock types.Block `json:"rawblock"` | |||
HexBlock string `json:"hexblock"` | |||
HexBlockID string `json:"blockid"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.