Skip to content

Commit

Permalink
Merge pull request #1310 from libangzhu/proxy-exec
Browse files Browse the repository at this point in the history
Proxy exec
  • Loading branch information
bysomeone authored Sep 15, 2023
2 parents 77916d3 + 0e855c8 commit d854190
Show file tree
Hide file tree
Showing 20 changed files with 297 additions and 39 deletions.
1 change: 1 addition & 0 deletions cmd/chain33/chain33.fork.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ForkTicketFundAddrV1=3350000
ForkRootHash=4500000
ForkFormatAddressKey=0
ForkCheckEthTxSort=0
ForkProxyExec=0

[fork.sub.none]
ForkUseTimeDelay=0
Expand Down
1 change: 1 addition & 0 deletions cmd/chain33/chain33.system.fork.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ ForkTicketFundAddrV1=3350000
ForkRootHash=4500000
ForkFormatAddressKey=0
ForkCheckEthTxSort=0
ForkProxyExec=0
6 changes: 6 additions & 0 deletions cmd/chain33/chain33.test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,14 @@ coinType="bty"
minerwhitelist=["*"]

[exec]
#交易费相关统一在mempool中配置
#是否开启stat插件
enableStat=false
#是否开启MVCC插件
enableMVCC=false
alias=["token1:token","token2:token","token3:token"]
#代理执行器地址
proxyExecAddress="0x0000000000000000000000000000000000200005"

[exec.sub.token]
saveTokenTxList=true
Expand Down
3 changes: 2 additions & 1 deletion cmd/chain33/chain33.toml
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ enableStat=false
#是否开启MVCC插件
enableMVCC=false
alias=["token1:token","token2:token","token3:token"]

#代理执行器地址
proxyExecAddrss="0x0000000000000000000000000000000000200005"
[exec.sub.token]
#是否保存token交易信息
saveTokenTxList=true
Expand Down
51 changes: 49 additions & 2 deletions executor/execenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ package executor

import (
"bytes"

"errors"
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/client/api"
Expand Down Expand Up @@ -598,6 +599,42 @@ func (e *executor) rollback() {
}
}

func (e *executor) proxyGetRealTx(tx *types.Transaction) (*types.Transaction, error) {
if string(types.GetRealExecName(tx.GetExecer())) != "evm" {
return nil, fmt.Errorf("execName %s not allowd", string(types.GetRealExecName(tx.GetExecer())))
}
var actionData types.EVMContractAction4Chain33
err := types.Decode(tx.GetPayload(), &actionData)
if err != nil {
return nil, err
}
if len(actionData.GetPara()) == 0 {
return nil, errors.New("empty tx")
}
var realTx types.Transaction
err = types.Decode(actionData.Para, &realTx)
if err != nil {
return nil, err
}

return &realTx, nil

}

func (e *executor) proxyExecTx(tx *types.Transaction) (*types.Transaction, error) {
var realTx = tx
var err error
if tx.To == e.cfg.GetModuleConfig().Exec.ProxyExecAddress {
realTx, err = e.proxyGetRealTx(tx)
if err != nil {
return realTx, err
}
realTx.Signature = tx.Signature

}
return realTx, nil
}

