以太坊源码借读 以太坊国密算法EVM调试之旅

入门知识 1周前 (09-16) 9次浏览 0个评论

项目中使用国密算法,hash为国密方法,使用solc编译器编译合约代码,调用合约方法执行失败。找了半天,终于找到原因了。

先部署合约没有问题,但是合约执行方式不成功。后来发现交易输入中的add方法签名与以太坊solc编译的方法签名不一致,合约执行过程中找不到方法。交易执行失败

源码如下

pragma solidity ^0.6.4;
contract C {
    uint256 a;
    constructor() public  {
      a = 1;
    }
    function add(uint256 b) public {
        a = a + b;
    }
}

Go 合约调用

solcjs --bin math.sol
solcjs --abi math.sol

生成 go call 合约模板命令

//生成合约 go文件
abigen --bin=math_sol_C.bin --abi=math_sol_C.abi --pkg=math --out=Math.go

Go源码如下

package math
import (
    "fmt"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/crypto"
    "github.com/ethereum/go-ethereum/log"
    "github.com/truechain/truechain-engineering-code/accounts/abi/bind"
    "github.com/truechain/truechain-engineering-code/accounts/abi/bind/backends"
    "github.com/truechain/truechain-engineering-code/core/types"
    "math/big"
    "os"
    "testing"
)
func init() {
    log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
}
var (
    key, _   = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    addr     = crypto.PubkeyToAddress(key.PublicKey)
    testAddr = common.HexToAddress("0x1234123412341234123412341234123412341234")
)
func TestMath(t *testing.T) {
    contractBackend := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000)
    transactOpts := bind.NewKeyedTransactor(key)
    // Deploy the contract
    ensAddr, _, _, err := DeployToken(transactOpts, contractBackend)
    if err != nil {
        t.Fatalf("can't DeployContract: %v", err)
    }
    ens, err := NewToken(ensAddr, contractBackend)
    if err != nil {
        t.Fatalf("can't NewContract: %v", err)
    }
    contractBackend.Commit()
    tx, err := ens.Add(transactOpts, big.NewInt(50000))
    if err != nil {
        log.Error("Failed to request token transfer", ": %v", err)
    }
    fmt.Printf("Transfer pending: 0x%xn", tx.Hash())
    contractBackend.Commit()
}

执行测试用例,可以部署成功

// 这是部署的日志状态打印
SetCode  171   0xdbff645123207cac88f3054b7d9159225f4f45a59d8d8d85e384f1dd7b162904   0xe8CCbD4fcE87173a98561A17E028DDc1bC7d0BFe
// 只有一个变量a,在状态中的存储key是索引0,value是1.
updateTrie 0xe8CCbD4fcE87173a98561A17E028DDc1bC7d0BFe  key  0x0000000000000000000000000000000000000000000000000000000000000000  v  0x0000000000000000000000000000000000000000000000000000000000000001

执行ens.Add方法以太坊源码借读,调用会失败

DEBUG[05-29|18:40:27.021] VM returned with error                   err="evm: execution reverted"

是不是很奇怪,部署没有问题,但是调用方法却出错了

EVM 跟踪日志

在交易执行中添加合约跟踪日志,在上一篇文档中添加了,但是没用。

prefix := fmt.Sprintf("block_%d-%d-%#x-",block.NumberU64(), i, tx.Hash().Bytes()[:4])
        dump, _ = ioutil.TempFile(os.TempDir(), prefix)
        // Swap out the noop logger to the standard tracer
        writer = bufio.NewWriter(dump)
        vmConf = vm.Config{
            Debug:                   true,
            Tracer:                  vm.NewJSONLogger(&logConfig, writer),
            EnablePreimageRecording: true,
        }
        receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, usedGas, feeAmount, vmConf)
        if err != nil {
            return nil, nil, 0, err
        }
        if writer != nil {
            writer.Flush()
        }
        if dump != nil {
            dump.Close()
            log.Info("Wrote standard trace", "file", dump.Name())
        }

以下是比较成功调用和失败的跟踪日志。图中圆圈不一致以太坊源码借读,方法签名中使用了hash算法。

取出交易的Input,前几个字段是方法签名,后面c350是add方法参数5000的十六进制表示

1003e2d2000000000000000000000000000000000000000000000000000000000000c350
caf838c8000000000000000000000000000000000000000000000000000000000000c350

哈希生成方法签名

func TestMethod(t *testing.T) {
    method := []byte("add(uint256)")
    //国密
    sig := crypto.Keccak256(method)[:4]
    fmt.Println(" ", hex.EncodeToString(sig))
    // 原生
    d := sha3.NewLegacyKeccak256()
    d.Write(method)
    fmt.Println(" ", hex.EncodeToString(d.Sum(nil)[:4]))
}

执行结果

=== RUN   TestMethod
  caf838c8
  1003e2d2
--- PASS: TestMethod (0.00s)

验证发现方法签名不一致,合约执行过程中找不到方法

// 以太坊 code
60806040523480156100115760006000fd5b505b600160006000508190909055505b610026565b60ab806100346000396000f3fe608060405234801560105760006000fd5b5060043610602c5760003560e01c80631003e2d214603257602c565b60006000fd5b605c6004803603602081101560475760006000fd5b8101908080359060200190929190505050605e565b005b806000600050540160006000508190909055505b5056fea2646970667358221220c76ddd0af49ffc6b50b07f255c3b36ade4aa285b54aced71e2930afea3df133364736f6c63430006040033
// 国密 code
0x60606040523415600b57fe5b5b60016000819055505b5b6092806100246000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063caf838c814603a575bfe5b3415604157fe5b605560048080359060200190919050506057565b005b80600054016000819055505b505600a165627a7a72305820d2459cc400ba3e9a500c20bd88d035902735f29d9d58ff5538f75e510bb703ed0029

使用以下国密输入+国密代码调用合约成功。

caf838c8000000000000000000000000000000000000000000000000000000000000c350

国密合约代码可以使用国密solc编译,ABI不需要修改。以太坊Solc编译器

挖矿网Ethos中文站简单易用的挖矿系统,为挖矿产业提供教程软件以及矿机测评交易信息等,挖矿网各种数字货币挖矿收益对比计算,挖矿网介绍挖矿的工具,以及矿场的最新消息等。http://www.ethospool.com/

喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址