lotus/chain/types.go
2019-07-05 16:36:08 +02:00

594 lines
12 KiB
Go

package chain
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/filecoin-project/go-lotus/chain/address"
"math/big"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
ipld "github.com/ipfs/go-ipld-format"
"github.com/multiformats/go-multihash"
"github.com/polydawn/refmt/obj/atlas"
)
func init() {
ipld.Register(0x1f, IpldDecode)
cbor.RegisterCborType(MessageReceipt{})
cbor.RegisterCborType(Actor{})
cbor.RegisterCborType(BlockMsg{})
///*
cbor.RegisterCborType(atlas.BuildEntry(BigInt{}).UseTag(2).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc(
func(i BigInt) ([]byte, error) {
if i.Int == nil {
return []byte{}, nil
}
return i.Bytes(), nil
})).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(x []byte) (BigInt, error) {
return BigFromBytes(x), nil
})).
Complete())
//*/
cbor.RegisterCborType(atlas.BuildEntry(SignedMessage{}).UseTag(45).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc(
func(sm SignedMessage) ([]interface{}, error) {
return []interface{}{
sm.Message,
sm.Signature,
}, nil
})).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(x []interface{}) (SignedMessage, error) {
sigb, ok := x[1].([]byte)
if !ok {
return SignedMessage{}, fmt.Errorf("signature in signed message was not bytes")
}
sig, err := SignatureFromBytes(sigb)
if err != nil {
return SignedMessage{}, err
}
return SignedMessage{
Message: x[0].(Message),
Signature: sig,
}, nil
})).
Complete())
cbor.RegisterCborType(atlas.BuildEntry(Signature{}).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc(
func(s Signature) ([]byte, error) {
buf := make([]byte, 4)
n := binary.PutUvarint(buf, uint64(s.TypeCode()))
return append(buf[:n], s.Data...), nil
})).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(x []byte) (Signature, error) {
return SignatureFromBytes(x)
})).
Complete())
cbor.RegisterCborType(atlas.BuildEntry(Message{}).UseTag(44).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc(
func(m Message) ([]interface{}, error) {
return []interface{}{
m.To.Bytes(),
m.From.Bytes(),
m.Nonce,
m.Value,
m.GasPrice,
m.GasLimit,
m.Method,
m.Params,
}, nil
})).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(arr []interface{}) (Message, error) {
to, err := address.NewFromBytes(arr[0].([]byte))
if err != nil {
return Message{}, err
}
from, err := address.NewFromBytes(arr[1].([]byte))
if err != nil {
return Message{}, err
}
nonce, ok := arr[2].(uint64)
if !ok {
return Message{}, fmt.Errorf("expected uint64 nonce at index 2")
}
value := arr[3].(BigInt)
gasPrice := arr[4].(BigInt)
gasLimit := arr[5].(BigInt)
method, _ := arr[6].(uint64)
params, _ := arr[7].([]byte)
if gasPrice.Nil() {
gasPrice = NewInt(0)
}
if gasLimit.Nil() {
gasLimit = NewInt(0)
}
return Message{
To: to,
From: from,
Nonce: nonce,
Value: value,
GasPrice: gasPrice,
GasLimit: gasLimit,
Method: method,
Params: params,
}, nil
})).
Complete())
cbor.RegisterCborType(atlas.BuildEntry(BlockHeader{}).UseTag(43).Transform().
TransformMarshal(atlas.MakeMarshalTransformFunc(
func(blk BlockHeader) ([]interface{}, error) {
if blk.Tickets == nil {
blk.Tickets = []Ticket{}
}
if blk.Parents == nil {
blk.Parents = []cid.Cid{}
}
return []interface{}{
blk.Miner.Bytes(),
blk.Tickets,
blk.ElectionProof,
blk.Parents,
blk.ParentWeight,
blk.Height,
blk.StateRoot,
blk.Messages,
blk.MessageReceipts,
}, nil
})).
TransformUnmarshal(atlas.MakeUnmarshalTransformFunc(
func(arr []interface{}) (BlockHeader, error) {
miner, err := address.NewFromBytes(arr[0].([]byte))
if err != nil {
return BlockHeader{}, err
}
tickets := []Ticket{}
ticketarr, _ := arr[1].([]interface{})
for _, t := range ticketarr {
tickets = append(tickets, Ticket(t.([]byte)))
}
electionProof, _ := arr[2].([]byte)
parents := []cid.Cid{}
parentsArr, _ := arr[3].([]interface{})
for _, p := range parentsArr {
parents = append(parents, p.(cid.Cid))
}
parentWeight := arr[4].(BigInt)
height := arr[5].(uint64)
stateRoot := arr[6].(cid.Cid)
msgscid := arr[7].(cid.Cid)
recscid := arr[8].(cid.Cid)
return BlockHeader{
Miner: miner,
Tickets: tickets,
ElectionProof: electionProof,
Parents: parents,
ParentWeight: parentWeight,
Height: height,
StateRoot: stateRoot,
Messages: msgscid,
MessageReceipts: recscid,
}, nil
})).
Complete())
}
type BigInt struct {
*big.Int
}
func NewInt(i uint64) BigInt {
return BigInt{big.NewInt(0).SetUint64(i)}
}
func BigFromBytes(b []byte) BigInt {
i := big.NewInt(0).SetBytes(b)
return BigInt{i}
}
func BigMul(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Mul(a.Int, b.Int)}
}
func BigAdd(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Add(a.Int, b.Int)}
}
func BigSub(a, b BigInt) BigInt {
return BigInt{big.NewInt(0).Sub(a.Int, b.Int)}
}
func BigCmp(a, b BigInt) int {
return a.Int.Cmp(b.Int)
}
func (bi *BigInt) Nil() bool {
return bi.Int == nil
}
type Actor struct {
Code cid.Cid
Head cid.Cid
Nonce uint64
Balance BigInt
}
type BlockHeader struct {
Miner address.Address
Tickets []Ticket
ElectionProof []byte
Parents []cid.Cid
ParentWeight BigInt
Height uint64
StateRoot cid.Cid
Messages cid.Cid
BLSAggregate Signature
MessageReceipts cid.Cid
}
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
data, err := b.Serialize()
if err != nil {
return nil, err
}
pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31)
c, err := pref.Sum(data)
if err != nil {
return nil, err
}
return block.NewBlockWithCid(data, c)
}
func (b *BlockHeader) Cid() cid.Cid {
sb, err := b.ToStorageBlock()
if err != nil {
panic(err)
}
return sb.Cid()
}
func DecodeBlock(b []byte) (*BlockHeader, error) {
var blk BlockHeader
if err := cbor.DecodeInto(b, &blk); err != nil {
return nil, err
}
return &blk, nil
}
func (blk *BlockHeader) Serialize() ([]byte, error) {
return cbor.DumpObject(blk)
}
type Message struct {
To address.Address
From address.Address
Nonce uint64
Value BigInt
GasPrice BigInt
GasLimit BigInt
Method uint64
Params []byte
}
func DecodeMessage(b []byte) (*Message, error) {
var msg Message
if err := cbor.DecodeInto(b, &msg); err != nil {
return nil, err
}
return &msg, nil
}
func (m *Message) Serialize() ([]byte, error) {
return cbor.DumpObject(m)
}
func (m *Message) ToStorageBlock() (block.Block, error) {
data, err := m.Serialize()
if err != nil {
return nil, err
}
pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31)
c, err := pref.Sum(data)
if err != nil {
return nil, err
}
return block.NewBlockWithCid(data, c)
}
func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
data, err := m.Serialize()
if err != nil {
return nil, err
}
pref := cid.NewPrefixV1(0x1f, multihash.BLAKE2B_MIN+31)
c, err := pref.Sum(data)
if err != nil {
return nil, err
}
return block.NewBlockWithCid(data, c)
}
func (m *SignedMessage) Cid() cid.Cid {
sb, err := m.ToStorageBlock()
if err != nil {
panic(err)
}
return sb.Cid()
}
type MessageReceipt struct {
ExitCode uint8
Return []byte
GasUsed BigInt
}
func (mr *MessageReceipt) Equals(o *MessageReceipt) bool {
return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && BigCmp(mr.GasUsed, o.GasUsed) == 0
}
type SignedMessage struct {
Message Message
Signature Signature
}
func DecodeSignedMessage(data []byte) (*SignedMessage, error) {
var msg SignedMessage
if err := cbor.DecodeInto(data, &msg); err != nil {
return nil, err
}
return &msg, nil
}
func (sm *SignedMessage) Serialize() ([]byte, error) {
data, err := cbor.DumpObject(sm)
if err != nil {
return nil, err
}
return data, nil
}
type TipSet struct {
cids []cid.Cid
blks []*BlockHeader
height uint64
}
func NewTipSet(blks []*BlockHeader) (*TipSet, error) {
var ts TipSet
ts.cids = []cid.Cid{blks[0].Cid()}
ts.blks = blks
for _, b := range blks[1:] {
if b.Height != blks[0].Height {
return nil, fmt.Errorf("cannot create tipset with mismatching heights")
}
ts.cids = append(ts.cids, b.Cid())
}
ts.height = blks[0].Height
return &ts, nil
}
func (ts *TipSet) Cids() []cid.Cid {
return ts.cids
}
func (ts *TipSet) Height() uint64 {
return ts.height
}
func (ts *TipSet) Parents() []cid.Cid {
return ts.blks[0].Parents
}
func (ts *TipSet) Blocks() []*BlockHeader {
return ts.blks
}
func (ts *TipSet) Equals(ots *TipSet) bool {
if len(ts.blks) != len(ots.blks) {
return false
}
for i, b := range ts.blks {
if b.Cid() != ots.blks[i].Cid() {
return false
}
}
return true
}
type Ticket []byte
type ElectionProof []byte
func IpldDecode(block block.Block) (ipld.Node, error) {
var i interface{}
if err := cbor.DecodeInto(block.RawData(), &i); err != nil {
panic(err)
}
fmt.Println("IPLD DECODE!")
return &filecoinIpldNode{i}, nil
}
type filecoinIpldNode struct {
val interface{}
}
func (f *filecoinIpldNode) Cid() cid.Cid {
switch t := f.val.(type) {
case BlockHeader:
return t.Cid()
case SignedMessage:
return t.Cid()
default:
panic("whats going on")
}
}
func (f *filecoinIpldNode) Copy() ipld.Node {
panic("no")
}
func (f *filecoinIpldNode) Links() []*ipld.Link {
switch t := f.val.(type) {
case BlockHeader:
fmt.Println("block links!", t.StateRoot)
return []*ipld.Link{
{
Cid: t.StateRoot,
},
{
Cid: t.Messages,
},
{
Cid: t.MessageReceipts,
},
}
case Message:
return nil
default:
panic("whats going on")
}
}
func (f *filecoinIpldNode) Resolve(path []string) (interface{}, []string, error) {
/*
switch t := f.val.(type) {
case Block:
switch path[0] {
}
case Message:
default:
panic("whats going on")
}
*/
panic("please dont call this")
}
// Tree lists all paths within the object under 'path', and up to the given depth.
// To list the entire object (similar to `find .`) pass "" and -1
func (f *filecoinIpldNode) Tree(path string, depth int) []string {
panic("dont call this either")
}
func (f *filecoinIpldNode) ResolveLink(path []string) (*ipld.Link, []string, error) {
panic("please no")
}
func (f *filecoinIpldNode) Stat() (*ipld.NodeStat, error) {
panic("dont call this")
}
func (f *filecoinIpldNode) Size() (uint64, error) {
panic("dont call this")
}
func (f *filecoinIpldNode) Loggable() map[string]interface{} {
return nil
}
func (f *filecoinIpldNode) RawData() []byte {
switch t := f.val.(type) {
case BlockHeader:
sb, err := t.ToStorageBlock()
if err != nil {
panic(err)
}
return sb.RawData()
case SignedMessage:
sb, err := t.ToStorageBlock()
if err != nil {
panic(err)
}
return sb.RawData()
default:
panic("whats going on")
}
}
func (f *filecoinIpldNode) String() string {
return "cats"
}
type FullBlock struct {
Header *BlockHeader
Messages []*SignedMessage
}
func (fb *FullBlock) Cid() cid.Cid {
return fb.Header.Cid()
}
type BlockMsg struct {
Header *BlockHeader
Messages []cid.Cid
}
func DecodeBlockMsg(b []byte) (*BlockMsg, error) {
var bm BlockMsg
if err := cbor.DecodeInto(b, &bm); err != nil {
return nil, err
}
return &bm, nil
}
func (bm *BlockMsg) Cid() cid.Cid {
return bm.Header.Cid()
}
func (bm *BlockMsg) Serialize() ([]byte, error) {
return cbor.DumpObject(bm)
}