func (e *executor) execTx(exec *Executor, tx *types.Transaction, index int) (*types.Receipt, error) {
if e.height == 0 { //genesis block 不检查手续费
receipt, err := e.Exec(tx, index)
Expand All @@ -609,10 +646,20 @@ func (e *executor) execTx(exec *Executor, tx *types.Transaction, index int) (*ty
}
return receipt, nil
}

var err error
//代理执行 EVM-->txpayload-->chain33 tx
if e.cfg.IsFork(e.height, "ForkProxyExec") {
tx, err = e.proxyExecTx(tx)
if err != nil {
return nil, err
}
}

//交易检查规则:
//1. mempool 检查区块,尽量检查更多的错误
//2. 打包的时候,尽量打包更多的交易,只要基本的签名,以及格式没有问题
err := e.checkTx(tx, index)
err = e.checkTx(tx, index)
if err != nil {
elog.Error("execTx.checkTx ", "txhash", common.ToHex(tx.Hash()), "err", err)
if e.cfg.IsPara() {
Expand Down
68 changes: 66 additions & 2 deletions executor/execenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
package executor

import (
"github.com/33cn/chain33/common/crypto"
erpctypes "github.com/33cn/chain33/rpc/ethrpc/types"
drivers "github.com/33cn/chain33/system/dapp"
ecommon "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"math/big"
"testing"
"time"

drivers "github.com/33cn/chain33/system/dapp"

"strings"

_ "github.com/33cn/chain33/system"
Expand All @@ -19,6 +24,7 @@ import (
)

func TestLoadDriverFork(t *testing.T) {

str := types.GetDefaultCfgstring()
new := strings.Replace(str, "Title=\"local\"", "Title=\"chain33\"", 1)
exec, _ := initEnv(types.MergeCfg(types.ReadFile("../cmd/chain33/chain33.fork.toml"), new))
Expand Down Expand Up @@ -97,3 +103,61 @@ func (app *notAllowApp) Allow(tx *types.Transaction, index int) error {
}
return types.ErrActionNotSupport
}

func TestProxyExec(t *testing.T) {
exec, _ := initEnv(types.GetDefaultCfgstring())
cfg := exec.client.GetConfig()
ctx := &executorCtx{
stateHash: nil,
height: 0,
blocktime: time.Now().Unix(),
difficulty: 1,
mainHash: nil,
parentHash: nil,
}

execute := newExecutor(ctx, exec, nil, nil, nil)
//测试解析代理地址
proxyAddr := ecommon.HexToAddress("0x0000000000000000000000000000000000200005")
var hexKey = "7939624566468cfa3cb2c9f39d5ad83bdc7cf4356bfd1a7b8094abda6b0699d1"
sk, err := ethcrypto.ToECDSA(ecommon.FromHex(hexKey))
assert.Nil(t, err)

signer := ethtypes.NewEIP155Signer(big.NewInt(3999))
//构建eth交易
to, _ := util.Genaddress()
//coins 转账,没有签名的裸交易
coinsTx := util.CreateCoinsTx(cfg, nil, to, 1000)
etx := ethtypes.NewTransaction(uint64(0), proxyAddr, big.NewInt(0), 3000000, big.NewInt(10e9), types.Encode(coinsTx))
signtx, err := ethtypes.SignTx(etx, signer, sk)
assert.Nil(t, err)
v, r, s := signtx.RawSignatureValues()
cv, err := erpctypes.CaculateRealV(v, signtx.ChainId().Uint64(), signtx.Type())
assert.Nil(t, err)
sig := make([]byte, 65)
copy(sig[32-len(r.Bytes()):32], r.Bytes())
copy(sig[64-len(s.Bytes()):64], s.Bytes())
sig[64] = cv
txSha3 := signer.Hash(signtx)
pubkey, err := ethcrypto.Ecrecover(txSha3.Bytes(), sig)
assert.Nil(t, err)
assembleTx := erpctypes.AssembleChain33Tx(signtx, sig, pubkey, cfg)
//checkSign
err = execute.checkTx(assembleTx, 0)
assert.Errorf(t, err, "ErrExecNameNotAllow")
types.AllowUserExec = append(types.AllowUserExec, []byte("evm"))
err = execute.checkTx(assembleTx, 0)
assert.Nil(t, err)

crypto.Init(cfg.GetModuleConfig().Crypto, cfg.GetSubConfig().Crypto)
assert.True(t, assembleTx.CheckSign(0))
//解析交易
realTx, err := execute.proxyExecTx(assembleTx)
assert.Nil(t, err)
assert.Equal(t, "0xa42431da868c58877a627cc71dc95f01bf40c196", realTx.From())
testTx := realTx.Clone()
testTx.Signature = nil

//与原始交易对比
assert.Equal(t, coinsTx.Hash(), testTx.Hash())
}
10 changes: 4 additions & 6 deletions executor/executor_real_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ package executor_test
import (
"errors"
"fmt"
"net/http"
_ "net/http/pprof"
"testing"

"sync"

"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/merkle"
Expand All @@ -22,6 +16,10 @@ import (
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/util/testnode"
"github.com/stretchr/testify/assert"
"net/http"
_ "net/http/pprof"
"sync"
"testing"
)

var runonce sync.Once
Expand Down
1 change: 1 addition & 0 deletions queue/queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ func TestChannelClose(t *testing.T) {
go q.Start()
//rpc 模块 会向其他模块发送消息,自己本身不需要订阅消息
go func() {
time.Sleep(time.Millisecond * 100)
done <- struct{}{}
}()
for i := 0; i < 10000; i++ {
Expand Down
13 changes: 11 additions & 2 deletions rpc/ethrpc/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,17 @@ func (e *ethHandler) EstimateGas(callMsg *types.CallMsg) (hexutil.Uint64, error)
})

fee := properFee.GetProperFee()
//GetMinTxFeeRate 默认1e5
realFee, _ := tx.GetRealFee(e.cfg.GetMinTxFeeRate())
//判断是否是代理执行的地址,如果是,则直接返回,不会交给evm执行器去模拟执行计算gas.
if callMsg.To == e.cfg.GetModuleConfig().Exec.ProxyExecAddress {
rightFee := realFee
if realFee < fee {
rightFee = fee
}
return hexutil.Uint64(rightFee), nil
}

var minimumGas int64 = 21000
if callMsg.Data == nil || len(*callMsg.Data) == 0 {
if fee < e.cfg.GetMinTxFeeRate() {
Expand Down Expand Up @@ -597,8 +608,6 @@ func (e *ethHandler) EstimateGas(callMsg *types.CallMsg) (hexutil.Uint64, error)
}

bigGas, _ := new(big.Int).SetString(gas.Gas, 10)
//GetMinTxFeeRate 默认1e5
realFee, _ := tx.GetRealFee(e.cfg.GetMinTxFeeRate())

var finalFee = realFee
if bigGas.Uint64() > uint64(realFee) {
Expand Down
60 changes: 60 additions & 0 deletions system/mempool/check.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package mempool

import (
"bytes"
"errors"
"fmt"
"math/big"
"sort"
"sync/atomic"
"time"

Expand Down Expand Up @@ -198,6 +202,13 @@ func (mem *Mempool) checkTxRemote(msg *queue.Message) *queue.Message {
}
}

//检查mempool内是否有相同的tx.nonce
err = mem.evmTxNonceCheck(tx.Tx())
if err != nil {
msg.Data = err
return msg
}

err = mem.PushTx(tx.Tx())
if err != nil {
if err == types.ErrMemFull {
Expand All @@ -209,3 +220,52 @@ func (mem *Mempool) checkTxRemote(msg *queue.Message) *queue.Message {
}
return msg
}

//evmTxNonceCheck 检查eth noce 是否有重复值,如果有的话,需要比较txFee大小,用于替换较小的fee的那笔交易
func (mem *Mempool) evmTxNonceCheck(tx *types.Transaction) error {
if !types.IsEthSignID(tx.Tx().GetSignature().GetTy()) {
return nil
}

//较小的nonce 则返回错误,不被允许进入mempool
if tx.GetNonce() < mem.getCurrentNonce(tx.From()) {
return types.ErrLowNonce
}
details := mem.GetAccTxs(&types.ReqAddrs{Addrs: []string{tx.From()}})
txs := details.GetTxs()
txs = append(txs, &types.TransactionDetail{Tx: tx, Index: int64(len(txs))})
if len(txs) > 1 {
sort.SliceStable(txs, func(i, j int) bool { //nonce asc
return txs[i].Tx.GetNonce() < txs[j].Tx.GetNonce()
})
//遇到相同的Nonce ,较低的手续费的交易将被删除
for i, stx := range txs {
if bytes.Equal(stx.Tx.Hash(), tx.Hash()) {
continue
}

if txs[i].GetTx().GetNonce() == tx.GetNonce() {
bnfee := big.NewInt(txs[i].GetTx().Fee)
//相同的nonce,fee 必须提升至1.1 倍 才能有效替换之前的交易
bnfee = bnfee.Mul(bnfee, big.NewInt(110))
bnfee = bnfee.Div(bnfee, big.NewInt(1e2))
if tx.Fee < bnfee.Int64() {
err := fmt.Errorf("requires at least 10 percent increase in handling fee,need more:%d", bnfee.Int64()-tx.Fee)
mlog.Error("checkTxNonce", "fee err", err, "txfee", tx.Fee, "mempooltx", txs[0].GetTx().Fee, "from:", tx.From())
return err
}

//删除Expire 较大的交易或者更低手续费的交易,确保先创建的交易留在mempool 中
mem.RemoveTxs(&types.TxHashList{
Hashes: [][]byte{txs[i].GetTx().Hash()},
})
mlog.Info("evmTxNonceCheck", "remote txhash:", common.ToHex(txs[i].GetTx().Hash()), "replace txHash:", common.ToHex(tx.Hash()))
return nil
}
}

}

return nil

}
Loading

0 comments on commit d854190

Please sign in to comment.