mirror of https://github.com/poanetwork/gecko.git
103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package timestampvm
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/ava-labs/gecko/ids"
|
|
|
|
"github.com/ava-labs/gecko/utils/formatting"
|
|
)
|
|
|
|
var (
|
|
errDBError = errors.New("error getting data from database")
|
|
errBadData = errors.New("data must be base 58 repr. of 32 bytes")
|
|
errNoSuchBlock = errors.New("couldn't get block from database. Does it exist?")
|
|
)
|
|
|
|
// Service is the API service for this VM
|
|
type Service struct{ vm *VM }
|
|
|
|
// ProposeBlockArgs are the arguments to function ProposeValue
|
|
type ProposeBlockArgs struct {
|
|
// Data in the block. Must be base 58 encoding of 32 bytes.
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
// ProposeBlockReply is the reply from function ProposeBlock
|
|
type ProposeBlockReply struct{ Success bool }
|
|
|
|
// ProposeBlock is an API method to propose a new block whose data is [args].Data.
|
|
// [args].Data must be a string repr. of a 32 byte array
|
|
func (s *Service) ProposeBlock(_ *http.Request, args *ProposeBlockArgs, reply *ProposeBlockReply) error {
|
|
byteFormatter := formatting.CB58{}
|
|
if err := byteFormatter.FromString(args.Data); err != nil {
|
|
return errBadData
|
|
}
|
|
dataSlice := byteFormatter.Bytes
|
|
if len(dataSlice) != dataLen {
|
|
return errBadData
|
|
}
|
|
var data [dataLen]byte // The data as an array of bytes
|
|
copy(data[:], dataSlice[:dataLen]) // Copy the bytes in dataSlice to data
|
|
s.vm.proposeBlock(data)
|
|
reply.Success = true
|
|
return nil
|
|
}
|
|
|
|
// APIBlock is the API representation of a block
|
|
type APIBlock struct {
|
|
Timestamp int64 `json:"timestamp"` // Timestamp of most recent block
|
|
Data string `json:"data"` // Data in the most recent block. Base 58 repr. of 5 bytes.
|
|
ID string `json:"id"` // String repr. of ID of the most recent block
|
|
ParentID string `json:"parentID"` // String repr. of ID of the most recent block's parent
|
|
}
|
|
|
|
// GetBlockArgs are the arguments to GetBlock
|
|
type GetBlockArgs struct {
|
|
// ID of the block we're getting.
|
|
// If left blank, gets the latest block
|
|
ID string
|
|
}
|
|
|
|
// GetBlockReply is the reply from GetBlock
|
|
type GetBlockReply struct {
|
|
APIBlock
|
|
}
|
|
|
|
// GetBlock gets the block whose ID is [args.ID]
|
|
// If [args.ID] is empty, get the latest block
|
|
func (s *Service) GetBlock(_ *http.Request, args *GetBlockArgs, reply *GetBlockReply) error {
|
|
var ID ids.ID
|
|
var err error
|
|
if args.ID == "" {
|
|
ID = s.vm.LastAccepted()
|
|
} else {
|
|
ID, err = ids.FromString(args.ID)
|
|
if err != nil {
|
|
return errors.New("problem parsing ID")
|
|
}
|
|
}
|
|
|
|
blockInterface, err := s.vm.GetBlock(ID)
|
|
if err != nil {
|
|
return errDatabase
|
|
}
|
|
|
|
block, ok := blockInterface.(*Block)
|
|
if !ok {
|
|
return errBadData
|
|
}
|
|
|
|
reply.APIBlock.ID = block.ID().String()
|
|
reply.APIBlock.Timestamp = block.Timestamp
|
|
reply.APIBlock.ParentID = block.ParentID().String()
|
|
byteFormatter := formatting.CB58{Bytes: block.Data[:]}
|
|
reply.Data = byteFormatter.String()
|
|
|
|
return nil
|
|
}
|