Merge branch 'release/v1.20.0'
This commit is contained in:
commit
75c744a438
@ -1,2 +1,2 @@
|
||||
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWHkVVMJ1rfVLM5poNrgwTJiaDkpDLkPqQ9zVuNPQ7AJ6p
|
||||
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWRyzqeQd51HCvVK3nvegmnBsYYPLSZbxR3Q9XAoUrUZ18
|
||||
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWCa1wgMMBB9JjA2kYqaN1v5uh7xvcsc2gQJBHzPp7G57H
|
||||
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWD6fCvo1dyci6wsjTLyv7eJK73pCVz6RCQjbtPvbc8LYw
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,7 +4,6 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@ -71,7 +70,8 @@ const UpgradeSkyrHeight = 510
|
||||
|
||||
const UpgradeSharkHeight = 16800 // 6 days after genesis
|
||||
|
||||
const UpgradeHyggeHeight = math.MaxInt64
|
||||
// 2023-02-21T16:30:00Z
|
||||
const UpgradeHyggeHeight = 322354
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
|
@ -31,6 +31,10 @@ var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at e
|
||||
// tipset's parent. In the presence of null blocks, the height at which the message is invoked may
|
||||
// be less than the specified tipset.
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
// Copy the message as we modify it below.
|
||||
msgCopy := *msg
|
||||
msg = &msgCopy
|
||||
|
||||
if msg.GasLimit == 0 {
|
||||
msg.GasLimit = build.BlockGasLimit
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
gocrypto "github.com/filecoin-project/go-crypto"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
typescrypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
@ -38,11 +39,19 @@ type EthTx struct {
|
||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||
AccessList []EthHash `json:"accessList"`
|
||||
V EthBigInt `json:"yParity"`
|
||||
V EthBigInt `json:"v"`
|
||||
R EthBigInt `json:"r"`
|
||||
S EthBigInt `json:"s"`
|
||||
}
|
||||
|
||||
func (tx *EthTx) Reward(blkBaseFee big.Int) EthBigInt {
|
||||
availablePriorityFee := big.Sub(big.Int(tx.MaxFeePerGas), blkBaseFee)
|
||||
if big.Cmp(big.Int(tx.MaxPriorityFeePerGas), availablePriorityFee) <= 0 {
|
||||
return tx.MaxPriorityFeePerGas
|
||||
}
|
||||
return EthBigInt(availablePriorityFee)
|
||||
}
|
||||
|
||||
type EthTxArgs struct {
|
||||
ChainID int `json:"chainId"`
|
||||
Nonce int `json:"nonce"`
|
||||
@ -97,24 +106,31 @@ func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) {
|
||||
|
||||
func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
||||
var (
|
||||
to *EthAddress
|
||||
params []byte
|
||||
paramsReader = bytes.NewReader(msg.Params)
|
||||
err error
|
||||
to *EthAddress
|
||||
params []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if msg.Version != 0 {
|
||||
return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version)
|
||||
}
|
||||
|
||||
if len(msg.Params) > 0 {
|
||||
paramsReader := bytes.NewReader(msg.Params)
|
||||
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
||||
if err != nil {
|
||||
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
||||
}
|
||||
if paramsReader.Len() != 0 {
|
||||
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
|
||||
}
|
||||
if len(params) == 0 {
|
||||
return EthTxArgs{}, xerrors.Errorf("non-empty params encode empty byte array")
|
||||
}
|
||||
}
|
||||
|
||||
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
||||
switch msg.Method {
|
||||
case builtintypes.MethodsEAM.CreateExternal:
|
||||
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
||||
if err != nil {
|
||||
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
||||
}
|
||||
default:
|
||||
if msg.Method != builtintypes.MethodsEAM.CreateExternal {
|
||||
return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
|
||||
}
|
||||
} else if msg.Method == builtintypes.MethodsEVM.InvokeContract {
|
||||
@ -123,23 +139,12 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
to = &addr
|
||||
|
||||
if len(msg.Params) > 0 {
|
||||
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
||||
if err != nil {
|
||||
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return EthTxArgs{},
|
||||
xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)",
|
||||
msg.Method, builtintypes.MethodsEVM.InvokeContract)
|
||||
}
|
||||
|
||||
if paramsReader.Len() != 0 {
|
||||
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
|
||||
}
|
||||
|
||||
return EthTxArgs{
|
||||
ChainID: build.Eip155ChainId,
|
||||
Nonce: int(msg.Nonce),
|
||||
@ -159,34 +164,26 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er
|
||||
|
||||
var err error
|
||||
var params []byte
|
||||
var to address.Address
|
||||
method := builtintypes.MethodsEVM.InvokeContract
|
||||
// nil indicates the EAM, only CreateExternal is allowed
|
||||
if tx.To == nil {
|
||||
to = builtintypes.EthereumAddressManagerActorAddr
|
||||
method = builtintypes.MethodsEAM.CreateExternal
|
||||
if len(tx.Input) == 0 {
|
||||
return nil, xerrors.New("cannot call CreateExternal without params")
|
||||
}
|
||||
|
||||
if len(tx.Input) > 0 {
|
||||
buf := new(bytes.Buffer)
|
||||
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
|
||||
return nil, xerrors.Errorf("failed to serialize Create params: %w", err)
|
||||
return nil, xerrors.Errorf("failed to write input args: %w", err)
|
||||
}
|
||||
|
||||
params = buf.Bytes()
|
||||
}
|
||||
|
||||
var to address.Address
|
||||
var method abi.MethodNum
|
||||
// nil indicates the EAM, only CreateExternal is allowed
|
||||
if tx.To == nil {
|
||||
method = builtintypes.MethodsEAM.CreateExternal
|
||||
to = builtintypes.EthereumAddressManagerActorAddr
|
||||
} else {
|
||||
method = builtintypes.MethodsEVM.InvokeContract
|
||||
to, err = tx.To.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err)
|
||||
}
|
||||
if len(tx.Input) > 0 {
|
||||
buf := new(bytes.Buffer)
|
||||
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
|
||||
return nil, xerrors.Errorf("failed to write input args: %w", err)
|
||||
}
|
||||
params = buf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
|
@ -2643,7 +2643,7 @@ Response:
|
||||
"accessList": [
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
],
|
||||
"yParity": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
}
|
||||
@ -2682,7 +2682,7 @@ Response:
|
||||
"accessList": [
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
],
|
||||
"yParity": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
}
|
||||
@ -2720,7 +2720,7 @@ Response:
|
||||
"accessList": [
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
],
|
||||
"yParity": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
}
|
||||
|
2
extern/filecoin-ffi
vendored
2
extern/filecoin-ffi
vendored
@ -1 +1 @@
|
||||
Subproject commit 4c503e5e2291b5d541f89d982d975e7994536a54
|
||||
Subproject commit 7efaa7b47fe9d4bdb4ba0b2a0fafa4e573864ee5
|
2
go.mod
2
go.mod
@ -44,7 +44,7 @@ require (
|
||||
github.com/filecoin-project/go-legs v0.4.4
|
||||
github.com/filecoin-project/go-padreader v0.0.1
|
||||
github.com/filecoin-project/go-paramfetch v0.0.4
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc2
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc3
|
||||
github.com/filecoin-project/go-statemachine v1.0.2
|
||||
github.com/filecoin-project/go-statestore v0.2.0
|
||||
github.com/filecoin-project/go-storedcounter v0.1.0
|
||||
|
4
go.sum
4
go.sum
@ -356,8 +356,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS
|
||||
github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||
github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||
github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc2 h1:nl92h86XridAoy0fjvW+8/8/eI0caVSm0fhAnIvtR64=
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc2/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024=
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc3 h1:qExCc2swTe5ndsiu9dEoMqIwppjuTNRbsAFgpzHnHbc=
|
||||
github.com/filecoin-project/go-state-types v0.10.0-rc3/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
|
||||
github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
|
||||
|
1
itests/contracts/GetDifficulty.hex
Normal file
1
itests/contracts/GetDifficulty.hex
Normal file
@ -0,0 +1 @@
|
||||
608060405234801561001057600080fd5b5060b58061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063b6baffe314602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea2646970667358221220c113f1abaabaed6a0324d363896b0d15a8bca7b9a540948a5be5b636a12a534f64736f6c63430008110033
|
9
itests/contracts/GetDifficulty.sol
Normal file
9
itests/contracts/GetDifficulty.sol
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity >=0.8.17;
|
||||
|
||||
contract GetDifficulty {
|
||||
function getDifficulty () public view returns (uint256) {
|
||||
return block.difficulty;
|
||||
}
|
||||
}
|
||||
|
1
itests/contracts/TransparentUpgradeableProxy.hex
Normal file
1
itests/contracts/TransparentUpgradeableProxy.hex
Normal file
File diff suppressed because one or more lines are too long
590
itests/contracts/TransparentUpgradeableProxy.sol
Normal file
590
itests/contracts/TransparentUpgradeableProxy.sol
Normal file
@ -0,0 +1,590 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
abstract contract Initializable {
|
||||
uint8 private _initialized;
|
||||
|
||||
bool private _initializing;
|
||||
|
||||
event Initialized(uint8 version);
|
||||
|
||||
modifier initializer() {
|
||||
bool isTopLevelCall = !_initializing;
|
||||
require(
|
||||
(isTopLevelCall && _initialized < 1) ||
|
||||
(!Address.isContract(address(this)) && _initialized == 1),
|
||||
"Initializable: contract is already initialized"
|
||||
);
|
||||
_initialized = 1;
|
||||
if (isTopLevelCall) {
|
||||
_initializing = true;
|
||||
}
|
||||
_;
|
||||
if (isTopLevelCall) {
|
||||
_initializing = false;
|
||||
emit Initialized(1);
|
||||
}
|
||||
}
|
||||
|
||||
modifier reinitializer(uint8 version) {
|
||||
require(
|
||||
!_initializing && _initialized < version,
|
||||
"Initializable: contract is already initialized"
|
||||
);
|
||||
_initialized = version;
|
||||
_initializing = true;
|
||||
_;
|
||||
_initializing = false;
|
||||
emit Initialized(version);
|
||||
}
|
||||
|
||||
modifier onlyInitializing() {
|
||||
require(_initializing, "Initializable: contract is not initializing");
|
||||
_;
|
||||
}
|
||||
|
||||
function _disableInitializers() internal virtual {
|
||||
require(!_initializing, "Initializable: contract is initializing");
|
||||
if (_initialized != type(uint8).max) {
|
||||
_initialized = type(uint8).max;
|
||||
emit Initialized(type(uint8).max);
|
||||
}
|
||||
}
|
||||
|
||||
function _getInitializedVersion() internal view returns (uint8) {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
function _isInitializing() internal view returns (bool) {
|
||||
return _initializing;
|
||||
}
|
||||
}
|
||||
|
||||
contract Implementation4 is Initializable {
|
||||
uint256 internal _value;
|
||||
|
||||
function initialize() public initializer {}
|
||||
|
||||
function setValue(uint256 _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
|
||||
function getValue() public view returns (uint256) {
|
||||
return _value;
|
||||
}
|
||||
|
||||
fallback() external {
|
||||
_value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
contract Implementation2 is Initializable {
|
||||
uint256 internal _value;
|
||||
|
||||
function initialize() public initializer {}
|
||||
|
||||
function setValue(uint256 _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
|
||||
function getValue() public view returns (uint256) {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
abstract contract Proxy {
|
||||
function _delegate(address implementation) internal virtual {
|
||||
assembly {
|
||||
calldatacopy(0, 0, calldatasize())
|
||||
|
||||
let result := delegatecall(
|
||||
gas(),
|
||||
implementation,
|
||||
0,
|
||||
calldatasize(),
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
returndatacopy(0, 0, returndatasize())
|
||||
|
||||
switch result
|
||||
case 0 {
|
||||
revert(0, returndatasize())
|
||||
}
|
||||
default {
|
||||
return(0, returndatasize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _implementation() internal view virtual returns (address);
|
||||
|
||||
function _fallback() internal virtual {
|
||||
_beforeFallback();
|
||||
_delegate(_implementation());
|
||||
}
|
||||
|
||||
fallback() external payable virtual {
|
||||
_fallback();
|
||||
}
|
||||
|
||||
receive() external payable virtual {
|
||||
_fallback();
|
||||
}
|
||||
|
||||
function _beforeFallback() internal virtual {}
|
||||
}
|
||||
|
||||
interface IBeacon {
|
||||
function implementation() external view returns (address);
|
||||
}
|
||||
|
||||
interface IERC1822Proxiable {
|
||||
function proxiableUUID() external view returns (bytes32);
|
||||
}
|
||||
|
||||
library Address {
|
||||
function isContract(address account) internal view returns (bool) {
|
||||
return account.code.length > 0;
|
||||
}
|
||||
|
||||
function sendValue(address payable recipient, uint256 amount) internal {
|
||||
require(
|
||||
address(this).balance >= amount,
|
||||
"Address: insufficient balance"
|
||||
);
|
||||
|
||||
(bool success, ) = recipient.call{value: amount}("");
|
||||
require(
|
||||
success,
|
||||
"Address: unable to send value, recipient may have reverted"
|
||||
);
|
||||
}
|
||||
|
||||
function functionCall(
|
||||
address target,
|
||||
bytes memory data
|
||||
) internal returns (bytes memory) {
|
||||
return
|
||||
functionCallWithValue(
|
||||
target,
|
||||
data,
|
||||
0,
|
||||
"Address: low-level call failed"
|
||||
);
|
||||
}
|
||||
|
||||
function functionCall(
|
||||
address target,
|
||||
bytes memory data,
|
||||
string memory errorMessage
|
||||
) internal returns (bytes memory) {
|
||||
return functionCallWithValue(target, data, 0, errorMessage);
|
||||
}
|
||||
|
||||
function functionCallWithValue(
|
||||
address target,
|
||||
bytes memory data,
|
||||
uint256 value
|
||||
) internal returns (bytes memory) {
|
||||
return
|
||||
functionCallWithValue(
|
||||
target,
|
||||
data,
|
||||
value,
|
||||
"Address: low-level call with value failed"
|
||||
);
|
||||
}
|
||||
|
||||
function functionCallWithValue(
|
||||
address target,
|
||||
bytes memory data,
|
||||
uint256 value,
|
||||
string memory errorMessage
|
||||
) internal returns (bytes memory) {
|
||||
require(
|
||||
address(this).balance >= value,
|
||||
"Address: insufficient balance for call"
|
||||
);
|
||||
(bool success, bytes memory returndata) = target.call{value: value}(
|
||||
data
|
||||
);
|
||||
return
|
||||
verifyCallResultFromTarget(
|
||||
target,
|
||||
success,
|
||||
returndata,
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
|
||||
function functionStaticCall(
|
||||
address target,
|
||||
bytes memory data
|
||||
) internal view returns (bytes memory) {
|
||||
return
|
||||
functionStaticCall(
|
||||
target,
|
||||
data,
|
||||
"Address: low-level static call failed"
|
||||
);
|
||||
}
|
||||
|
||||
function functionStaticCall(
|
||||
address target,
|
||||
bytes memory data,
|
||||
string memory errorMessage
|
||||
) internal view returns (bytes memory) {
|
||||
(bool success, bytes memory returndata) = target.staticcall(data);
|
||||
return
|
||||
verifyCallResultFromTarget(
|
||||
target,
|
||||
success,
|
||||
returndata,
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
|
||||
function functionDelegateCall(
|
||||
address target,
|
||||
bytes memory data
|
||||
) internal returns (bytes memory) {
|
||||
return
|
||||
functionDelegateCall(
|
||||
target,
|
||||
data,
|
||||
"Address: low-level delegate call failed"
|
||||
);
|
||||
}
|
||||
|
||||
function functionDelegateCall(
|
||||
address target,
|
||||
bytes memory data,
|
||||
string memory errorMessage
|
||||
) internal returns (bytes memory) {
|
||||
(bool success, bytes memory returndata) = target.delegatecall(data);
|
||||
return
|
||||
verifyCallResultFromTarget(
|
||||
target,
|
||||
success,
|
||||
returndata,
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
|
||||
function verifyCallResultFromTarget(
|
||||
address target,
|
||||
bool success,
|
||||
bytes memory returndata,
|
||||
string memory errorMessage
|
||||
) internal view returns (bytes memory) {
|
||||
if (success) {
|
||||
if (returndata.length == 0) {
|
||||
require(isContract(target), "Address: call to non-contract");
|
||||
}
|
||||
return returndata;
|
||||
} else {
|
||||
_revert(returndata, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function verifyCallResult(
|
||||
bool success,
|
||||
bytes memory returndata,
|
||||
string memory errorMessage
|
||||
) internal pure returns (bytes memory) {
|
||||
if (success) {
|
||||
return returndata;
|
||||
} else {
|
||||
_revert(returndata, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function _revert(
|
||||
bytes memory returndata,
|
||||
string memory errorMessage
|
||||
) private pure {
|
||||
if (returndata.length > 0) {
|
||||
assembly {
|
||||
let returndata_size := mload(returndata)
|
||||
revert(add(32, returndata), returndata_size)
|
||||
}
|
||||
} else {
|
||||
revert(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
library StorageSlot {
|
||||
struct AddressSlot {
|
||||
address value;
|
||||
}
|
||||
|
||||
struct BooleanSlot {
|
||||
bool value;
|
||||
}
|
||||
|
||||
struct Bytes32Slot {
|
||||
bytes32 value;
|
||||
}
|
||||
|
||||
struct Uint256Slot {
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
function getAddressSlot(
|
||||
bytes32 slot
|
||||
) internal pure returns (AddressSlot storage r) {
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
function getBooleanSlot(
|
||||
bytes32 slot
|
||||
) internal pure returns (BooleanSlot storage r) {
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
function getBytes32Slot(
|
||||
bytes32 slot
|
||||
) internal pure returns (Bytes32Slot storage r) {
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
|
||||
function getUint256Slot(
|
||||
bytes32 slot
|
||||
) internal pure returns (Uint256Slot storage r) {
|
||||
assembly {
|
||||
r.slot := slot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract contract ERC1967Upgrade {
|
||||
bytes32 private constant _ROLLBACK_SLOT =
|
||||
0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
|
||||
|
||||
bytes32 internal constant _IMPLEMENTATION_SLOT =
|
||||
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
||||
|
||||
event Upgraded(address indexed implementation);
|
||||
|
||||
function _getImplementation() internal view returns (address) {
|
||||
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
|
||||
}
|
||||
|
||||
function _setImplementation(address newImplementation) private {
|
||||
require(
|
||||
Address.isContract(newImplementation),
|
||||
"ERC1967: new implementation is not a contract"
|
||||
);
|
||||
StorageSlot
|
||||
.getAddressSlot(_IMPLEMENTATION_SLOT)
|
||||
.value = newImplementation;
|
||||
}
|
||||
|
||||
function _upgradeTo(address newImplementation) internal {
|
||||
_setImplementation(newImplementation);
|
||||
emit Upgraded(newImplementation);
|
||||
}
|
||||
|
||||
function _upgradeToAndCall(
|
||||
address newImplementation,
|
||||
bytes memory data,
|
||||
bool forceCall
|
||||
) internal {
|
||||
_upgradeTo(newImplementation);
|
||||
if (data.length > 0 || forceCall) {
|
||||
Address.functionDelegateCall(newImplementation, data);
|
||||
}
|
||||
}
|
||||
|
||||
function _upgradeToAndCallUUPS(
|
||||
address newImplementation,
|
||||
bytes memory data,
|
||||
bool forceCall
|
||||
) internal {
|
||||
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
|
||||
_setImplementation(newImplementation);
|
||||
} else {
|
||||
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (
|
||||
bytes32 slot
|
||||
) {
|
||||
require(
|
||||
slot == _IMPLEMENTATION_SLOT,
|
||||
"ERC1967Upgrade: unsupported proxiableUUID"
|
||||
);
|
||||
} catch {
|
||||
revert("ERC1967Upgrade: new implementation is not UUPS");
|
||||
}
|
||||
_upgradeToAndCall(newImplementation, data, forceCall);
|
||||
}
|
||||
}
|
||||
|
||||
bytes32 internal constant _ADMIN_SLOT =
|
||||
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
|
||||
|
||||
event AdminChanged(address previousAdmin, address newAdmin);
|
||||
|
||||
function _getAdmin() internal view returns (address) {
|
||||
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
|
||||
}
|
||||
|
||||
function _setAdmin(address newAdmin) private {
|
||||
require(
|
||||
newAdmin != address(0),
|
||||
"ERC1967: new admin is the zero address"
|
||||
);
|
||||
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
|
||||
}
|
||||
|
||||
function _changeAdmin(address newAdmin) internal {
|
||||
emit AdminChanged(_getAdmin(), newAdmin);
|
||||
_setAdmin(newAdmin);
|
||||
}
|
||||
|
||||
bytes32 internal constant _BEACON_SLOT =
|
||||
0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
|
||||
|
||||
event BeaconUpgraded(address indexed beacon);
|
||||
|
||||
function _getBeacon() internal view returns (address) {
|
||||
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
|
||||
}
|
||||
|
||||
function _setBeacon(address newBeacon) private {
|
||||
require(
|
||||
Address.isContract(newBeacon),
|
||||
"ERC1967: new beacon is not a contract"
|
||||
);
|
||||
require(
|
||||
Address.isContract(IBeacon(newBeacon).implementation()),
|
||||
"ERC1967: beacon implementation is not a contract"
|
||||
);
|
||||
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
|
||||
}
|
||||
|
||||
function _upgradeBeaconToAndCall(
|
||||
address newBeacon,
|
||||
bytes memory data,
|
||||
bool forceCall
|
||||
) internal {
|
||||
_setBeacon(newBeacon);
|
||||
emit BeaconUpgraded(newBeacon);
|
||||
if (data.length > 0 || forceCall) {
|
||||
Address.functionDelegateCall(
|
||||
IBeacon(newBeacon).implementation(),
|
||||
data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
|
||||
constructor(address _logic, bytes memory _data) payable {
|
||||
_upgradeToAndCall(_logic, _data, false);
|
||||
}
|
||||
|
||||
function _implementation()
|
||||
internal
|
||||
view
|
||||
virtual
|
||||
override
|
||||
returns (address impl)
|
||||
{
|
||||
return ERC1967Upgrade._getImplementation();
|
||||
}
|
||||
}
|
||||
|
||||
contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||
constructor(address _logic) payable ERC1967Proxy(_logic, "") {
|
||||
_changeAdmin(msg.sender);
|
||||
}
|
||||
|
||||
modifier ifAdmin() {
|
||||
if (msg.sender == _getAdmin()) {
|
||||
_;
|
||||
} else {
|
||||
_fallback();
|
||||
}
|
||||
}
|
||||
|
||||
function admin() external payable ifAdmin returns (address admin_) {
|
||||
_requireZeroValue();
|
||||
admin_ = _getAdmin();
|
||||
}
|
||||
|
||||
function implementation()
|
||||
external
|
||||
payable
|
||||
ifAdmin
|
||||
returns (address implementation_)
|
||||
{
|
||||
_requireZeroValue();
|
||||
implementation_ = _implementation();
|
||||
}
|
||||
|
||||
function changeAdmin(address newAdmin) external payable virtual ifAdmin {
|
||||
_requireZeroValue();
|
||||
_changeAdmin(newAdmin);
|
||||
}
|
||||
|
||||
function upgradeTo(address newImplementation) external payable ifAdmin {
|
||||
_requireZeroValue();
|
||||
_upgradeToAndCall(newImplementation, bytes(""), false);
|
||||
}
|
||||
|
||||
function upgradeToAndCall(
|
||||
address newImplementation,
|
||||
bytes calldata data
|
||||
) external payable ifAdmin {
|
||||
_upgradeToAndCall(newImplementation, data, true);
|
||||
}
|
||||
|
||||
function _admin() internal view virtual returns (address) {
|
||||
return _getAdmin();
|
||||
}
|
||||
|
||||
function _beforeFallback() internal virtual override {
|
||||
require(
|
||||
msg.sender != _getAdmin(),
|
||||
"TransparentUpgradeableProxy: admin cannot fallback to proxy target"
|
||||
);
|
||||
super._beforeFallback();
|
||||
}
|
||||
|
||||
function _requireZeroValue() private {
|
||||
require(msg.value == 0);
|
||||
}
|
||||
}
|
||||
|
||||
contract TestHelper {
|
||||
function getValue(address proxyAddress) public returns (uint256) {
|
||||
Implementation2 proxyInstance2 = Implementation2(proxyAddress);
|
||||
return proxyInstance2.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
contract TransparentUpgradeableProxyTestRunner {
|
||||
function test() public {
|
||||
assert(0 == getValue());
|
||||
}
|
||||
|
||||
function getValue() public returns (uint256) {
|
||||
Implementation4 instance4 = new Implementation4();
|
||||
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||
address(instance4)
|
||||
);
|
||||
Implementation2 instance2 = new Implementation2();
|
||||
proxy.upgradeTo(address(instance2));
|
||||
//use helper because proxy admin can't call getValue()
|
||||
TestHelper h = new TestHelper();
|
||||
return h.getValue(address(proxy));
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ set -o pipefail
|
||||
# to compile all of the .sol files to their corresponding evm binary files stored as .hex
|
||||
# solc outputs to stdout a format that we just want to grab the last line of and then remove the trailing newline on that line
|
||||
|
||||
find . -name \*.sol -print0 |
|
||||
find . -maxdepth 1 -name \*.sol -print0 |
|
||||
xargs -0 -I{} bash -euc -o pipefail 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'
|
||||
|
||||
|
||||
@ -17,3 +17,7 @@ for filename in Constructor TestApp ValueSender Create2Factory DeployValueTest;
|
||||
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
||||
done
|
||||
|
||||
for filename in TransparentUpgradeableProxy ; do
|
||||
echo $filename
|
||||
solc --bin $filename.sol | tail -n1| tr -d "\n" > $filename.hex
|
||||
done
|
||||
|
@ -28,7 +28,7 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
defer cancel()
|
||||
|
||||
// Wait for the network to create 20 blocks
|
||||
<-time.After(20 * blockTime)
|
||||
client.WaitTillChain(ctx, kit.HeightAtLeast(20))
|
||||
|
||||
history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{5, "0x10"}),
|
||||
@ -37,6 +37,7 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
require.Equal(6, len(history.BaseFeePerGas))
|
||||
require.Equal(5, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||
require.Nil(history.Reward)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{"5", "0x10"}),
|
||||
@ -45,6 +46,7 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
require.Equal(6, len(history.BaseFeePerGas))
|
||||
require.Equal(5, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||
require.Nil(history.Reward)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{"0x10", "0x12"}),
|
||||
@ -53,6 +55,7 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
require.Equal(17, len(history.BaseFeePerGas))
|
||||
require.Equal(16, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock)
|
||||
require.Nil(history.Reward)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{5, "0x10"}),
|
||||
@ -61,6 +64,7 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
require.Equal(6, len(history.BaseFeePerGas))
|
||||
require.Equal(5, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||
require.Nil(history.Reward)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{5, "10"}),
|
||||
@ -69,19 +73,28 @@ func TestEthFeeHistory(t *testing.T) {
|
||||
require.Equal(6, len(history.BaseFeePerGas))
|
||||
require.Equal(5, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
||||
require.Nil(history.Reward)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{5, "10", &[]float64{0.25, 0.50, 0.75}}),
|
||||
json.Marshal([]interface{}{5, "10", &[]float64{25, 50, 75}}),
|
||||
).Assert(require.NoError))
|
||||
require.NoError(err)
|
||||
require.Equal(6, len(history.BaseFeePerGas))
|
||||
require.Equal(5, len(history.GasUsedRatio))
|
||||
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
||||
require.NotNil(history.Reward)
|
||||
require.Equal(0, len(*history.Reward))
|
||||
require.Equal(5, len(*history.Reward))
|
||||
for _, arr := range *history.Reward {
|
||||
require.Equal(3, len(arr))
|
||||
}
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{1025, "10", &[]float64{0.25, 0.50, 0.75}}),
|
||||
json.Marshal([]interface{}{1025, "10", &[]float64{25, 50, 75}}),
|
||||
).Assert(require.NoError))
|
||||
require.Error(err)
|
||||
|
||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||
json.Marshal([]interface{}{5, "10", &[]float64{}}),
|
||||
).Assert(require.NoError))
|
||||
require.NoError(err)
|
||||
}
|
||||
|
@ -136,6 +136,113 @@ func TestEthNewPendingTransactionFilter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthNewPendingTransactionSub(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
kit.QuietAllLogsExcept("events", "messagepool")
|
||||
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC())
|
||||
ens.InterconnectAll().BeginMining(10 * time.Millisecond)
|
||||
|
||||
// create a new address where to send funds.
|
||||
addr, err := client.WalletNew(ctx, types.KTBLS)
|
||||
require.NoError(err)
|
||||
|
||||
// get the existing balance from the default wallet to then split it.
|
||||
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||
require.NoError(err)
|
||||
|
||||
// install filter
|
||||
subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "newPendingTransactions"})).Assert(require.NoError))
|
||||
require.NoError(err)
|
||||
|
||||
var subResponses []ethtypes.EthSubscriptionResponse
|
||||
err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error {
|
||||
subResponses = append(subResponses, *resp)
|
||||
return nil
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
const iterations = 100
|
||||
|
||||
// we'll send half our balance (saving the other half for gas),
|
||||
// in `iterations` increments.
|
||||
toSend := big.Div(bal, big.NewInt(2))
|
||||
each := big.Div(toSend, big.NewInt(iterations))
|
||||
|
||||
waitAllCh := make(chan struct{})
|
||||
go func() {
|
||||
headChangeCh, err := client.ChainNotify(ctx)
|
||||
require.NoError(err)
|
||||
<-headChangeCh // skip hccurrent
|
||||
|
||||
defer func() {
|
||||
close(waitAllCh)
|
||||
}()
|
||||
|
||||
count := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case headChanges := <-headChangeCh:
|
||||
for _, change := range headChanges {
|
||||
if change.Type == store.HCApply {
|
||||
msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key())
|
||||
require.NoError(err)
|
||||
count += len(msgs)
|
||||
if count == iterations {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var sms []*types.SignedMessage
|
||||
for i := 0; i < iterations; i++ {
|
||||
msg := &types.Message{
|
||||
From: client.DefaultKey.Address,
|
||||
To: addr,
|
||||
Value: each,
|
||||
}
|
||||
|
||||
sm, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(err)
|
||||
require.EqualValues(i, sm.Message.Nonce)
|
||||
|
||||
sms = append(sms, sm)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-waitAllCh:
|
||||
case <-ctx.Done():
|
||||
t.Errorf("timeout waiting to pack messages")
|
||||
}
|
||||
|
||||
expected := make(map[string]bool)
|
||||
for _, sm := range sms {
|
||||
hash, err := ethtypes.EthHashFromCid(sm.Cid())
|
||||
require.NoError(err)
|
||||
expected[hash.String()] = false
|
||||
}
|
||||
|
||||
// expect to have seen iteration number of mpool messages
|
||||
require.Equal(len(subResponses), len(expected), "expected number of filter results to equal number of messages")
|
||||
|
||||
for _, txid := range subResponses {
|
||||
expected[txid.Result.(string)] = true
|
||||
}
|
||||
|
||||
for _, found := range expected {
|
||||
require.True(found)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthNewBlockFilter(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
@ -843,3 +843,28 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
|
||||
// The receive() function emits one log, that's how we know we hit it.
|
||||
require.Len(t, receipt.Logs, 1)
|
||||
}
|
||||
|
||||
func TestFEVMProxyUpgradeable(t *testing.T) {
|
||||
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||
defer cancel()
|
||||
|
||||
//install transparently upgradeable proxy
|
||||
proxyFilename := "contracts/TransparentUpgradeableProxy.hex"
|
||||
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, proxyFilename)
|
||||
|
||||
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "test()", []byte{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFEVMGetBlockDifficulty(t *testing.T) {
|
||||
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||
defer cancel()
|
||||
|
||||
//install contract
|
||||
filenameActor := "contracts/GetDifficulty.hex"
|
||||
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||
|
||||
ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDifficulty()", []byte{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(ret), 32)
|
||||
}
|
||||
|
@ -178,7 +178,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -253,8 +253,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -285,7 +285,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -354,8 +354,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -649,7 +649,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -724,8 +724,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -756,7 +756,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -825,8 +825,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3009,7 +3009,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3084,8 +3084,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3116,7 +3116,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3185,8 +3185,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3359,7 +3359,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3434,8 +3434,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3466,7 +3466,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3535,8 +3535,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3726,7 +3726,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3801,8 +3801,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
@ -3833,7 +3833,7 @@
|
||||
"s",
|
||||
"type",
|
||||
"value",
|
||||
"yParity"
|
||||
"v"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -3902,8 +3902,8 @@
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "Chain ID that this transaction is valid on."
|
||||
},
|
||||
"yParity": {
|
||||
"title": "yParity",
|
||||
"v": {
|
||||
"title": "v",
|
||||
"type": "string",
|
||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
@ -525,7 +526,7 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&evm.GetStorageAtParams{
|
||||
StorageKey: position,
|
||||
StorageKey: *(*[32]byte)(position),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize parameters: %w", err)
|
||||
@ -601,6 +602,18 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
||||
if params.BlkCount > 1024 {
|
||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024")
|
||||
}
|
||||
rewardPercentiles := make([]float64, 0)
|
||||
if params.RewardPercentiles != nil {
|
||||
rewardPercentiles = append(rewardPercentiles, *params.RewardPercentiles...)
|
||||
}
|
||||
for i, rp := range rewardPercentiles {
|
||||
if rp < 0 || rp > 100 {
|
||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be between 0 and 100", rp)
|
||||
}
|
||||
if i > 0 && rp < rewardPercentiles[i-1] {
|
||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be larger than %f", rp, rewardPercentiles[i-1])
|
||||
}
|
||||
}
|
||||
|
||||
ts, err := a.parseBlkParam(ctx, params.NewestBlkNum)
|
||||
if err != nil {
|
||||
@ -619,18 +632,40 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
||||
// we can do is duplicate the last value.
|
||||
baseFeeArray := []ethtypes.EthBigInt{ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)}
|
||||
gasUsedRatioArray := []float64{}
|
||||
rewardsArray := make([][]ethtypes.EthBigInt, 0)
|
||||
|
||||
for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) {
|
||||
// Unfortunately we need to rebuild the full message view so we can
|
||||
// totalize gas used in the tipset.
|
||||
block, err := newEthBlockFromFilecoinTipSet(ctx, ts, false, a.Chain, a.StateAPI)
|
||||
msgs, err := a.Chain.MessagesForTipset(ctx, ts)
|
||||
if err != nil {
|
||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
||||
return ethtypes.EthFeeHistory{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
|
||||
}
|
||||
|
||||
// both arrays should be reversed at the end
|
||||
txGasRewards := gasRewardSorter{}
|
||||
for txIdx, msg := range msgs {
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false)
|
||||
if err != nil || msgLookup == nil {
|
||||
return ethtypes.EthFeeHistory{}, nil
|
||||
}
|
||||
|
||||
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, a.Chain, a.StateAPI)
|
||||
if err != nil {
|
||||
return ethtypes.EthFeeHistory{}, nil
|
||||
}
|
||||
|
||||
txGasRewards = append(txGasRewards, gasRewardTuple{
|
||||
reward: tx.Reward(ts.Blocks()[0].ParentBaseFee),
|
||||
gas: uint64(msgLookup.Receipt.GasUsed),
|
||||
})
|
||||
}
|
||||
|
||||
rewards, totalGasUsed := calculateRewardsAndGasUsed(rewardPercentiles, txGasRewards)
|
||||
|
||||
// arrays should be reversed at the end
|
||||
baseFeeArray = append(baseFeeArray, ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee))
|
||||
gasUsedRatioArray = append(gasUsedRatioArray, float64(block.GasUsed)/float64(build.BlockGasLimit))
|
||||
gasUsedRatioArray = append(gasUsedRatioArray, float64(totalGasUsed)/float64(build.BlockGasLimit))
|
||||
rewardsArray = append(rewardsArray, rewards)
|
||||
|
||||
parentTsKey := ts.Parents()
|
||||
ts, err = a.Chain.LoadTipSet(ctx, parentTsKey)
|
||||
@ -646,6 +681,9 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
||||
for i, j := 0, len(gasUsedRatioArray)-1; i < j; i, j = i+1, j-1 {
|
||||
gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i]
|
||||
}
|
||||
for i, j := 0, len(rewardsArray)-1; i < j; i, j = i+1, j-1 {
|
||||
rewardsArray[i], rewardsArray[j] = rewardsArray[j], rewardsArray[i]
|
||||
}
|
||||
|
||||
ret := ethtypes.EthFeeHistory{
|
||||
OldestBlock: ethtypes.EthUint64(oldestBlkHeight),
|
||||
@ -653,13 +691,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
||||
GasUsedRatio: gasUsedRatioArray,
|
||||
}
|
||||
if params.RewardPercentiles != nil {
|
||||
// TODO: Populate reward percentiles
|
||||
// https://github.com/filecoin-project/lotus/issues/10236
|
||||
// We need to calculate the requested percentiles of effective gas premium
|
||||
// based on the newest block (I presume it's the newest, we need to dig in
|
||||
// as it's underspecified). Effective means we're clamped at the gas_fee_cap - base_fee.
|
||||
reward := make([][]ethtypes.EthBigInt, 0)
|
||||
ret.Reward = &reward
|
||||
ret.Reward = &rewardsArray
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@ -751,18 +783,20 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
|
||||
}
|
||||
|
||||
var params []byte
|
||||
if len(tx.Data) > 0 {
|
||||
initcode := abi.CborBytes(tx.Data)
|
||||
params2, err := actors.SerializeParams(&initcode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize params: %w", err)
|
||||
}
|
||||
params = params2
|
||||
}
|
||||
|
||||
var to address.Address
|
||||
var method abi.MethodNum
|
||||
if tx.To == nil {
|
||||
// this is a contract creation
|
||||
to = builtintypes.EthereumAddressManagerActorAddr
|
||||
|
||||
initcode := abi.CborBytes(tx.Data)
|
||||
params2, err := actors.SerializeParams(&initcode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize Create params: %w", err)
|
||||
}
|
||||
params = params2
|
||||
method = builtintypes.MethodsEAM.CreateExternal
|
||||
} else {
|
||||
addr, err := tx.To.ToFilecoinAddress()
|
||||
@ -770,15 +804,6 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
|
||||
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
||||
}
|
||||
to = addr
|
||||
|
||||
if len(tx.Data) > 0 {
|
||||
var buf bytes.Buffer
|
||||
if err := cbg.WriteByteArray(&buf, tx.Data); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string")
|
||||
}
|
||||
params = buf.Bytes()
|
||||
}
|
||||
|
||||
method = builtintypes.MethodsEVM.InvokeContract
|
||||
}
|
||||
|
||||
@ -1246,8 +1271,9 @@ func (e *EthEvent) uninstallFilter(ctx context.Context, f filter.Filter) error {
|
||||
}
|
||||
|
||||
const (
|
||||
EthSubscribeEventTypeHeads = "newHeads"
|
||||
EthSubscribeEventTypeLogs = "logs"
|
||||
EthSubscribeEventTypeHeads = "newHeads"
|
||||
EthSubscribeEventTypeLogs = "logs"
|
||||
EthSubscribeEventTypePendingTransactions = "newPendingTransactions"
|
||||
)
|
||||
|
||||
func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||
@ -1309,6 +1335,15 @@ func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethty
|
||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||
return ethtypes.EthSubscriptionID{}, err
|
||||
}
|
||||
sub.addFilter(ctx, f)
|
||||
case EthSubscribeEventTypePendingTransactions:
|
||||
f, err := e.MemPoolFilterManager.Install(ctx)
|
||||
if err != nil {
|
||||
// clean up any previous filters added and stop the sub
|
||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||
return ethtypes.EthSubscriptionID{}, err
|
||||
}
|
||||
|
||||
sub.addFilter(ctx, f)
|
||||
default:
|
||||
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType)
|
||||
@ -1629,6 +1664,15 @@ func (e *ethSubscription) start(ctx context.Context) {
|
||||
}
|
||||
|
||||
e.send(ctx, ev)
|
||||
case *types.SignedMessage: // mpool txid
|
||||
evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}, e.StateAPI)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, r := range evs.Results {
|
||||
e.send(ctx, r)
|
||||
}
|
||||
default:
|
||||
log.Warnf("unexpected subscription value type: %T", vt)
|
||||
}
|
||||
@ -2135,3 +2179,50 @@ func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) {
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) {
|
||||
var totalGasUsed uint64
|
||||
for _, tx := range txGasRewards {
|
||||
totalGasUsed += tx.gas
|
||||
}
|
||||
|
||||
rewards := make([]ethtypes.EthBigInt, len(rewardPercentiles))
|
||||
for i := range rewards {
|
||||
rewards[i] = ethtypes.EthBigIntZero
|
||||
}
|
||||
|
||||
if len(txGasRewards) == 0 {
|
||||
return rewards, totalGasUsed
|
||||
}
|
||||
|
||||
sort.Stable(txGasRewards)
|
||||
|
||||
var idx int
|
||||
var sum uint64
|
||||
for i, percentile := range rewardPercentiles {
|
||||
threshold := uint64(float64(totalGasUsed) * percentile / 100)
|
||||
for sum < threshold && idx < len(txGasRewards)-1 {
|
||||
sum += txGasRewards[idx].gas
|
||||
idx++
|
||||
}
|
||||
rewards[i] = txGasRewards[idx].reward
|
||||
}
|
||||
|
||||
return rewards, totalGasUsed
|
||||
}
|
||||
|
||||
type gasRewardTuple struct {
|
||||
gas uint64
|
||||
reward ethtypes.EthBigInt
|
||||
}
|
||||
|
||||
// sorted in ascending order
|
||||
type gasRewardSorter []gasRewardTuple
|
||||
|
||||
func (g gasRewardSorter) Len() int { return len(g) }
|
||||
func (g gasRewardSorter) Swap(i, j int) {
|
||||
g[i], g[j] = g[j], g[i]
|
||||
}
|
||||
func (g gasRewardSorter) Less(i, j int) bool {
|
||||
return g[i].reward.Int.Cmp(g[j].reward.Int) == -1
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
)
|
||||
@ -100,3 +102,65 @@ func TestEthLogFromEvent(t *testing.T) {
|
||||
require.Len(t, topics, 1)
|
||||
require.Equal(t, topics[0], ethtypes.EthHash{})
|
||||
}
|
||||
|
||||
func TestReward(t *testing.T) {
|
||||
baseFee := big.NewInt(100)
|
||||
testcases := []struct {
|
||||
maxFeePerGas, maxPriorityFeePerGas big.Int
|
||||
answer big.Int
|
||||
}{
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(200)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(300), answer: big.NewInt(300)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(500), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(600), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(1000), answer: big.NewInt(500)},
|
||||
{maxFeePerGas: big.NewInt(50), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(-50)},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
tx := ethtypes.EthTx{
|
||||
MaxFeePerGas: ethtypes.EthBigInt(tc.maxFeePerGas),
|
||||
MaxPriorityFeePerGas: ethtypes.EthBigInt(tc.maxPriorityFeePerGas),
|
||||
}
|
||||
reward := tx.Reward(baseFee)
|
||||
require.Equal(t, 0, reward.Int.Cmp(tc.answer.Int), reward, tc.answer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewardPercentiles(t *testing.T) {
|
||||
testcases := []struct {
|
||||
percentiles []float64
|
||||
txGasRewards gasRewardSorter
|
||||
answer []int64
|
||||
}{
|
||||
{
|
||||
percentiles: []float64{25, 50, 75},
|
||||
txGasRewards: []gasRewardTuple{},
|
||||
answer: []int64{0, 0, 0},
|
||||
},
|
||||
{
|
||||
percentiles: []float64{25, 50, 75, 100},
|
||||
txGasRewards: []gasRewardTuple{
|
||||
{gas: uint64(0), reward: ethtypes.EthBigInt(big.NewInt(300))},
|
||||
{gas: uint64(100), reward: ethtypes.EthBigInt(big.NewInt(200))},
|
||||
{gas: uint64(350), reward: ethtypes.EthBigInt(big.NewInt(100))},
|
||||
{gas: uint64(500), reward: ethtypes.EthBigInt(big.NewInt(600))},
|
||||
{gas: uint64(300), reward: ethtypes.EthBigInt(big.NewInt(700))},
|
||||
},
|
||||
answer: []int64{200, 700, 700, 700},
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
rewards, totalGasUsed := calculateRewardsAndGasUsed(tc.percentiles, tc.txGasRewards)
|
||||
gasUsed := uint64(0)
|
||||
for _, tx := range tc.txGasRewards {
|
||||
gasUsed += tx.gas
|
||||
}
|
||||
ans := []ethtypes.EthBigInt{}
|
||||
for _, bi := range tc.answer {
|
||||
ans = append(ans, ethtypes.EthBigInt(big.NewInt(bi)))
|
||||
}
|
||||
require.Equal(t, totalGasUsed, gasUsed)
|
||||
require.Equal(t, len(ans), len(tc.percentiles))
|
||||
require.Equal(t, ans, rewards)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user