I'm storing my data in a redis database and when I ask for it, I get a valid json back. The json looks like this:
{"Data":"hi","Hash":"000f7dcfca98450a0f405384db3878c1956cb98309e63cf2d0a963cff9f17260","PrevHash":"000daf177434acd55a3284787b793a3453c3d70eacdb9a84f5faed43adb2ff58","Nonce":8504,"TimeStamp":1611498968}
It's a valid json string (Go omits leading and traling quotes) but I get this error when unmarshalling. illegal base64 data at input byte 0
err = json.Unmarshal([]byte(item), &block)
type Block struct {
Data []byte
Hash []byte
PrevHash []byte
Nonce int
TimeStamp int64
}
func (chain *BlockChain) AddBlock(data string) {
var lastHash []byte
item, err := chain.Database.Get(ctx, "lastHash").Result()
Handle(err)
lastHash = []byte(item)
newBlock := createBlock(data, lastHash)
_, err = chain.Database.Set(ctx, StrHash(newBlock.Hash), newBlock, 0).Result()
Handle(err)
_, err = chain.Database.Set(ctx, "lastHash", newBlock.Hash, 0).Result()
}
func (chain *BlockChain) Iterator() *BlockChainIterator {
return &BlockChainIterator{
CurrentHash: chain.LastHash,
Database: chain.Database,
}
}
func (iterator *BlockChainIterator) Next() *Block {
var block *Block
item, err := iterator.Database.Get(ctx, StrHash(iterator.CurrentHash)).Result()
Handle(err)
err = json.Unmarshal([]byte(item), &block)
Handle(err)
iterator.CurrentHash = block.PrevHash
return block
}
// -----------------
// Utility Functions
// -----------------
// TODO: Think about this. Wouldn't it be better to store everything as strings rather than converting it?
type jsonBlock struct {
Data string
Hash string
PrevHash string
Nonce int
TimeStamp int64
}
// This function gets called automatically by go-redis
func (b *Block) MarshalBinary() ([]byte, error) {
jb := jsonBlock{
Data: string(b.Data),
Hash: StrHash(b.Hash),
PrevHash: StrHash(b.PrevHash),
Nonce: b.Nonce,
TimeStamp: b.TimeStamp,
}
return json.Marshal(jb)
}
The Hash value (and also PrevHash) in JSON is not the Base64 encoded form of the data, but rather a hexadecimal representation. If you try to unmarshal it into a Go value of type []byte, the encoding/json package assumes and try to interpret it as Base64 encoded data.
Same goes for the Data field: it should be of Go type string since it is not the Base64 encoded form, so change it to string.
Try to unmarshal Hash and PrevHash into fields of type string, and do hexa decoding using hex.DecodeString().
You may implement a custom unmarshaler to do this automatically.
A convenient way would be to create a HexData type that is a []byte but decodes from hex string:
type HexData []byte
func (h *HexData) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
decoded, err := hex.DecodeString(s)
if err != nil {
return err
}
*h = HexData(decoded)
return nil
}
Using it:
type Block struct {
Data string
Hash HexData
PrevHash HexData
Nonce int
TimeStamp int64
}
func main() {
var b Block
if err := json.Unmarshal([]byte(src), &b); err != nil {
panic(err)
}
fmt.Printf("%+v\n", b)
}
Output (try it on the Go Playground):
{Data:hi Hash:[0 15 125 207 202 152 69 10 15 64 83 132 219 56 120 193 149 108 185 131 9 230 60 242 208 169 99 207 249 241 114 96] PrevHash:[0 13 175 23 116 52 172 213 90 50 132 120 123 121 58 52 83 195 215 14 172 219 154 132 245 250 237 67 173 178 255 88] Nonce:8504 TimeStamp:1611498968}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With