b7a4dbb07f
And use the new CidBuilder from the spec actors. This patch does not switch over to inline CIDs by default, but paves the way.
161 lines
3.2 KiB
Go
161 lines
3.2 KiB
Go
package types
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
block "github.com/ipfs/go-block-format"
|
|
"github.com/ipfs/go-cid"
|
|
xerrors "golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
)
|
|
|
|
const MessageVersion = 0
|
|
|
|
type ChainMsg interface {
|
|
Cid() cid.Cid
|
|
VMMessage() *Message
|
|
ToStorageBlock() (block.Block, error)
|
|
// FIXME: This is the *message* length, this name is misleading.
|
|
ChainLength() int
|
|
}
|
|
|
|
type Message struct {
|
|
Version int64
|
|
|
|
To address.Address
|
|
From address.Address
|
|
|
|
Nonce uint64
|
|
|
|
Value BigInt
|
|
|
|
GasPrice BigInt
|
|
GasLimit int64
|
|
|
|
Method abi.MethodNum
|
|
Params []byte
|
|
}
|
|
|
|
func (m *Message) Caller() address.Address {
|
|
return m.From
|
|
}
|
|
|
|
func (m *Message) Receiver() address.Address {
|
|
return m.To
|
|
}
|
|
|
|
func (m *Message) ValueReceived() abi.TokenAmount {
|
|
return m.Value
|
|
}
|
|
|
|
func DecodeMessage(b []byte) (*Message, error) {
|
|
var msg Message
|
|
if err := msg.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if msg.Version != MessageVersion {
|
|
return nil, fmt.Errorf("decoded message had incorrect version (%d)", msg.Version)
|
|
}
|
|
|
|
return &msg, nil
|
|
}
|
|
|
|
func (m *Message) Serialize() ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
if err := m.MarshalCBOR(buf); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func (m *Message) ChainLength() int {
|
|
ser, err := m.Serialize()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return len(ser)
|
|
}
|
|
|
|
func (m *Message) ToStorageBlock() (block.Block, error) {
|
|
data, err := m.Serialize()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := abi.CidBuilder.Sum(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return block.NewBlockWithCid(data, c)
|
|
}
|
|
|
|
func (m *Message) Cid() cid.Cid {
|
|
b, err := m.ToStorageBlock()
|
|
if err != nil {
|
|
panic(fmt.Sprintf("failed to marshal message: %s", err)) // I think this is maybe sketchy, what happens if we try to serialize a message with an undefined address in it?
|
|
}
|
|
|
|
return b.Cid()
|
|
}
|
|
|
|
func (m *Message) RequiredFunds() BigInt {
|
|
return BigAdd(
|
|
m.Value,
|
|
BigMul(m.GasPrice, NewInt(uint64(m.GasLimit))),
|
|
)
|
|
}
|
|
|
|
func (m *Message) VMMessage() *Message {
|
|
return m
|
|
}
|
|
|
|
func (m *Message) Equals(o *Message) bool {
|
|
return m.Cid() == o.Cid()
|
|
}
|
|
|
|
func (m *Message) ValidForBlockInclusion(minGas int64) error {
|
|
if m.Version != 0 {
|
|
return xerrors.New("'Version' unsupported")
|
|
}
|
|
|
|
if m.To == address.Undef {
|
|
return xerrors.New("'To' address cannot be empty")
|
|
}
|
|
|
|
if m.From == address.Undef {
|
|
return xerrors.New("'From' address cannot be empty")
|
|
}
|
|
|
|
if m.Value.LessThan(big.Zero()) {
|
|
return xerrors.New("'Value' field cannot be negative")
|
|
}
|
|
|
|
if m.Value.GreaterThan(TotalFilecoinInt) {
|
|
return xerrors.New("'Value' field cannot be greater than total filecoin supply")
|
|
}
|
|
|
|
if m.GasPrice.LessThan(big.Zero()) {
|
|
return xerrors.New("'GasPrice' field cannot be negative")
|
|
}
|
|
|
|
if m.GasLimit > build.BlockGasLimit {
|
|
return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
|
|
}
|
|
|
|
// since prices might vary with time, this is technically semantic validation
|
|
if m.GasLimit < minGas {
|
|
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
const TestGasLimit = 100e6
|