package bsv
import "math/big"
type BlockHeader struct {
Version int32
PrevHash []byte
MerkleRoot []byte
Time uint32
Bits uint32
Nonce uint32
}
func NewBlockHeader(arg interface{}) (*BlockHeader, error) {
switch v := arg.(type) {
case []byte:
return BlockHeaderFromBuffer(v)
case *BufferReader:
return BlockHeaderFromBufferReader(v)
case map[string]interface{}:
return blockHeaderFromObject(v)
case string:
return BlockHeaderFromString(v)
default:
return nil, newError("InvalidArgument", "Unrecognized argument for BlockHeader")
}
}
func blockHeaderFromObject(data map[string]interface{}) (*BlockHeader, error) {
h := &BlockHeader{}
switch v := data["version"].(type) {
case int:
h.Version = int32(v)
case int32:
h.Version = v
case int64:
h.Version = int32(v)
case uint32:
h.Version = int32(v)
case float64:
h.Version = int32(v)
}
if v, ok := data["prevHash"].(string); ok {
h.PrevHash = reverseBuf(fromHex(v))
} else if v, ok := data["prevHash"].([]byte); ok {
h.PrevHash = v
}
if v, ok := data["merkleRoot"].(string); ok {
h.MerkleRoot = reverseBuf(fromHex(v))
} else if v, ok := data["merkleRoot"].([]byte); ok {
h.MerkleRoot = v
}
switch v := data["time"].(type) {
case int:
h.Time = uint32(v)
case int32:
h.Time = uint32(v)
case int64:
h.Time = uint32(v)
case uint32:
h.Time = v
case uint64:
h.Time = uint32(v)
case float64:
h.Time = uint32(v)
}
switch v := data["bits"].(type) {
case int:
h.Bits = uint32(v)
case int32:
h.Bits = uint32(v)
case int64:
h.Bits = uint32(v)
case uint32:
h.Bits = v
case uint64:
h.Bits = uint32(v)
case float64:
h.Bits = uint32(v)
}
switch v := data["nonce"].(type) {
case int:
h.Nonce = uint32(v)
case int32:
h.Nonce = uint32(v)
case int64:
h.Nonce = uint32(v)
case uint32:
h.Nonce = v
case uint64:
h.Nonce = uint32(v)
case float64:
h.Nonce = uint32(v)
}
return h, nil
}
func BlockHeaderFromBufferReader(br *BufferReader) (*BlockHeader, error) {
h := &BlockHeader{}
h.Version = br.ReadInt32LE()
h.PrevHash = br.Read(32)
h.MerkleRoot = br.Read(32)
h.Time = br.ReadUInt32LE()
h.Bits = br.ReadUInt32LE()
h.Nonce = br.ReadUInt32LE()
return h, nil
}
func BlockHeaderFromBuffer(buf []byte) (*BlockHeader, error) {
br, err := NewBufferReader(buf)
if err != nil {
return nil, err
}
return BlockHeaderFromBufferReader(br)
}
func BlockHeaderFromString(str string) (*BlockHeader, error) {
return BlockHeaderFromBuffer(fromHex(str))
}
func (h *BlockHeader) ToBufferWriter(bw *BufferWriter) *BufferWriter {
if bw == nil {
bw = NewBufferWriter()
}
bw.WriteInt32LE(h.Version)
bw.Write(h.PrevHash)
bw.Write(h.MerkleRoot)
bw.WriteUInt32LE(h.Time)
bw.WriteUInt32LE(h.Bits)
bw.WriteUInt32LE(h.Nonce)
return bw
}
func (h *BlockHeader) ToBuffer() []byte {
return h.ToBufferWriter(nil).ToBuffer()
}
func (h *BlockHeader) ToString() string { return toHex(h.ToBuffer()) }
func (h *BlockHeader) ToObject() map[string]interface{} {
return map[string]interface{}{
"hash": h.Hash(),
"version": h.Version,
"prevHash": toHex(reverseBuf(h.PrevHash)),
"merkleRoot": toHex(reverseBuf(h.MerkleRoot)),
"time": h.Time,
"bits": h.Bits,
"nonce": h.Nonce,
}
}
func (h *BlockHeader) getHash() []byte {
return (Hash{}).Sha256sha256(h.ToBuffer())
}
func (h *BlockHeader) Hash() string {
return toHex(reverseBuf(h.getHash()))
}
func (h *BlockHeader) GetTargetDifficulty(bits uint32) *BN {
if bits == 0 {
bits = h.Bits
}
target := NewBNFromNumber(int64(bits & 0xffffff))
mov := int64(8 * ((bits >> 24) - 3))
for mov > 0 {
target = target.Mul(big.NewInt(2))
mov--
}
return target
}
func (h *BlockHeader) ValidProofOfWork() bool {
pow, _ := NewBNFromHex(h.Hash())
target := h.GetTargetDifficulty(0)
return pow.Cmp(target.Int) <= 0
}
const (
BlockHeaderStartOfHeader = 8
MaxTimeOffset = 2 * 60 * 60
)
type Block struct {
Header *BlockHeader
Transactions []*Transaction
}
const BlockMaxBlockSize = 128000000
func NewBlock(arg interface{}) (*Block, error) {
switch v := arg.(type) {
case []byte:
return BlockFromBuffer(v)
case string:
return BlockFromString(v)
case *Block:
return v, nil
default:
return nil, newError("InvalidArgument", "Unrecognized argument for Block")
}
}
func BlockFromString(str string) (*Block, error) {
return BlockFromBuffer(fromHex(str))
}
func BlockFromBuffer(buf []byte) (*Block, error) {
br, err := NewBufferReader(buf)
if err != nil {
return nil, err
}
header, err := BlockHeaderFromBufferReader(br)
if err != nil {
return nil, err
}
block := &Block{Header: header, Transactions: []*Transaction{}}
txCount, err := br.ReadVarintNum()
if err != nil {
return nil, err
}
for i := 0; i < txCount; i++ {
tx, err := TransactionFromBufferReader(br)
if err != nil {
return nil, err
}
block.Transactions = append(block.Transactions, tx)
}
return block, nil
}
func BlockFromRawBlock(data []byte) (*Block, error) {
if len(data) < 8 {
return nil, newError("InvalidArgument", "raw block data too short")
}
blockSize := int(uint32(data[4]) | uint32(data[5])<<8 | uint32(data[6])<<16 | uint32(data[7])<<24)
blockEnd := 8 + blockSize
if blockEnd > len(data) {
blockEnd = len(data)
}
if blockEnd > len(data) {
return nil, newError("InvalidArgument", "raw block data truncated")
}
return BlockFromBuffer(data[8:blockEnd])
}
func (b *Block) ToBufferWriter(bw *BufferWriter) *BufferWriter {
if bw == nil {
bw = NewBufferWriter()
}
b.Header.ToBufferWriter(bw)
bw.WriteVarintNum(len(b.Transactions))
for _, tx := range b.Transactions {
bw.Write(tx.ToBuffer())
}
return bw
}
func (b *Block) ToBuffer() []byte {
return b.ToBufferWriter(nil).ToBuffer()
}
func (b *Block) ToString() string { return toHex(b.ToBuffer()) }
func (b *Block) ToObject() map[string]interface{} {
txs := make([]map[string]interface{}, 0, len(b.Transactions))
for _, tx := range b.Transactions {
txs = append(txs, map[string]interface{}{"txid": tx.GetID(), "hex": tx.ToHex()})
}
return map[string]interface{}{
"header": b.Header.ToObject(),
"transactions": txs,
}
}