2019-07-12 10:43:15 +00:00
package types
import (
2019-08-21 17:15:28 +00:00
"bytes"
2020-10-12 18:46:34 +00:00
"encoding/json"
2019-07-12 10:43:15 +00:00
"fmt"
"github.com/ipfs/go-cid"
2023-01-26 15:41:28 +00:00
block "github.com/ipfs/go-libipfs/blocks"
2022-06-15 10:06:22 +00:00
"golang.org/x/xerrors"
2019-07-12 10:43:15 +00:00
2019-12-19 20:13:17 +00:00
"github.com/filecoin-project/go-address"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/build"
2019-07-12 10:43:15 +00:00
)
2020-04-27 18:35:00 +00:00
const MessageVersion = 0
2020-03-25 19:13:09 +00:00
type ChainMsg interface {
Cid ( ) cid . Cid
VMMessage ( ) * Message
ToStorageBlock ( ) ( block . Block , error )
2020-06-26 23:13:14 +00:00
// FIXME: This is the *message* length, this name is misleading.
2020-03-25 19:13:09 +00:00
ChainLength ( ) int
}
2019-07-12 10:43:15 +00:00
type Message struct {
2020-08-20 04:37:21 +00:00
Version uint64
2020-04-27 18:35:00 +00:00
2019-07-12 10:43:15 +00:00
To address . Address
From address . Address
Nonce uint64
2020-08-06 17:09:03 +00:00
Value abi . TokenAmount
2019-07-12 10:43:15 +00:00
2020-08-06 17:09:03 +00:00
GasLimit int64
GasFeeCap abi . TokenAmount
GasPremium abi . TokenAmount
2019-07-12 10:43:15 +00:00
2020-02-11 01:43:26 +00:00
Method abi . MethodNum
2019-07-12 10:43:15 +00:00
Params [ ] byte
}
2020-06-02 14:29:39 +00:00
func ( m * Message ) Caller ( ) address . Address {
return m . From
2020-02-16 22:15:01 +00:00
}
2020-06-02 14:29:39 +00:00
func ( m * Message ) Receiver ( ) address . Address {
return m . To
2020-02-16 22:15:01 +00:00
}
2020-06-02 14:29:39 +00:00
func ( m * Message ) ValueReceived ( ) abi . TokenAmount {
return m . Value
2020-02-16 22:15:01 +00:00
}
2019-07-12 10:43:15 +00:00
func DecodeMessage ( b [ ] byte ) ( * Message , error ) {
var msg Message
2019-08-21 17:15:28 +00:00
if err := msg . UnmarshalCBOR ( bytes . NewReader ( b ) ) ; err != nil {
2019-07-12 10:43:15 +00:00
return nil , err
}
2020-04-27 18:35:00 +00:00
if msg . Version != MessageVersion {
return nil , fmt . Errorf ( "decoded message had incorrect version (%d)" , msg . Version )
}
2019-07-12 10:43:15 +00:00
return & msg , nil
}
func ( m * Message ) Serialize ( ) ( [ ] byte , error ) {
2019-08-21 17:15:28 +00:00
buf := new ( bytes . Buffer )
if err := m . MarshalCBOR ( buf ) ; err != nil {
return nil , err
}
return buf . Bytes ( ) , nil
2019-07-12 10:43:15 +00:00
}
2020-03-25 11:29:35 +00:00
func ( m * Message ) ChainLength ( ) int {
ser , err := m . Serialize ( )
if err != nil {
panic ( err )
}
return len ( ser )
}
2019-07-12 10:43:15 +00:00
func ( m * Message ) ToStorageBlock ( ) ( block . Block , error ) {
data , err := m . Serialize ( )
if err != nil {
return nil , err
}
2020-07-23 02:05:11 +00:00
c , err := abi . CidBuilder . Sum ( data )
2019-07-12 10:43:15 +00:00
if err != nil {
return nil , err
}
return block . NewBlockWithCid ( data , c )
}
2019-08-01 20:40:47 +00:00
func ( m * Message ) Cid ( ) cid . Cid {
b , err := m . ToStorageBlock ( )
if err != nil {
2019-11-16 23:41:14 +00:00
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?
2019-08-01 20:40:47 +00:00
}
return b . Cid ( )
}
2019-09-26 03:48:53 +00:00
2020-10-12 18:46:34 +00:00
type mCid struct {
* RawMessage
CID cid . Cid
}
type RawMessage Message
func ( m * Message ) MarshalJSON ( ) ( [ ] byte , error ) {
return json . Marshal ( & mCid {
RawMessage : ( * RawMessage ) ( m ) ,
CID : m . Cid ( ) ,
} )
}
2019-09-26 03:48:53 +00:00
func ( m * Message ) RequiredFunds ( ) BigInt {
2020-08-06 17:09:03 +00:00
return BigMul ( m . GasFeeCap , NewInt ( uint64 ( m . GasLimit ) ) )
2019-09-26 03:48:53 +00:00
}
2019-09-27 23:55:15 +00:00
func ( m * Message ) VMMessage ( ) * Message {
return m
}
2019-11-19 21:27:25 +00:00
func ( m * Message ) Equals ( o * Message ) bool {
return m . Cid ( ) == o . Cid ( )
}
2020-05-14 19:28:33 +00:00
2020-08-10 12:55:27 +00:00
func ( m * Message ) EqualCall ( o * Message ) bool {
m1 := * m
m2 := * o
m1 . GasLimit , m2 . GasLimit = 0 , 0
m1 . GasFeeCap , m2 . GasFeeCap = big . Zero ( ) , big . Zero ( )
m1 . GasPremium , m2 . GasPremium = big . Zero ( ) , big . Zero ( )
return ( & m1 ) . Equals ( & m2 )
}
2020-11-17 06:34:06 +00:00
func ( m * Message ) ValidForBlockInclusion ( minGas int64 , version network . Version ) error {
2020-05-14 19:28:33 +00:00
if m . Version != 0 {
return xerrors . New ( "'Version' unsupported" )
}
if m . To == address . Undef {
return xerrors . New ( "'To' address cannot be empty" )
}
2020-11-17 06:34:06 +00:00
if m . To == build . ZeroAddress && version >= network . Version7 {
return xerrors . New ( "invalid 'To' address" )
}
2022-10-19 04:38:35 +00:00
if ! abi . AddressValidForNetworkVersion ( m . To , version ) {
return xerrors . New ( "'To' address protocol unsupported for network version" )
}
2020-05-14 19:28:33 +00:00
if m . From == address . Undef {
return xerrors . New ( "'From' address cannot be empty" )
}
2022-10-19 04:38:35 +00:00
if ! abi . AddressValidForNetworkVersion ( m . From , version ) {
return xerrors . New ( "'From' address protocol unsupported for network version" )
}
2020-08-11 22:59:12 +00:00
if m . Value . Int == nil {
return xerrors . New ( "'Value' cannot be nil" )
}
2020-05-14 19:28:33 +00:00
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" )
}
2020-08-11 22:59:12 +00:00
if m . GasFeeCap . Int == nil {
return xerrors . New ( "'GasFeeCap' cannot be nil" )
}
2020-08-06 19:14:08 +00:00
if m . GasFeeCap . LessThan ( big . Zero ( ) ) {
2020-08-07 02:09:01 +00:00
return xerrors . New ( "'GasFeeCap' field cannot be negative" )
}
2020-08-11 22:59:12 +00:00
if m . GasPremium . Int == nil {
return xerrors . New ( "'GasPremium' cannot be nil" )
}
2020-08-07 02:09:01 +00:00
if m . GasPremium . LessThan ( big . Zero ( ) ) {
return xerrors . New ( "'GasPremium' field cannot be negative" )
2020-05-14 19:28:33 +00:00
}
2020-08-12 18:24:35 +00:00
if m . GasPremium . GreaterThan ( m . GasFeeCap ) {
return xerrors . New ( "'GasFeeCap' less than 'GasPremium'" )
}
2020-05-14 19:28:33 +00:00
if m . GasLimit > build . BlockGasLimit {
2022-08-01 15:15:26 +00:00
return xerrors . Errorf ( "'GasLimit' field cannot be greater than a block's gas limit (%d > %d)" , m . GasLimit , build . BlockGasLimit )
2020-05-14 19:28:33 +00:00
}
// since prices might vary with time, this is technically semantic validation
if m . GasLimit < minGas {
2020-10-13 17:20:11 +00:00
return xerrors . Errorf ( "'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d" , m . GasLimit , minGas )
2020-05-14 19:28:33 +00:00
}
return nil
}
2020-07-20 17:57:06 +00:00
const TestGasLimit = 100e6