Unverified Commit 7be29e49 authored by vipwzw's avatar vipwzw Committed by GitHub

Merge branch 'master' into upgrade_protobuf

parents 9931f210 71f4916a
......@@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
)
//EvmCmd 是Evm命令行入口
func EvmCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "evm",
......@@ -36,32 +37,32 @@ func EvmCmd() *cobra.Command {
}
cmd.AddCommand(
CreateContractCmd(),
CallContractCmd(),
EstimateContractCmd(),
CheckContractAddrCmd(),
EvmDebugCmd(),
EvmTransferCmd(),
EvmWithdrawCmd(),
GetEvmBalanceCmd(),
EvmToolsCmd(),
createContractCmd(),
callContractCmd(),
estimateContractCmd(),
checkContractAddrCmd(),
evmDebugCmd(),
evmTransferCmd(),
evmWithdrawCmd(),
getEvmBalanceCmd(),
evmToolsCmd(),
)
return cmd
}
// some tools for evm op
func EvmToolsCmd() *cobra.Command {
func evmToolsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "tool",
Short: "Some tools for evm op",
}
cmd.AddCommand(EvmToolsAddressCmd())
cmd.AddCommand(evmToolsAddressCmd())
return cmd
}
// transfer address format between ethereum and chain33
func EvmToolsAddressCmd() *cobra.Command {
func evmToolsAddressCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "address",
Short: "Transfer address format between ethereum and local (you should input one address of them)",
......@@ -105,7 +106,7 @@ func transferAddress(cmd *cobra.Command, args []string) {
addr = *addrP
fmt.Println(fmt.Sprintf("Local Address: %v", local))
}
fmt.Println(fmt.Sprintf("Ethereum Address: %v", ChecksumAddr(addr.Bytes())))
fmt.Println(fmt.Sprintf("Ethereum Address: %v", checksumAddr(addr.Bytes())))
return
}
......@@ -113,7 +114,7 @@ func transferAddress(cmd *cobra.Command, args []string) {
}
// get balance of an execer
func GetEvmBalanceCmd() *cobra.Command {
func getEvmBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Get balance of a evm contract address",
......@@ -161,10 +162,15 @@ func evmBalance(cmd *cobra.Command, args []string) {
ctx.Run()
}
// AccountResult 账户余额查询出来之后进行单位转换
type AccountResult struct {
// 货币
Currency int32 `json:"currency,omitempty"`
// 余额
Balance string `json:"balance,omitempty"`
// 冻结余额
Frozen string `json:"frozen,omitempty"`
// 账户地址
Addr string `json:"addr,omitempty"`
}
......@@ -182,7 +188,7 @@ func parseGetBalanceRes(arg interface{}) (interface{}, error) {
}
// 创建EVM合约
func CreateContractCmd() *cobra.Command {
func createContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new EVM contract",
......@@ -319,7 +325,7 @@ func createEvmTransferTx(cmd *cobra.Command, caller, execName, expire, rpcLaddr
}
// 调用EVM合约
func CallContractCmd() *cobra.Command {
func callContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "call",
Short: "Call the EVM contract",
......@@ -431,7 +437,7 @@ func addEstimateFlags(cmd *cobra.Command) {
}
// 估算合约消耗
func EstimateContractCmd() *cobra.Command {
func estimateContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "estimate",
Short: "Estimate the gas cost of calling or creating a contract",
......@@ -442,7 +448,7 @@ func EstimateContractCmd() *cobra.Command {
}
// 检查地址是否为EVM合约
func CheckContractAddrCmd() *cobra.Command {
func checkContractAddrCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "check",
Short: "Check if the address is a valid EVM contract",
......@@ -485,34 +491,34 @@ func checkContractAddr(cmd *cobra.Command, args []string) {
}
// 查询或设置EVM调试开关
func EvmDebugCmd() *cobra.Command {
func evmDebugCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "debug",
Short: "Query or set evm debug status",
}
cmd.AddCommand(
EvmDebugQueryCmd(),
EvmDebugSetCmd(),
EvmDebugClearCmd())
evmDebugQueryCmd(),
evmDebugSetCmd(),
evmDebugClearCmd())
return cmd
}
func EvmDebugQueryCmd() *cobra.Command {
func evmDebugQueryCmd() *cobra.Command {
return &cobra.Command{
Use: "query",
Short: "Query evm debug status",
Run: evmDebugQuery,
}
}
func EvmDebugSetCmd() *cobra.Command {
func evmDebugSetCmd() *cobra.Command {
return &cobra.Command{
Use: "set",
Short: "Set evm debug to ON",
Run: evmDebugSet,
}
}
func EvmDebugClearCmd() *cobra.Command {
func evmDebugClearCmd() *cobra.Command {
return &cobra.Command{
Use: "clear",
Short: "Set evm debug to OFF",
......@@ -521,17 +527,17 @@ func EvmDebugClearCmd() *cobra.Command {
}
func evmDebugQuery(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, 0)
evmDebugRPC(cmd, 0)
}
func evmDebugSet(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, 1)
evmDebugRPC(cmd, 1)
}
func evmDebugClear(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, -1)
evmDebugRPC(cmd, -1)
}
func evmDebugRpc(cmd *cobra.Command, flag int32) {
func evmDebugRPC(cmd *cobra.Command, flag int32) {
var debugReq = evmtypes.EvmDebugReq{Optype: flag}
var debugResp evmtypes.EvmDebugResp
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
......@@ -545,7 +551,7 @@ func evmDebugRpc(cmd *cobra.Command, flag int32) {
}
// 向EVM合约地址转账
func EvmTransferCmd() *cobra.Command {
func evmTransferCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "transfer",
Short: "Transfer to evm contract address",
......@@ -593,7 +599,7 @@ func evmTransfer(cmd *cobra.Command, args []string) {
}
// 向EVM合约地址转账
func EvmWithdrawCmd() *cobra.Command {
func evmWithdrawCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw",
Short: "Withdraw from evm contract address to caller's balance",
......@@ -662,7 +668,7 @@ func sendQuery(rpcAddr, funcName string, request interface{}, result proto.Messa
}
// 这里实现 EIP55中提及的以太坊地址表示方式(增加Checksum)
func ChecksumAddr(address []byte) string {
func checksumAddr(address []byte) string {
unchecksummed := hex.EncodeToString(address[:])
sha := sha3.NewKeccak256()
sha.Write([]byte(unchecksummed))
......
......@@ -24,7 +24,7 @@ import (
var (
evmDebug = false
// 本合约地址
// EvmAddress 本合约地址
EvmAddress = address.ExecAddress(types.ExecName(evmtypes.ExecutorName))
)
......@@ -35,6 +35,7 @@ func init() {
ety.InitFuncList(types.ListMethod(&EVMExecutor{}))
}
// Init 初始化本合约对象
func Init(name string, sub []byte) {
driverName = name
drivers.Register(driverName, newEVMDriver, types.GetDappFork(driverName, "Enable"))
......@@ -43,6 +44,7 @@ func Init(name string, sub []byte) {
state.InitForkData()
}
// GetName 返回本合约名称
func GetName() string {
return newEVMDriver().GetName()
}
......@@ -53,13 +55,14 @@ func newEVMDriver() drivers.Driver {
return evm
}
// EVM执行器结构
// EVMExecutor EVM执行器结构
type EVMExecutor struct {
drivers.DriverBase
vmCfg *runtime.Config
mStateDB *state.MemoryStateDB
}
// NewEVMExecutor 新创建执行器对象
func NewEVMExecutor() *EVMExecutor {
exec := &EVMExecutor{}
......@@ -70,15 +73,18 @@ func NewEVMExecutor() *EVMExecutor {
return exec
}
// GetFuncMap 获取方法列表
func (evm *EVMExecutor) GetFuncMap() map[string]reflect.Method {
ety := types.LoadExecutorType(driverName)
return ety.GetExecFuncMap()
}
// GetDriverName 获取本合约驱动名称
func (evm *EVMExecutor) GetDriverName() string {
return evmtypes.ExecutorName
}
// Allow 允许哪些交易在本命执行器执行
func (evm *EVMExecutor) Allow(tx *types.Transaction, index int) error {
err := evm.DriverBase.Allow(tx, index)
if err == nil {
......@@ -94,6 +100,7 @@ func (evm *EVMExecutor) Allow(tx *types.Transaction, index int) error {
return types.ErrNotAllow
}
// IsFriend 是否允许对应的KEY
func (evm *EVMExecutor) IsFriend(myexec, writekey []byte, othertx *types.Transaction) bool {
if othertx == nil {
return false
......@@ -115,11 +122,12 @@ func (evm *EVMExecutor) getNewAddr(txHash []byte) common.Address {
return common.NewAddress(txHash)
}
// CheckTx 校验交易
func (evm *EVMExecutor) CheckTx(tx *types.Transaction, index int) error {
return nil
}
//获取运行状态名
// GetActionName 获取运行状态名
func (evm *EVMExecutor) GetActionName(tx *types.Transaction) string {
if bytes.Equal(tx.Execer, []byte(types.ExecName(evmtypes.ExecutorName))) {
return types.ExecName(evmtypes.ExecutorName)
......@@ -127,15 +135,17 @@ func (evm *EVMExecutor) GetActionName(tx *types.Transaction) string {
return tx.ActionName()
}
// GetMStateDB 获取内部状态数据库
func (evm *EVMExecutor) GetMStateDB() *state.MemoryStateDB {
return evm.mStateDB
}
// GetVMConfig 获取VM配置
func (evm *EVMExecutor) GetVMConfig() *runtime.Config {
return evm.vmCfg
}
// 构造一个新的EVM上下文对象
// NewEVMContext 构造一个新的EVM上下文对象
func (evm *EVMExecutor) NewEVMContext(msg *common.Message) runtime.Context {
return runtime.Context{
CanTransfer: CanTransfer,
......
......@@ -18,6 +18,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// Exec 本合约执行逻辑
func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, error) {
evm.CheckInit()
// 先转换消息
......@@ -33,12 +34,12 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
env := runtime.NewEVM(context, evm.mStateDB, *evm.vmCfg)
isCreate := strings.Compare(msg.To().String(), EvmAddress) == 0
var (
ret = []byte("")
ret []byte
vmerr error
leftOverGas = uint64(0)
leftOverGas uint64
contractAddr common.Address
snapshot = -1
execName = ""
snapshot int
execName string
)
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
......@@ -76,18 +77,18 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if vmerr != nil {
log.Error("evm contract exec error", "error info", vmerr)
return nil, vmerr
} else {
}
// 计算消耗了多少费用(实际消耗的费用)
usedFee, overflow := common.SafeMul(usedGas, uint64(msg.GasPrice()))
// 费用消耗溢出,执行失败
if overflow || usedFee > uint64(tx.Fee) {
// 如果操作没有回滚,则在这里处理
if curVer != nil && snapshot >= curVer.GetId() && curVer.GetId() > -1 {
if curVer != nil && snapshot >= curVer.GetID() && curVer.GetID() > -1 {
evm.mStateDB.RevertToSnapshot(snapshot)
}
return nil, model.ErrOutOfGas
}
}
// 打印合约中生成的日志
evm.mStateDB.PrintLogs()
......@@ -96,10 +97,10 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
return nil, nil
}
// 从状态机中获取数据变更和变更日志
data, logs := evm.mStateDB.GetChangedData(curVer.GetId())
data, logs := evm.mStateDB.GetChangedData(curVer.GetID())
contractReceipt := &evmtypes.ReceiptEVMContract{Caller: msg.From().String(), ContractName: execName, ContractAddr: contractAddr.String(), UsedGas: usedGas, Ret: ret}
logs = append(logs, &types.ReceiptLog{evmtypes.TyLogCallContract, types.Encode(contractReceipt)})
logs = append(logs, &types.ReceiptLog{Ty: evmtypes.TyLogCallContract, Log: types.Encode(contractReceipt)})
logs = append(logs, evm.mStateDB.GetReceiptLogs(contractAddr.String())...)
if types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMKVHash") {
......@@ -124,13 +125,14 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
return receipt, nil
}
// CheckInit 检查是否初始化数据库
func (evm *EVMExecutor) CheckInit() {
if evm.mStateDB == nil {
evm.mStateDB = state.NewMemoryStateDB(evm.GetStateDB(), evm.GetLocalDB(), evm.GetCoinsAccount(), evm.GetHeight())
}
}
// 目前的交易中,如果是coins交易,金额是放在payload的,但是合约不行,需要修改Transaction结构
// GetMessage 目前的交易中,如果是coins交易,金额是放在payload的,但是合约不行,需要修改Transaction结构
func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message, err error) {
var action evmtypes.EVMContractAction
err = types.Decode(tx.Payload, &action)
......@@ -189,7 +191,7 @@ func (evm *EVMExecutor) calcKVHash(addr common.Address, logs []*types.ReceiptLog
if len(hashes) > 0 {
hash := common.ToHash(hashes)
return &types.KeyValue{getDataHashKey(addr), hash.Bytes()}
return &types.KeyValue{Key: getDataHashKey(addr), Value: hash.Bytes()}
}
return nil
}
......
......@@ -9,6 +9,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// ExecDelLocal 处理区块回滚
func (evm *EVMExecutor) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := evm.DriverBase.ExecDelLocal(tx, receipt, index)
if err != nil {
......
......@@ -11,6 +11,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// ExecLocal 处理本地区块新增逻辑
func (evm *EVMExecutor) ExecLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := evm.DriverBase.ExecLocal(tx, receipt, index)
if err != nil {
......
......@@ -12,22 +12,22 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/state"
)
// 检查合约调用账户是否有充足的金额进行转账交易操作
func CanTransfer(db state.StateDB, sender, recipient common.Address, amount uint64) bool {
// CanTransfer 检查合约调用账户是否有充足的金额进行转账交易操作
func CanTransfer(db state.EVMStateDB, sender, recipient common.Address, amount uint64) bool {
return db.CanTransfer(sender.String(), recipient.String(), amount)
}
// 在内存数据库中执行转账操作(只修改内存中的金额)
// Transfer 在内存数据库中执行转账操作(只修改内存中的金额)
// 从外部账户地址到合约账户地址
func Transfer(db state.StateDB, sender, recipient common.Address, amount uint64) bool {
func Transfer(db state.EVMStateDB, sender, recipient common.Address, amount uint64) bool {
return db.Transfer(sender.String(), recipient.String(), amount)
}
// 获取制定高度区块的哈希
// GetHashFn 获取制定高度区块的哈希
func GetHashFn(api client.QueueProtocolAPI) func(blockHeight uint64) common.Hash {
return func(blockHeight uint64) common.Hash {
if api != nil {
reply, err := api.GetBlockHash(&types.ReqInt{int64(blockHeight)})
reply, err := api.GetBlockHash(&types.ReqInt{Height: int64(blockHeight)})
if nil != err {
log.Error("Call GetBlockHash Failed.", err)
}
......
......@@ -17,7 +17,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询
// Query_CheckAddrExists 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询
func (evm *EVMExecutor) Query_CheckAddrExists(in *evmtypes.CheckEVMAddrReq) (types.Message, error) {
evm.CheckInit()
addrStr := in.Addr
......@@ -51,7 +51,7 @@ func (evm *EVMExecutor) Query_CheckAddrExists(in *evmtypes.CheckEVMAddrReq) (typ
return ret, nil
}
// 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
// Query_EstimateGas 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types.Message, error) {
evm.CheckInit()
var (
......@@ -80,9 +80,9 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
var (
vmerr error
leftOverGas = uint64(0)
leftOverGas uint64
contractAddr common.Address
execName = "estimateGas"
execName string
)
if isCreate {
......@@ -100,7 +100,7 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
return result, vmerr
}
// 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
// Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
func (evm *EVMExecutor) Query_EvmDebug(in *evmtypes.EvmDebugReq) (types.Message, error) {
evm.CheckInit()
optype := in.Optype
......
......@@ -23,7 +23,7 @@ func TestCreateContract1(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 10000000)
mdb := buildStateDB(getAddr(privKey).String(), 500000000)
ret, addr, leftGas, err, statedb := createContract(mdb, tx, 0)
ret, addr, leftGas, statedb, err := createContract(mdb, tx, 0)
test := NewTester(t)
test.assertNil(err)
......@@ -33,7 +33,7 @@ func TestCreateContract1(t *testing.T) {
test.assertNotEqualsI(common.Address(addr), common.EmptyAddress())
// 检查返回数据是否正确
test.assertEqualsV(statedb.GetLastSnapshot().GetId(), 0)
test.assertEqualsV(statedb.GetLastSnapshot().GetID(), 0)
}
// 创建合约gas不足
......@@ -46,7 +46,7 @@ func TestCreateContract2(t *testing.T) {
gas := uint64(30)
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 0)
ret, _, leftGas, _, err := createContract(mdb, tx, 0)
test := NewTester(t)
......@@ -72,7 +72,7 @@ func TestCreateContract3(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 0)
ret, _, leftGas, _, err := createContract(mdb, tx, 0)
test := NewTester(t)
......@@ -98,7 +98,7 @@ func TestCreateContract4(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 50)
ret, _, leftGas, _, err := createContract(mdb, tx, 50)
test := NewTester(t)
......
......@@ -144,13 +144,12 @@ func runCase(tt *testing.T, c VMCase, file string) {
// 合约执行出错的情况下,判断错误是否相同,如果相同,则返回,不判断post
if len(c.err) > 0 && c.err == err.Error() {
return
} else {
}
// 非意料情况下的出错,视为错误
tt.Errorf("test case:%s, failed:%s", c.name, err)
tt.Fail()
return
}
}
// 4 检查执行结果 post (注意,这里不检查Gas具体扣费数额,因为计费规则不一样,值检查执行结果是否正确)
t := NewTester(tt)
// 4.1 返回结果
......
......@@ -79,11 +79,11 @@ func scanTestData(basePath string) {
// 检查两个文件是否都存在
if _, err := os.Stat(keyFile); os.IsNotExist(err) {
fmt.Errorf("test template file:%s, not exists!", keyFile)
fmt.Println(fmt.Errorf("test template file:%s, not exists", keyFile))
return nil
}
if _, err := os.Stat(dataFile); os.IsNotExist(err) {
fmt.Errorf("test data file:%s, not exists!", dataFile)
fmt.Println(fmt.Errorf("test data file:%s, not exists", dataFile))
return nil
}
testmap[keyFile] = dataFile
......
......@@ -4,19 +4,21 @@
package tests
// VMCase 一个测试用例
type VMCase struct {
name string
env EnvJson
exec ExecJson
env EnvJSON
exec ExecJSON
gas int64
logs string
out string
err string
pre map[string]AccountJson
post map[string]AccountJson
pre map[string]AccountJSON
post map[string]AccountJSON
}
type EnvJson struct {
// EnvJSON 上下文信息
type EnvJSON struct {
currentCoinbase string
currentDifficulty int64
currentGasLimit int64
......@@ -24,7 +26,8 @@ type EnvJson struct {
currentTimestamp int64
}
type ExecJson struct {
// ExecJSON 调用信息
type ExecJSON struct {
address string
caller string
code string
......@@ -35,7 +38,8 @@ type ExecJson struct {
value int64
}
type AccountJson struct {
// AccountJSON 账户信息
type AccountJSON struct {
balance int64
code string
nonce int64
......
......@@ -10,10 +10,12 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// Tester 测试执行对象
type Tester struct {
t *testing.T
}
// NewTester 新创建测试执行对象
func NewTester(t *testing.T) *Tester {
return &Tester{t: t}
}
......
......@@ -68,9 +68,9 @@ func parseVMCase(data interface{}, ut *VMCase) {
}
}
func parseEnv(data interface{}) EnvJson {
func parseEnv(data interface{}) EnvJSON {
m := data.(map[string]interface{})
ut := EnvJson{}
ut := EnvJSON{}
for k, v := range m {
switch k {
case "currentCoinbase":
......@@ -90,9 +90,9 @@ func parseEnv(data interface{}) EnvJson {
return ut
}
func parseExec(data interface{}) ExecJson {
func parseExec(data interface{}) ExecJSON {
m := data.(map[string]interface{})
ut := ExecJson{}
ut := ExecJSON{}
for k, v := range m {
switch k {
case "address":
......@@ -118,8 +118,8 @@ func parseExec(data interface{}) ExecJson {
return ut
}
func parseAccount(data interface{}) map[string]AccountJson {
ret := make(map[string]AccountJson)
func parseAccount(data interface{}) map[string]AccountJSON {
ret := make(map[string]AccountJSON)
m := data.(map[string]interface{})
for k, v := range m {
ret[unpre(k)] = parseAccount2(v)
......@@ -127,9 +127,9 @@ func parseAccount(data interface{}) map[string]AccountJson {
return ret
}
func parseAccount2(data interface{}) AccountJson {
func parseAccount2(data interface{}) AccountJSON {
m := data.(map[string]interface{})
ut := AccountJson{}
ut := AccountJSON{}
for k, v := range m {
switch k {
case "balance":
......@@ -215,7 +215,7 @@ func addAccount(mdb *db.GoMemDB, execAddr string, acc1 *types.Account) {
}
}
func addContractAccount(db *state.MemoryStateDB, mdb *db.GoMemDB, addr string, a AccountJson, creator string) {
func addContractAccount(db *state.MemoryStateDB, mdb *db.GoMemDB, addr string, a AccountJSON, creator string) {
acc := state.NewContractAccount(addr, db)
acc.SetCreator(creator)
code, err := hex.DecodeString(a.code)
......@@ -247,7 +247,7 @@ func buildStateDB(addr string, balance int64) *db.GoMemDB {
return mdb
}
func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error, statedb *state.MemoryStateDB) {
func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret []byte, contractAddr common.Address, leftOverGas uint64, statedb *state.MemoryStateDB, err error) {
inst := evm.NewEVMExecutor()
inst.CheckInit()
msg, _ := inst.GetMessage(&tx)
......@@ -273,5 +273,5 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret
addr := *crypto2.RandomContractAddress()
ret, _, leftGas, err := env.Create(runtime.AccountRef(msg.From()), addr, msg.Data(), msg.GasLimit(), fmt.Sprintf("%s%s", evmtypes.EvmPrefix, common.BytesToHash(tx.Hash()).Hex()), "")
return ret, addr, leftGas, err, statedb
return ret, addr, leftGas, statedb, err
}
......@@ -13,37 +13,43 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 封装地址结构体,并提供各种常用操作封装
// Address 封装地址结构体,并提供各种常用操作封装
// 这里封装的操作主要是为了提供Address<->big.Int, Address<->[]byte 之间的互相转换
// 并且转换的核心是使用地址对象中的Hash160元素,因为在EVM中地址固定为[20]byte,超出此范围的地址无法正确解释执行
type Address struct {
addr *address.Address
}
// String 字符串结构
func (a Address) String() string { return a.addr.String() }
// Bytes 字节数组
func (a Address) Bytes() []byte {
return a.addr.Hash160[:]
}
// Big 大数字
func (a Address) Big() *big.Int {
ret := new(big.Int).SetBytes(a.Bytes())
return ret
}
// txHash生成EVM合约地址
// NewAddress xHash生成EVM合约地址
func NewAddress(txHash []byte) Address {
execAddr := address.GetExecAddress(types.ExecName(evmtypes.EvmPrefix) + BytesToHash(txHash).Hex())
return Address{addr: execAddr}
}
// ExecAddress 返回合约地址
func ExecAddress(execName string) Address {
execAddr := address.GetExecAddress(execName)
return Address{addr: execAddr}
}
// Hash 计算地址哈希
func (a Address) Hash() Hash { return ToHash(a.Bytes()) }
// BytesToAddress 字节向地址转换
func BytesToAddress(b []byte) Address {
a := new(address.Address)
a.Version = 0
......@@ -51,6 +57,7 @@ func BytesToAddress(b []byte) Address {
return Address{addr: a}
}
// StringToAddress 字符串转换为地址
func StringToAddress(s string) *Address {
addr, err := address.NewAddrFromString(s)
if err != nil {
......@@ -70,6 +77,7 @@ func bigBytes(b *big.Int) (out [20]byte) {
return
}
// BigToAddress 大数字转换为地址
func BigToAddress(b *big.Int) Address {
a := new(address.Address)
a.Version = 0
......@@ -77,4 +85,5 @@ func BigToAddress(b *big.Int) Address {
return Address{addr: a}
}
// EmptyAddress 返回空地址
func EmptyAddress() Address { return BytesToAddress([]byte{0}) }
......@@ -11,28 +11,34 @@ import (
// 常用的大整数常量定义
var (
// Big0 大数字0
Big0 = big.NewInt(0)
// Big1 大数字1
Big1 = big.NewInt(1)
// Big32 大数字32
Big32 = big.NewInt(32)
// Big256 大数字256
Big256 = big.NewInt(256)
// Big257 大数字257
Big257 = big.NewInt(257)
)
// 2的各种常用取幂结果
var (
// TT255 2的255次幂
TT255 = BigPow(2, 255)
tt256 = BigPow(2, 256)
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
)
const (
// 一个big.Word类型取值占用多少个位
// WordBits 一个big.Word类型取值占用多少个位
WordBits = 32 << (uint64(^big.Word(0)) >> 63)
// 一个big.Word类型取值占用多少个字节
// WordBytes 一个big.Word类型取值占用多少个字节
WordBytes = WordBits / 8
)
// 返回两者之中的较大值
// BigMax 返回两者之中的较大值
func BigMax(x, y *big.Int) *big.Int {
if x.Cmp(y) < 0 {
return y
......@@ -40,7 +46,7 @@ func BigMax(x, y *big.Int) *big.Int {
return x
}
// 返回两者之中的较小值
// BigMin 返回两者之中的较小值
func BigMin(x, y *big.Int) *big.Int {
if x.Cmp(y) > 0 {
return y
......@@ -48,13 +54,13 @@ func BigMin(x, y *big.Int) *big.Int {
return x
}
// 返回a的b次幂
// BigPow 返回a的b次幂
func BigPow(a, b int64) *big.Int {
r := big.NewInt(a)
return r.Exp(r, big.NewInt(b), nil)
}
// 求补
// U256 求补
func U256(x *big.Int) *big.Int {
return x.And(x, tt256m1)
}
......@@ -68,12 +74,11 @@ func U256(x *big.Int) *big.Int {
func S256(x *big.Int) *big.Int {
if x.Cmp(TT255) < 0 {
return x
} else {
return new(big.Int).Sub(x, tt256)
}
return new(big.Int).Sub(x, tt256)
}
// 指数函数,可以指定底数,结果被截断为256位长度
// Exp 指数函数,可以指定底数,结果被截断为256位长度
func Exp(base, exponent *big.Int) *big.Int {
result := big.NewInt(1)
......@@ -89,7 +94,7 @@ func Exp(base, exponent *big.Int) *big.Int {
return result
}
// big.Int以小端编码时,第n个位置的字节取值
// Byte big.Int以小端编码时,第n个位置的字节取值
// 例如: bigint '5', padlength 32, n=31 => 5
func Byte(bigint *big.Int, padlength, n int) byte {
if n >= padlength {
......@@ -117,17 +122,7 @@ func bigEndianByteAt(bigint *big.Int, n int) byte {
return byte(word >> shift)
}
// 以大端方式将big.Int编码为字节数组,结果数组长度为n
func PaddedBigBytes(bigint *big.Int, n int) []byte {
if bigint.BitLen()/8 >= n {
return bigint.Bytes()
}
ret := make([]byte, n)
ReadBits(bigint, ret)
return ret
}
// 以大端方式将big.Int编码为字节数组
// ReadBits 以大端方式将big.Int编码为字节数组
func ReadBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
......@@ -139,17 +134,12 @@ func ReadBits(bigint *big.Int, buf []byte) {
}
}
// 减法运算,返回是否溢出
func SafeSub(x, y uint64) (uint64, bool) {
return x - y, x < y
}
// 加法运算,返回是否溢出
// SafeAdd 加法运算,返回是否溢出
func SafeAdd(x, y uint64) (uint64, bool) {
return x + y, y > math.MaxUint64-x
}
// 乘法运算,返回是否溢出
// SafeMul 乘法运算,返回是否溢出
func SafeMul(x, y uint64) (uint64, bool) {
if x == 0 || y == 0 {
return 0, false
......@@ -157,6 +147,7 @@ func SafeMul(x, y uint64) (uint64, bool) {
return x * y, y > math.MaxUint64/x
}
// Zero 检查数字是否为0
func Zero(value *big.Int) bool {
if value == nil || value.Sign() == 0 {
return true
......
......@@ -9,7 +9,7 @@ import (
"sort"
)
// 右填充字节数组
// RightPadBytes 右填充字节数组
func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
......@@ -21,7 +21,7 @@ func RightPadBytes(slice []byte, l int) []byte {
return padded
}
// 左填充字节数组
// LeftPadBytes 左填充字节数组
func LeftPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
......@@ -33,7 +33,7 @@ func LeftPadBytes(slice []byte, l int) []byte {
return padded
}
// 十六进制的字符串转换为字节数组
// FromHex 十六进制的字符串转换为字节数组
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
......@@ -46,13 +46,13 @@ func FromHex(s string) []byte {
return Hex2Bytes(s)
}
// 十六进制字符串转换为字节数组
// Hex2Bytes 十六进制字符串转换为字节数组
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
// 将字节数组转换为16进制的字符串表示
// Bytes2Hex 将字节数组转换为16进制的字符串表示
func Bytes2Hex(b []byte) string {
enc := make([]byte, len(b)*2+2)
copy(enc, "0x")
......@@ -60,7 +60,7 @@ func Bytes2Hex(b []byte) string {
return string(enc)
}
// 将字节数组转换为16进制的字符串表示
// Bytes2HexTrim 将字节数组转换为16进制的字符串表示
// 并且将前面多余的0去除
func Bytes2HexTrim(b []byte) string {
// 获取字节数组中第一个非零字节位置
......
......@@ -9,7 +9,7 @@ import (
"math/big"
)
// 返回从开始位置制定长度的数据
// GetData 返回从开始位置制定长度的数据
// 如果源数据不足,则剩余位置用零填充
func GetData(data []byte, start uint64, size uint64) []byte {
length := uint64(len(data))
......@@ -23,7 +23,7 @@ func GetData(data []byte, start uint64, size uint64) []byte {
return RightPadBytes(data[start:end], int(size))
}
// 返回从开始位置制定长度的数据
// GetDataBig 返回从开始位置制定长度的数据
// 如果源数据不足,则剩余位置用零填充
func GetDataBig(data []byte, start *big.Int, size *big.Int) []byte {
dlen := big.NewInt(int64(len(data)))
......@@ -33,12 +33,12 @@ func GetDataBig(data []byte, start *big.Int, size *big.Int) []byte {
return RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
}
// 将大整数转换为uint64,并判断是否溢出
// BigUint64 将大整数转换为uint64,并判断是否溢出
func BigUint64(v *big.Int) (uint64, bool) {
return v.Uint64(), v.BitLen() > 64
}
// 计算制定字节长度所对应的字长度(一个字,对应32个字节,也就是256位)
// ToWordSize 计算制定字节长度所对应的字长度(一个字,对应32个字节,也就是256位)
// 如果长度不足一个字长,则补足
// EVM在内存中存储时的最小单位是字长(256位),而不是字节
func ToWordSize(size uint64) uint64 {
......@@ -49,7 +49,7 @@ func ToWordSize(size uint64) uint64 {
return (size + 31) / 32
}
// 判断字节数组内容是否全为零
// AllZero 判断字节数组内容是否全为零
func AllZero(b []byte) bool {
for _, byte := range b {
if byte != 0 {
......
......@@ -20,7 +20,7 @@ func bigFromBase10(s string) *big.Int {
// u is the BN parameter that determines the prime: 1868033³.
var u = bigFromBase10("4965661367192848881")
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
......
......@@ -190,14 +190,14 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
A.Mod(A, P)
B := pool.Get().Mul(a.y, a.y)
B.Mod(B, P)
C_ := pool.Get().Mul(B, B)
C_.Mod(C_, P)
C := pool.Get().Mul(B, B)
C.Mod(C, P)
t := pool.Get().Add(a.x, B)
t2 := pool.Get().Mul(t, t)
t2.Mod(t2, P)
t.Sub(t2, A)
t2.Sub(t, C_)
t2.Sub(t, C)
d := pool.Get().Add(t2, t2)
t.Add(A, A)
e := pool.Get().Add(t, A)
......@@ -207,7 +207,7 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
......@@ -221,7 +221,7 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
pool.Put(A)
pool.Put(B)
pool.Put(C_)
pool.Put(C)
pool.Put(t)
pool.Put(t2)
pool.Put(d)
......
......@@ -134,7 +134,7 @@ func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
return e
}
func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
func (e *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
sum := newGFp12(pool)
sum.SetOne()
t := newGFp12(pool)
......@@ -148,12 +148,12 @@ func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
}
}
c.Set(sum)
e.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
return e
}
func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 {
......
......@@ -106,7 +106,7 @@ func (e *gfP2) Double(a *gfP2) *gfP2 {
return e
}
func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
func (e *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
sum := newGFp2(pool)
sum.SetOne()
t := newGFp2(pool)
......@@ -120,12 +120,12 @@ func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
}
}
c.Set(sum)
e.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
return e
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
......
......@@ -270,13 +270,13 @@ func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
t1.Mul(a.y, a.z, pool)
B.Sub(B, t1)
C_ := newGFp2(pool)
C_.Square(a.y, pool)
C := newGFp2(pool)
C.Square(a.y, pool)
t1.Mul(a.x, a.z, pool)
C_.Sub(C_, t1)
C.Sub(C, t1)
F := newGFp2(pool)
F.Mul(C_, a.y, pool)
F.Mul(C, a.y, pool)
F.MulXi(F, pool)
t1.Mul(A, a.z, pool)
F.Add(F, t1)
......@@ -286,14 +286,14 @@ func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
F.Invert(F, pool)
e.x.Mul(C_, F, pool)
e.x.Mul(C, F, pool)
e.y.Mul(B, F, pool)
e.z.Mul(A, F, pool)
t1.Put(pool)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
F.Put(pool)
return e
......
......@@ -92,12 +92,12 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
A := newGFp2(pool).Square(r.x, pool)
B := newGFp2(pool).Square(r.y, pool)
C_ := newGFp2(pool).Square(B, pool)
C := newGFp2(pool).Square(B, pool)
D := newGFp2(pool).Add(r.x, B)
D.Square(D, pool)
D.Sub(D, A)
D.Sub(D, C_)
D.Sub(D, C)
D.Add(D, D)
E := newGFp2(pool).Add(A, A)
......@@ -116,7 +116,7 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
rOut.y.Sub(D, rOut.x)
rOut.y.Mul(rOut.y, E, pool)
t := newGFp2(pool).Add(C_, C_)
t := newGFp2(pool).Add(C, C)
t.Add(t, t)
t.Add(t, t)
rOut.y.Sub(rOut.y, t)
......@@ -146,7 +146,7 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
D.Put(pool)
E.Put(pool)
G.Put(pool)
......
......@@ -175,12 +175,12 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := newGFp2(pool).Square(a.x, pool)
B := newGFp2(pool).Square(a.y, pool)
C_ := newGFp2(pool).Square(B, pool)
C := newGFp2(pool).Square(B, pool)
t := newGFp2(pool).Add(a.x, B)
t2 := newGFp2(pool).Square(t, pool)
t.Sub(t2, A)
t2.Sub(t, C_)
t2.Sub(t, C)
d := newGFp2(pool).Add(t2, t2)
t.Add(A, A)
e := newGFp2(pool).Add(t, A)
......@@ -189,7 +189,7 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
......@@ -201,7 +201,7 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
t.Put(pool)
t2.Put(pool)
d.Put(pool)
......
......@@ -16,7 +16,7 @@ import (
"golang.org/x/crypto/sha3"
)
// 校验签名信息是否正确
// ValidateSignatureValues 校验签名信息是否正确
func ValidateSignatureValues(r, s *big.Int) bool {
if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 {
return false
......@@ -24,7 +24,7 @@ func ValidateSignatureValues(r, s *big.Int) bool {
return true
}
// 根据压缩消息和签名,返回未压缩的公钥信息
// Ecrecover 根据压缩消息和签名,返回未压缩的公钥信息
func Ecrecover(hash, sig []byte) ([]byte, error) {
pub, err := SigToPub(hash, sig)
if err != nil {
......@@ -34,7 +34,7 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
return bytes, err
}
// 根据签名返回公钥信息
// SigToPub 根据签名返回公钥信息
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
btcsig := make([]byte, 65)
btcsig[0] = sig[64] + 27
......@@ -44,7 +44,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
return (*ecdsa.PublicKey)(pub), err
}
// 随机生成一个新的地址,给新创建的合约地址使用
// RandomContractAddress 随机生成一个新的地址,给新创建的合约地址使用
func RandomContractAddress() *common.Address {
c, err := crypto.New(types.GetSignName("", types.SECP256K1))
if err != nil {
......
......@@ -11,17 +11,26 @@ import (
)
const (
// HashLength 哈希长度
HashLength = 32
)
// Hash 重定义哈希类型
type Hash common.Hash
// Str 字符串形式
func (h Hash) Str() string { return string(h[:]) }
// Bytes 二进制形式
func (h Hash) Bytes() []byte { return h[:] }
// Big 大数字形式
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
// Hex 十六进制形式
func (h Hash) Hex() string { return Bytes2Hex(h[:]) }
// 设置哈希中的字节值,如果字节数组长度超过哈希长度,则被截断,只保留后面的部分
// SetBytes 设置哈希中的字节值,如果字节数组长度超过哈希长度,则被截断,只保留后面的部分
func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) {
b = b[len(b)-HashLength:]
......@@ -30,20 +39,17 @@ func (h *Hash) SetBytes(b []byte) {
copy(h[HashLength-len(b):], b)
}
// BigToHash 大数字转换为哈希
func BigToHash(b *big.Int) Hash {
return Hash(common.BigToHash(b))
}
// 将[]byte直接当做哈希处理
// BytesToHash 将[]byte直接当做哈希处理
func BytesToHash(b []byte) Hash {
return Hash(common.BytesToHash(b))
}
func EmptyHash(h Hash) bool {
return h == Hash{}
}
// 将[]byte经过哈希计算后转化为哈希对象
// ToHash 将[]byte经过哈希计算后转化为哈希对象
func ToHash(data []byte) Hash {
return BytesToHash(common.Sha256(data))
}
......@@ -4,7 +4,7 @@
package common
// 合约交易消息模型
// Message 合约交易消息模型
// 在EVM执行器中传递此消息,由外部Tx等价构造
type Message struct {
to *Address
......@@ -17,6 +17,7 @@ type Message struct {
data []byte
}
// NewMessage 新建消息结构
func NewMessage(from Address, to *Address, nonce int64, amount uint64, gasLimit uint64, gasPrice uint32, data []byte, alias string) *Message {
return &Message{
from: from,
......@@ -30,11 +31,26 @@ func NewMessage(from Address, to *Address, nonce int64, amount uint64, gasLimit
}
}
// From 来源
func (m Message) From() Address { return m.from }
// To 目的地址
func (m Message) To() *Address { return m.to }
// GasPrice Gas价格
func (m Message) GasPrice() uint32 { return m.gasPrice }
// Value 转账金额
func (m Message) Value() uint64 { return m.amount }
// Nonce nonce值
func (m Message) Nonce() int64 { return m.nonce }
// Data 附带数据
func (m Message) Data() []byte { return m.data }
// GasLimit Gas限制
func (m Message) GasLimit() uint64 { return m.gasLimit }
// Alias 合约别名
func (m Message) Alias() string { return m.alias }
......@@ -11,20 +11,26 @@ import (
)
const (
// GasQuickStep 计费
GasQuickStep uint64 = 2
// GasFastestStep 计费
GasFastestStep uint64 = 3
// GasFastStep 计费
GasFastStep uint64 = 5
// GasMidStep 计费
GasMidStep uint64 = 8
// GasSlowStep 计费
GasSlowStep uint64 = 10
// GasExtStep 计费
GasExtStep uint64 = 20
// 允许开辟的最大内存空间大小,超过此值时将会导致溢出
// MaxNewMemSize 允许开辟的最大内存空间大小,超过此值时将会导致溢出
MaxNewMemSize uint64 = 0xffffffffe0
)
// 返回真实花费的Gas
// availableGas - base * 63 / 64.
func callGas(gasTable GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
func callGas(gasTable Table, availableGas, base uint64, callCost *big.Int) (uint64, error) {
if availableGas == callCost.Uint64() {
availableGas = availableGas - base
gas := availableGas - availableGas/64
......
......@@ -12,15 +12,17 @@ import (
// 整数池允许的最大长度
const poolLimit = 256
// big.Int组成的内存池
// IntPool big.Int组成的内存池
type IntPool struct {
pool *Stack
}
// NewIntPool 创建新的内存池
func NewIntPool() *IntPool {
return &IntPool{pool: NewStack()}
}
// Get 取数据
func (p *IntPool) Get() *big.Int {
if p.pool.Len() > 0 {
return p.pool.Pop()
......@@ -28,6 +30,7 @@ func (p *IntPool) Get() *big.Int {
return new(big.Int)
}
// Put 存数据
func (p *IntPool) Put(is ...*big.Int) {
if len(p.pool.Items) > poolLimit {
return
......@@ -38,7 +41,7 @@ func (p *IntPool) Put(is ...*big.Int) {
}
}
// 返回一个零值的big.Int
// GetZero 返回一个零值的big.Int
func (p *IntPool) GetZero() *big.Int {
if p.pool.Len() > 0 {
return p.pool.Pop().SetUint64(0)
......@@ -49,17 +52,18 @@ func (p *IntPool) GetZero() *big.Int {
// 默认容量
const poolDefaultCap = 25
// 用于管理IntPool的Pool
// IntPoolPool 用于管理IntPool的Pool
type IntPoolPool struct {
pools []*IntPool
lock sync.Mutex
}
// PoolOfIntPools 内存缓冲池
var PoolOfIntPools = &IntPoolPool{
pools: make([]*IntPool, 0, poolDefaultCap),
}
// get is looking for an available pool to return.
// Get 返回一个可用的内存池
func (ipp *IntPoolPool) Get() *IntPool {
ipp.lock.Lock()
defer ipp.lock.Unlock()
......@@ -72,7 +76,7 @@ func (ipp *IntPoolPool) Get() *IntPool {
return NewIntPool()
}
// put a pool that has been allocated with get.
// Put 放入一个初始化过的内存池
func (ipp *IntPoolPool) Put(ip *IntPool) {
ipp.lock.Lock()
defer ipp.lock.Unlock()
......
......@@ -12,19 +12,20 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// 内存操作封装,在EVM中使用此对象模拟物理内存
// Memory 内存操作封装,在EVM中使用此对象模拟物理内存
type Memory struct {
// 内存中存储的数据
// Store 内存中存储的数据
Store []byte
// 上次开辟内存消耗的Gas
// LastGasCost 上次开辟内存消耗的Gas
LastGasCost uint64
}
// NewMemory 创建内存对象结构
func NewMemory() *Memory {
return &Memory{}
}
// 设置内存中的值, value => offset:offset + size
// Set 设置内存中的值, value => offset:offset + size
func (m *Memory) Set(offset, size uint64, value []byte) (err error) {
if size > 0 {
// 偏移量+大小一定不会大于内存长度
......@@ -39,7 +40,7 @@ func (m *Memory) Set(offset, size uint64, value []byte) (err error) {
return nil
}
// 从offset开始设置32个字节的内存值,如果值长度不足32个字节,左零值填充
// Set32 从offset开始设置32个字节的内存值,如果值长度不足32个字节,左零值填充
func (m *Memory) Set32(offset uint64, val *big.Int) (err error) {
// 确保长度足够设置值
......@@ -58,14 +59,14 @@ func (m *Memory) Set32(offset uint64, val *big.Int) (err error) {
return nil
}
// 扩充内存到指定大小
// Resize 扩充内存到指定大小
func (m *Memory) Resize(size uint64) {
if uint64(m.Len()) < size {
m.Store = append(m.Store, make([]byte, size-uint64(m.Len()))...)
}
}
// 获取内存中制定偏移量开始的指定长度的数据,返回数据的拷贝而非引用
// Get 获取内存中制定偏移量开始的指定长度的数据,返回数据的拷贝而非引用
func (m *Memory) Get(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
......@@ -81,7 +82,7 @@ func (m *Memory) Get(offset, size int64) (cpy []byte) {
return
}
// 同Get操作,不过这里返回的是数据引用
// GetPtr 同Get操作,不过这里返回的是数据引用
func (m *Memory) GetPtr(offset, size int64) []byte {
if size == 0 {
return nil
......@@ -94,17 +95,17 @@ func (m *Memory) GetPtr(offset, size int64) []byte {
return nil
}
// 返回内存中已开辟空间的大小(以字节计算)
// Len 返回内存中已开辟空间的大小(以字节计算)
func (m *Memory) Len() int {
return len(m.Store)
}
// 返回内存中的原始数据引用
// Data 返回内存中的原始数据引用
func (m *Memory) Data() []byte {
return m.Store
}
// 打印内存中的数据(调试用)
// Print 打印内存中的数据(调试用)
func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.Store))
if len(m.Store) > 0 {
......
......@@ -13,46 +13,56 @@ import (
// 本文件中定义各种操作下计算内存大小的逻辑
type (
// 计算所需内存大小
// MemorySizeFunc 计算所需内存大小
MemorySizeFunc func(*Stack) *big.Int
)
// MemorySha3 sha3计算所需内存大小
func MemorySha3(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryCallDataCopy callDataCopy所需内存大小
func MemoryCallDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryReturnDataCopy returnDataCopy所需内存大小
func MemoryReturnDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryCodeCopy codeCopy所需内存大小
func MemoryCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryExtCodeCopy extCodeCopy所需内存大小
func MemoryExtCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(3))
}
//MemoryMLoad mload所需内存大小
func MemoryMLoad(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
}
//MemoryMStore8 mstore8所需内存大小
func MemoryMStore8(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(1))
}
//MemoryMStore mstore所需内存大小
func MemoryMStore(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
}
//MemoryCreate create所需内存大小
func MemoryCreate(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(2))
}
//MemoryCall call所需内存大小
func MemoryCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
......@@ -60,6 +70,7 @@ func MemoryCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryDelegateCall delegateCall所需内存大小
func MemoryDelegateCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
......@@ -67,6 +78,7 @@ func MemoryDelegateCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryStaticCall staticCall所需内存大小
func MemoryStaticCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
......@@ -74,14 +86,17 @@ func MemoryStaticCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryReturn return所需内存大小
func MemoryReturn(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryRevert revert所需内存大小
func MemoryRevert(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryLog log所需内存大小
func MemoryLog(stack *Stack) *big.Int {
mSize, mStart := stack.Back(1), stack.Back(0)
return calcMemSize(mStart, mSize)
......
......@@ -11,63 +11,64 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/params"
)
// 栈对象封装,提供常用的栈操作
// Stack 栈对象封装,提供常用的栈操作
type Stack struct {
Items []*big.Int
}
// NewStack 新创建栈对象
func NewStack() *Stack {
return &Stack{Items: make([]*big.Int, 0, params.StackLimit)}
}
// 返回栈中的所有底层数据
// Data 返回栈中的所有底层数据
func (st *Stack) Data() []*big.Int {
return st.Items
}
// 数据入栈
// Push 数据入栈
func (st *Stack) Push(d *big.Int) {
st.Items = append(st.Items, d)
}
// 同时压栈多个数据
// PushN 同时压栈多个数据
func (st *Stack) PushN(ds ...*big.Int) {
st.Items = append(st.Items, ds...)
}
// 弹出栈顶数据
// Pop 弹出栈顶数据
func (st *Stack) Pop() (ret *big.Int) {
ret = st.Items[len(st.Items)-1]
st.Items = st.Items[:len(st.Items)-1]
return
}
// 栈长度
// Len 栈长度
func (st *Stack) Len() int {
return len(st.Items)
}
// 将栈顶数据和栈中指定位置的数据互换位置
// Swap 将栈顶数据和栈中指定位置的数据互换位置
func (st *Stack) Swap(n int) {
st.Items[st.Len()-n], st.Items[st.Len()-1] = st.Items[st.Len()-1], st.Items[st.Len()-n]
}
// 复制栈中指定位置的数据的栈顶
// Dup 复制栈中指定位置的数据的栈顶
func (st *Stack) Dup(pool *IntPool, n int) {
st.Push(pool.Get().Set(st.Items[st.Len()-n]))
}
// 返回顶端数据
// Peek 返回顶端数据
func (st *Stack) Peek() *big.Int {
return st.Items[st.Len()-1]
}
// 返回第n个取值
// Back 返回第n个取值
func (st *Stack) Back(n int) *big.Int {
return st.Items[st.Len()-n-1]
}
// 检查栈是否满足长度要求
// Require 检查栈是否满足长度要求
func (st *Stack) Require(n int) error {
if st.Len() < n {
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.Items), n)
......@@ -75,7 +76,7 @@ func (st *Stack) Require(n int) error {
return nil
}
// 印栈对象(调试用)
// Print 印栈对象(调试用)
func (st *Stack) Print() {
fmt.Println("### stack ###")
if len(st.Items) > 0 {
......
......@@ -11,11 +11,11 @@ import (
)
type (
// 校验栈中数据是否满足计算要求
// StackValidationFunc 校验栈中数据是否满足计算要求
StackValidationFunc func(*Stack) error
)
// 栈校验的通用逻辑封装(主要就是检查栈的深度和空间是否够用)
// MakeStackFunc 栈校验的通用逻辑封装(主要就是检查栈的深度和空间是否够用)
func MakeStackFunc(pop, push int) StackValidationFunc {
return func(stack *Stack) error {
if err := stack.Require(pop); err != nil {
......@@ -29,10 +29,12 @@ func MakeStackFunc(pop, push int) StackValidationFunc {
}
}
// MakeDupStackFunc 创建栈大小计算方法对象
func MakeDupStackFunc(n int) StackValidationFunc {
return MakeStackFunc(n, n+1)
}
// MakeSwapStackFunc 创建栈大小计算方法对象
func MakeSwapStackFunc(n int) StackValidationFunc {
return MakeStackFunc(n, n)
}
......@@ -5,8 +5,8 @@
package model
const (
// 内存中存储的字,占用多少位
// WordBitSize 内存中存储的字,占用多少位
WordBitSize = 256
// 内存中存储的字,占用多少字节
// WordByteSize 内存中存储的字,占用多少字节
WordByteSize = WordBitSize / 8
)
......@@ -7,24 +7,38 @@ package model
import "errors"
var (
// ErrOutOfGas out of gas
ErrOutOfGas = errors.New("out of gas")
// ErrCodeStoreOutOfGas contract creation code storage out of gas
ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas")
// ErrDepth max call depth exceeded
ErrDepth = errors.New("max call depth exceeded")
ErrTraceLimitReached = errors.New("the number of logs reached the specified limit")
// ErrInsufficientBalance insufficient balance for transfer
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
// ErrContractAddressCollision contract address collision
ErrContractAddressCollision = errors.New("contract address collision")
ErrGasLimitReached = errors.New("gas limit reached")
// ErrGasUintOverflow gas uint64 overflow
ErrGasUintOverflow = errors.New("gas uint64 overflow")
// ErrAddrNotExists address not exists
ErrAddrNotExists = errors.New("address not exists")
// ErrTransferBetweenContracts transferring between contracts not supports
ErrTransferBetweenContracts = errors.New("transferring between contracts not supports")
// ErrTransferBetweenEOA transferring between external accounts not supports
ErrTransferBetweenEOA = errors.New("transferring between external accounts not supports")
// ErrNoCreator contract has no creator information
ErrNoCreator = errors.New("contract has no creator information")
// ErrDestruct contract has been destructed
ErrDestruct = errors.New("contract has been destructed")
// ErrWriteProtection evm: write protection
ErrWriteProtection = errors.New("evm: write protection")
// ErrReturnDataOutOfBounds evm: return data out of bounds
ErrReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
// ErrExecutionReverted evm: execution reverted
ErrExecutionReverted = errors.New("evm: execution reverted")
// ErrMaxCodeSizeExceeded evm: max code size exceeded
ErrMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
NoCoinsAccount = errors.New("no coins account in executor!")
// ErrNoCoinsAccount no coins account in executor!
ErrNoCoinsAccount = errors.New("no coins account in executor")
)
......@@ -9,26 +9,26 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// 合约在日志,对应EVM中的Log指令,可以生成指定的日志信息
// ContractLog 合约在日志,对应EVM中的Log指令,可以生成指定的日志信息
// 目前这些日志只是在合约执行完成时进行打印,没有其它用途
type ContractLog struct {
// 合约地址
// Address 合约地址
Address common.Address
// 对应交易哈希
// TxHash 对应交易哈希
TxHash common.Hash
// 日志序号
// Index 日志序号
Index int
// 此合约提供的主题信息
// Topics 此合约提供的主题信息
Topics []common.Hash
// 日志数据
// Data 日志数据
Data []byte
}
// 合约日志打印格式
// PrintLog 合约日志打印格式
func (log *ContractLog) PrintLog() {
log15.Debug("!Contract Log!", "Contract address", log.Address.String(), "TxHash", log.TxHash.Hex(), "Log Index", log.Index, "Log Topics", log.Topics, "Log Data", common.Bytes2Hex(log.Data))
}
......@@ -11,19 +11,19 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/state"
)
// 解释器中调用Gas计算时所传递的合约中和Gas相关的参数结构
// GasParam 解释器中调用Gas计算时所传递的合约中和Gas相关的参数结构
// 之所以单独封装,是为了将解释器、指令集、Gas计算三者解耦
// 此结构包含的属性均为只读
type GasParam struct {
// 此合约对象的可用Gas(合约执行过程中会修改此值)
// Gas 此合约对象的可用Gas(合约执行过程中会修改此值)
Gas uint64
// 上下文中合约自身的地址
// Address 上下文中合约自身的地址
// 注意,当合约通过CallCode调用时,这个地址并不是当前合约代码对应的地址,而是调用者的地址
Address common.Address
}
// 解释器中调用Gas计算时所传递的合约中和EVM相关的参数结构
// EVMParam 解释器中调用Gas计算时所传递的合约中和EVM相关的参数结构
// 之所以单独封装,是为了将解释器、Gas计算两者解耦
// 此结构包含的属性中StateDB和CallGasTemp可写,解释器调用Gas计算的步骤如下:
// 1. 使用EVM构造EVMParam(属性除CallGasTemp外,全部传递引用);
......@@ -31,14 +31,14 @@ type GasParam struct {
// 3. 计算结束后,使用EVMParam中的值回填到EVM中;
type EVMParam struct {
// 状态数据操作入口
StateDB state.StateDB
// EVMStateDB 状态数据操作入口
StateDB state.EVMStateDB
// 此属性用于临时存储计算出来的Gas消耗值
// CallGasTemp 此属性用于临时存储计算出来的Gas消耗值
// 在指令执行时,会调用指令的gasCost方法,计算出此指令需要消耗的Gas,并存放在此临时属性中
// 然后在执行opCall时,从此属性获取消耗的Gas值
CallGasTemp uint64
// NUMBER 指令,当前区块高度
// BlockNumber NUMBER 指令,当前区块高度
BlockNumber *big.Int
}
......@@ -5,43 +5,75 @@
package params
const (
MaxCodeSize = 24576 // 合约允许的最大字节数
CallCreateDepth uint64 = 1024 // 合约递归调用最大深度
StackLimit uint64 = 1024 // 栈允许的最大深度
// MaxCodeSize 合约允许的最大字节数
MaxCodeSize = 24576
// CallCreateDepth 合约递归调用最大深度
CallCreateDepth uint64 = 1024
// StackLimit 栈允许的最大深度
StackLimit uint64 = 1024
// 各种操作对应的Gas定价
CreateDataGas uint64 = 200 // 创建合约时,按字节计费
CallStipend uint64 = 2300 // 每次CALL调用之前,给予一定额度的免费Gas
CallValueTransferGas uint64 = 9000 // 转账操作
CallNewAccountGas uint64 = 25000 // 操作目标地址事先不存在
QuadCoeffDiv uint64 = 512 // 计算开辟内存花费时,在计算出的内存大小平方基础上除此值
CopyGas uint64 = 3 // 内存数据复制时,按字计费
// CreateDataGas 创建合约时,按字节计费
CreateDataGas uint64 = 200
// CallStipend 每次CALL调用之前,给予一定额度的免费Gas
CallStipend uint64 = 2300
// CallValueTransferGas 转账操作
CallValueTransferGas uint64 = 9000
// CallNewAccountGas 操作目标地址事先不存在
CallNewAccountGas uint64 = 25000
// QuadCoeffDiv 计算开辟内存花费时,在计算出的内存大小平方基础上除此值
QuadCoeffDiv uint64 = 512
// CopyGas 内存数据复制时,按字计费
CopyGas uint64 = 3
Sha3Gas uint64 = 30 // SHA3操作
Sha3WordGas uint64 = 6 // SHA3操作的数据按字计费
SstoreSetGas uint64 = 20000 // SSTORE 从零值地址到非零值地址存储
SstoreResetGas uint64 = 5000 // SSTORE 从非零值地址到非零值地址存储
SstoreClearGas uint64 = 5000 // SSTORE 从非零值地址到零值地址存储
SstoreRefundGas uint64 = 15000 // SSTORE 删除值时给予的奖励
JumpdestGas uint64 = 1 // JUMPDEST 指令
LogGas uint64 = 375 // LOGN 操作计费
LogDataGas uint64 = 8 // LOGN生成的数据,每个字节的计费价格
LogTopicGas uint64 = 375 // LOGN 生成日志时,使用N*此值计费
CreateGas uint64 = 32000 // CREATE 指令
SuicideRefundGas uint64 = 24000 // SUICIDE 操作时给予的奖励
MemoryGas uint64 = 3 // 开辟新内存时按字收费
// Sha3Gas SHA3操作
Sha3Gas uint64 = 30
// Sha3WordGas SHA3操作的数据按字计费
Sha3WordGas uint64 = 6
// SstoreSetGas SSTORE 从零值地址到非零值地址存储
SstoreSetGas uint64 = 20000
// SstoreResetGas SSTORE 从非零值地址到非零值地址存储
SstoreResetGas uint64 = 5000
// SstoreClearGas SSTORE 从非零值地址到零值地址存储
SstoreClearGas uint64 = 5000
// SstoreRefundGas SSTORE 删除值时给予的奖励
SstoreRefundGas uint64 = 15000
// JumpdestGas JUMPDEST 指令
JumpdestGas uint64 = 1
// LogGas LOGN 操作计费
LogGas uint64 = 375
// LogDataGas LOGN生成的数据,每个字节的计费价格
LogDataGas uint64 = 8
// LogTopicGas LOGN 生成日志时,使用N*此值计费
LogTopicGas uint64 = 375
// CreateGas CREATE 指令
CreateGas uint64 = 32000
// SuicideRefundGas SUICIDE 操作时给予的奖励
SuicideRefundGas uint64 = 24000
// MemoryGas 开辟新内存时按字收费
MemoryGas uint64 = 3
// 预编译合约的Gas定价
EcrecoverGas uint64 = 3000 // ecrecover 指令
Sha256BaseGas uint64 = 60 // SHA256 基础计费
Sha256PerWordGas uint64 = 12 // SHA256 按字长计费 (总计费等于两者相加)
Ripemd160BaseGas uint64 = 600 // RIPEMD160 基础计费
Ripemd160PerWordGas uint64 = 120 // RIPEMD160 按字长计费 (总计费等于两者相加)
IdentityBaseGas uint64 = 15 // dataCopy 基础计费
IdentityPerWordGas uint64 = 3 // dataCopy 按字长计费(总计费等于两者相加)
ModExpQuadCoeffDiv uint64 = 20 // 大整数取模运算时计算出的费用除此数
Bn256AddGas uint64 = 500 // Bn256Add 计费
Bn256ScalarMulGas uint64 = 40000 // Bn256ScalarMul 计费
Bn256PairingBaseGas uint64 = 100000 // bn256Pairing 基础计费
Bn256PairingPerPointGas uint64 = 80000 // bn256Pairing 按point计费(总计费等于两者相加)
// EcrecoverGas ecrecover 指令
EcrecoverGas uint64 = 3000
// Sha256BaseGas SHA256 基础计费
Sha256BaseGas uint64 = 60
// Sha256PerWordGas SHA256 按字长计费 (总计费等于两者相加)
Sha256PerWordGas uint64 = 12
// Ripemd160BaseGas RIPEMD160 基础计费
Ripemd160BaseGas uint64 = 600
// Ripemd160PerWordGas RIPEMD160 按字长计费 (总计费等于两者相加)
Ripemd160PerWordGas uint64 = 120
// IdentityBaseGas dataCopy 基础计费
IdentityBaseGas uint64 = 15
// IdentityPerWordGas dataCopy 按字长计费(总计费等于两者相加)
IdentityPerWordGas uint64 = 3
// ModExpQuadCoeffDiv 大整数取模运算时计算出的费用除此数
ModExpQuadCoeffDiv uint64 = 20
// Bn256AddGas Bn256Add 计费
Bn256AddGas uint64 = 500
// Bn256ScalarMulGas Bn256ScalarMul 计费
Bn256ScalarMulGas uint64 = 40000
// Bn256PairingBaseGas bn256Pairing 基础计费
Bn256PairingBaseGas uint64 = 100000
// Bn256PairingPerPointGas bn256Pairing 按point计费(总计费等于两者相加)
Bn256PairingPerPointGas uint64 = 80000
)
......@@ -15,7 +15,7 @@ import (
// JUMPDEST指令会使用此对象进行跳转位置判断
type Destinations map[common.Hash]bitvec
// 检查PC只想的代码是否存在JUMPDEST指令,并且跳转目标有效
// Has 检查PC只想的代码是否存在JUMPDEST指令,并且跳转目标有效
func (d Destinations) Has(codehash common.Hash, code []byte, dest *big.Int) bool {
// 首先需要检查PC(指令指针),它不可能比代码长度还大,也不可能大于63位
// 注意,这里的参数dest就是PC指针
......
......@@ -8,22 +8,22 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// 合约对象引用
// ContractRef 合约对象引用
type ContractRef interface {
Address() common.Address
}
// 账户对象引用 (实现了合约对象引用ContractRef接口)
// AccountRef 账户对象引用 (实现了合约对象引用ContractRef接口)
// 因为在合约调用过程中,调用者有可能是外部账户,也有可能是合约账户,所以两者的结构是互通的
type AccountRef common.Address
// 将账户引用转换为普通地址对象
// Address 将账户引用转换为普通地址对象
func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
// 合约对象,它在内存中表示一个合约账户的代码即地址信息实体
// Contract 合约对象,它在内存中表示一个合约账户的代码即地址信息实体
// 每次合约调用都会创建一个新的合约对象
type Contract struct {
// 调用者地址,应该为外部账户的地址
// CallerAddress 调用者地址,应该为外部账户的地址
// 如果是通过合约再调用合约时,会从上级合约中获取调用者地址进行赋值
CallerAddress common.Address
......@@ -34,28 +34,30 @@ type Contract struct {
// 但是,二般情况下(外部账户通过CallCode直接调用合约代码时,此地址会设置为外部账户的地址,就是和caller一样)
self ContractRef
// 存储跳转信息,供JUMP和JUMPI指令使用
// Jumpdests 存储跳转信息,供JUMP和JUMPI指令使用
Jumpdests Destinations
// 合约代码和代码哈希
// Code合约代码
Code []byte
// CodeHash 代码哈希
CodeHash common.Hash
// 合约地址以及输入参数
// CodeAddr 合约地址
CodeAddr *common.Address
// Input 输入参数
Input []byte
// 此合约对象的可用Gas(合约执行过程中会修改此值)
// Gas 此合约对象的可用Gas(合约执行过程中会修改此值)
Gas uint64
// 合约调用的同时,如果包含转账逻辑,则此处为转账金额
// value 合约调用的同时,如果包含转账逻辑,则此处为转账金额
value uint64
// 委托调用时,此属性会被设置为true
// DelegateCall 委托调用时,此属性会被设置为true
DelegateCall bool
}
// 创建一个新的合约调用对象
// NewContract 创建一个新的合约调用对象
// 不管合约是否存在,每次调用时都会新创建一个合约对象交给解释器执行,对象持有合约代码和合约地址
func NewContract(caller ContractRef, object ContractRef, value uint64, gas uint64) *Contract {
......@@ -76,7 +78,7 @@ func NewContract(caller ContractRef, object ContractRef, value uint64, gas uint6
return c
}
// 设置当前的合约对象为被委托调用
// AsDelegate 设置当前的合约对象为被委托调用
// 返回当前合约对象的指针,以便在多层调用链模式下使用
func (c *Contract) AsDelegate() *Contract {
c.DelegateCall = true
......@@ -92,12 +94,12 @@ func (c *Contract) AsDelegate() *Contract {
return c
}
// 获取合约代码中制定位置的操作码
// GetOp 获取合约代码中制定位置的操作码
func (c *Contract) GetOp(n uint64) OpCode {
return OpCode(c.GetByte(n))
}
// 获取合约代码中制定位置的字节值
// GetByte 获取合约代码中制定位置的字节值
func (c *Contract) GetByte(n uint64) byte {
if n < uint64(len(c.Code)) {
return c.Code[n]
......@@ -106,14 +108,14 @@ func (c *Contract) GetByte(n uint64) byte {
return 0
}
// 返回合约的调用者
// Caller 返回合约的调用者
// 如果当前合约为委托调用,则调用它的不是外部账户,而是合约账户,所以此时的caller为调用此合约的合约的caller
// 这个关系可以一直递归向上,直到定位到caller为外部账户地址
func (c *Contract) Caller() common.Address {
return c.CallerAddress
}
// 从合约的可用gas中进行gas消费
// UseGas 从合约的可用gas中进行gas消费
func (c *Contract) UseGas(gas uint64) (ok bool) {
if c.Gas < gas {
return false
......@@ -122,26 +124,26 @@ func (c *Contract) UseGas(gas uint64) (ok bool) {
return true
}
// 返回上下文中合约自身的地址
// Address 返回上下文中合约自身的地址
// 注意,当合约通过CallCode调用时,这个地址并不是当前合约代码对应的地址,而是调用者的地址
func (c *Contract) Address() common.Address {
return c.self.Address()
}
// 合约包含转账逻辑时,转账的金额
// Value 合约包含转账逻辑时,转账的金额
func (c *Contract) Value() uint64 {
return c.value
}
// 设置合约代码内容
func (self *Contract) SetCode(hash common.Hash, code []byte) {
self.Code = code
self.CodeHash = hash
// SetCode 设置合约代码内容
func (c *Contract) SetCode(hash common.Hash, code []byte) {
c.Code = code
c.CodeHash = hash
}
// 设置合约代码和代码哈希
func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
self.Code = code
self.CodeHash = hash
self.CodeAddr = addr
// SetCallCode 设置合约代码和代码哈希
func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
c.Code = code
c.CodeHash = hash
c.CodeAddr = addr
}
......@@ -17,7 +17,7 @@ import (
"golang.org/x/crypto/ripemd160"
)
// 系统内置合约实现的接口,只包含两个操作:
// PrecompiledContract 系统内置合约实现的接口,只包含两个操作:
// 1 根据合约自身逻辑和入参,计算所需Gas;
// 2 执行合约。
type PrecompiledContract interface {
......@@ -28,7 +28,7 @@ type PrecompiledContract interface {
Run(input []byte) ([]byte, error)
}
// chain33平台支持君士坦丁堡版本支持的所有预编译合约指令,并从此版本开始同步支持EVM黄皮书中的新增指令;
// PrecompiledContractsByzantium chain33平台支持君士坦丁堡版本支持的所有预编译合约指令,并从此版本开始同步支持EVM黄皮书中的新增指令;
// 保存拜占庭版本支持的所有预编译合约(包括之前版本的合约);
// 后面如果有硬分叉,需要在此处考虑分叉逻辑,根据区块高度分别处理;
// 下面的8个预编译指令,直接引用go-ethereum中的EVM实现
......@@ -46,7 +46,7 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{8}): &bn256Pairing{},
}
// 调用预编译的合约逻辑并返回结果
// RunPrecompiledContract 调用预编译的合约逻辑并返回结果
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
gas := p.RequiredGas(input)
if contract.UseGas(gas) {
......@@ -58,10 +58,12 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr
// 预编译合约 ECRECOVER 椭圆曲线算法支持
type ecrecover struct{}
// RequiredGas 需要消耗多少Gas
func (c *ecrecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas
}
// Run 运算
func (c *ecrecover) Run(input []byte) ([]byte, error) {
const ecRecoverInputLength = 128
......@@ -98,6 +100,8 @@ type sha256hash struct{}
func (c *sha256hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
}
// Run run
func (c *sha256hash) Run(input []byte) ([]byte, error) {
h := sha256.Sum256(input)
return h[:], nil
......@@ -113,6 +117,8 @@ type ripemd160hash struct{}
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
}
// Run run
func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
ripemd := ripemd160.New()
ripemd.Write(input)
......@@ -129,6 +135,8 @@ type dataCopy struct{}
func (c *dataCopy) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
}
// Run run
func (c *dataCopy) Run(in []byte) ([]byte, error) {
return in, nil
}
......@@ -210,6 +218,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
return gas.Uint64()
}
// Run run
func (c *bigModExp) Run(input []byte) ([]byte, error) {
var (
baseLen = new(big.Int).SetBytes(common.GetData(input, 0, 32)).Uint64()
......
This diff is collapsed.
......@@ -397,7 +397,7 @@ func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack *
data := memory.Get(offset.Int64(), size.Int64())
hash := crypto.Keccak256(data)
if evm.VmConfig.EnablePreimageRecording {
if evm.VMConfig.EnablePreimageRecording {
evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
}
......
......@@ -15,25 +15,26 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/params"
)
// 解释器的配置模型
// Config 解释器的配置模型
type Config struct {
// 调试开关
// Debug 调试开关
Debug bool
// 记录操作日志
// Tracer 记录操作日志
Tracer Tracer
// 不允许使用Call, CallCode, DelegateCall
// NoRecursion 不允许使用Call, CallCode, DelegateCall
NoRecursion bool
// SHA3/keccak 操作时是否保存数据
// EnablePreimageRecording SHA3/keccak 操作时是否保存数据
EnablePreimageRecording bool
// 指令跳转表
// JumpTable 指令跳转表
JumpTable [256]Operation
}
// 解释器接结构定义
// Interpreter 解释器接结构定义
type Interpreter struct {
evm *EVM
cfg Config
gasTable gas.GasTable
gasTable gas.Table
// IntPool 整数内存池
IntPool *mm.IntPool
// 是否允许修改数据
......@@ -42,6 +43,7 @@ type Interpreter struct {
ReturnData []byte
}
// NewInterpreter 新创建一个解释器
func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
// 使用是否包含第一个STOP指令判断jump table是否完成初始化
// 需要注意,后继如果新增指令,需要在这里判断硬分叉,指定不同的指令集
......@@ -67,7 +69,7 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation Operation, stack
return nil
}
// 合约代码的解释执行主逻辑
// Run 合约代码的解释执行主逻辑
// 需要注意的是,如果返回执行出错,依然会扣除剩余的Gas
// (除非返回的是ErrExecutionReverted,这种情况下会保留剩余的Gas)
func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
......@@ -201,7 +203,7 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er
// 目前只按需构造必要的参数,理论上GasFun进行Gas计算时可以使用Contract中的所有参数
// 后继视需要修改GasParam结构
func buildGasParam(contract *Contract) *params.GasParam {
return &params.GasParam{contract.Gas, contract.Address()}
return &params.GasParam{Gas: contract.Gas, Address: contract.Address()}
}
// 从EVM构造参数传递给GasFunc逻辑使用
......
......@@ -15,44 +15,60 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/mm"
)
// Tracer接口用来在合约执行过程中收集跟踪数据。
// Tracer 接口用来在合约执行过程中收集跟踪数据。
// CaptureState 会在EVM解释每条指令时调用。
// 需要注意的是,传入的引用参数不允许修改,否则会影响EVM解释执行;如果需要使用其中的数据,请复制后使用。
type Tracer interface {
// CaptureStart 开始记录
CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value uint64) error
// CaptureState 保存状态
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error
// CaptureFault 保存错误
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error
// CaptureEnd 结束记录
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
}
// 使用json格式打印日志
// JSONLogger 使用json格式打印日志
type JSONLogger struct {
encoder *json.Encoder
}
// 指令执行状态信息
// StructLog 指令执行状态信息
type StructLog struct {
// Pc pc指针
Pc uint64 `json:"pc"`
// Op 操作码
Op string `json:"op"`
// Gas gas
Gas uint64 `json:"gas"`
// GasCost 花费
GasCost uint64 `json:"gasCost"`
// Memory 内存对象
Memory []string `json:"memory"`
// MemorySize 内存大小
MemorySize int `json:"memSize"`
// Stack 栈对象
Stack []string `json:"stack"`
// Storage 存储对象
Storage map[common.Hash]common.Hash `json:"-"`
// Depth 调用深度
Depth int `json:"depth"`
// Err 错误信息
Err error `json:"-"`
}
// NewJSONLogger 创建新的日志记录器
func NewJSONLogger(writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer)}
}
// CaptureStart 开始记录
func (logger *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value uint64) error {
return nil
}
// CaptureState outputs state information on the logger.
// CaptureState 输出当前虚拟机状态
func (logger *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error {
log := StructLog{
Pc: pc,
......@@ -72,7 +88,6 @@ func (logger *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost
func formatStack(data []*big.Int) (res []string) {
for _, v := range data {
res = append(res, v.Text(16))
v.String()
}
return
}
......@@ -84,12 +99,12 @@ func formatMemory(data []byte) (res []string) {
return
}
// CaptureFault outputs state information on the logger.
// CaptureFault 目前实现为空
func (logger *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *mm.Memory, stack *mm.Stack, contract *Contract, depth int, err error) error {
return nil
}
// CaptureEnd is triggered at end of execution.
// CaptureEnd 结束记录
func (logger *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
type endLog struct {
Output string `json:"output"`
......
......@@ -4,10 +4,10 @@
package runtime
// EVM操作码定义,本质上就是一个字节,所以操作码最多只支持256个
// OpCode EVM操作码定义,本质上就是一个字节,所以操作码最多只支持256个
type OpCode byte
// 是否为压栈操作
// IsPush 是否为压栈操作
func (op OpCode) IsPush() bool {
if op >= PUSH1 && op <= PUSH32 {
return true
......@@ -15,14 +15,14 @@ func (op OpCode) IsPush() bool {
return false
}
// 是否为跳转操作
// IsStaticJump 是否为跳转操作
func (op OpCode) IsStaticJump() bool {
return op == JUMP
}
var opmap map[OpCode]string
// 是否为跳转操作
// String 打印字符串形式
func (op OpCode) String() string {
if opmap == nil {
initMap()
......@@ -197,178 +197,310 @@ func initMap() {
// unofficial opcodes used for parsing
const (
// PUSH 压栈操作
PUSH OpCode = 0xb0 + iota
// DUP 操作
DUP
// SWAP 操作
SWAP
)
const (
// 0x0 算术操作
// STOP 0x0 算术操作
STOP OpCode = iota
// ADD 操作
ADD
// MUL op
MUL
// SUB op
SUB
// DIV op
DIV
// SDIV op
SDIV
// MOD op
MOD
// SMOD op
SMOD
// ADDMOD op
ADDMOD
// MULMOD op
MULMOD
// EXP op
EXP
// SIGNEXTEND op
SIGNEXTEND
)
const (
// 比较、位操作
// LT 比较、位操作
LT OpCode = iota + 0x10
// GT op
GT
// SLT op
SLT
// SGT op
SGT
// EQ op
EQ
// ISZERO op
ISZERO
// AND op
AND
// OR op
OR
// XOR op
XOR
// NOT op
NOT
// BYTE op
BYTE
// SHL op
SHL
// SHR op
SHR
// SAR op
SAR
// SHA3 op
SHA3 = 0x20
)
const (
// 0x30 合约数据操作
// ADDRESS 0x30 合约数据操作
ADDRESS OpCode = 0x30 + iota
// BALANCE op
BALANCE
// ORIGIN op
ORIGIN
// CALLER op
CALLER
// CALLVALUE op
CALLVALUE
// CALLDATALOAD op
CALLDATALOAD
// CALLDATASIZE op
CALLDATASIZE
// CALLDATACOPY op
CALLDATACOPY
// CODESIZE op
CODESIZE
// CODECOPY op
CODECOPY
// GASPRICE op
GASPRICE
// EXTCODESIZE op
EXTCODESIZE
// EXTCODECOPY op
EXTCODECOPY
// RETURNDATASIZE op
RETURNDATASIZE
// RETURNDATACOPY op
RETURNDATACOPY
)
const (
// 0x40 区块相关操作
// BLOCKHASH 0x40 区块相关操作
BLOCKHASH OpCode = 0x40 + iota
// COINBASE op
COINBASE
// TIMESTAMP op
TIMESTAMP
// NUMBER op
NUMBER
// DIFFICULTY op
DIFFICULTY
// GASLIMIT op
GASLIMIT
)
const (
// 0x50 存储相关操作
// POP 0x50 存储相关操作
POP OpCode = 0x50 + iota
// MLOAD op
MLOAD
// MSTORE op
MSTORE
// MSTORE8 op
MSTORE8
// SLOAD op
SLOAD
// SSTORE op
SSTORE
// JUMP op
JUMP
// JUMPI op
JUMPI
// PC op
PC
// MSIZE op
MSIZE
// GAS op
GAS
// JUMPDEST op
JUMPDEST
)
const (
// 0x60 栈操作
// PUSH1 0x60 栈操作
PUSH1 OpCode = 0x60 + iota
// PUSH2 op
PUSH2
// PUSH3 op
PUSH3
// PUSH4 op
PUSH4
// PUSH5 op
PUSH5
// PUSH6 op
PUSH6
// PUSH7 op
PUSH7
// PUSH8 op
PUSH8
// PUSH9 op
PUSH9
// PUSH10 op
PUSH10
// PUSH11 op
PUSH11
// PUSH12 op
PUSH12
// PUSH13 op
PUSH13
// PUSH14 op
PUSH14
// PUSH15 op
PUSH15
// PUSH16 op
PUSH16
// PUSH17 op
PUSH17
// PUSH18 op
PUSH18
// PUSH19 op
PUSH19
// PUSH20 op
PUSH20
// PUSH21 op
PUSH21
// PUSH22 op
PUSH22
// PUSH23 op
PUSH23
// PUSH24 op
PUSH24
// PUSH25 op
PUSH25
// PUSH26 op
PUSH26
// PUSH27 op
PUSH27
// PUSH28 op
PUSH28
// PUSH29 op
PUSH29
// PUSH30 op
PUSH30
// PUSH31 op
PUSH31
// PUSH32 op
PUSH32
// DUP1 op
DUP1
// DUP2 op
DUP2
// DUP3 op
DUP3
// DUP4 op
DUP4
// DUP5 op
DUP5
// DUP6 op
DUP6
// DUP7 op
DUP7
// DUP8 op
DUP8
// DUP9 op
DUP9
// DUP10 op
DUP10
// DUP11 op
DUP11
// DUP12 op
DUP12
// DUP13 op
DUP13
// DUP14 op
DUP14
// DUP15 op
DUP15
// DUP16 op
DUP16
// SWAP1 op
SWAP1
// SWAP2 op
SWAP2
// SWAP3 op
SWAP3
// SWAP4 op
SWAP4
// SWAP5 op
SWAP5
// SWAP6 op
SWAP6
// SWAP7 op
SWAP7
// SWAP8 op
SWAP8
// SWAP9 op
SWAP9
// SWAP10 op
SWAP10
// SWAP11 op
SWAP11
// SWAP12 op
SWAP12
// SWAP13 op
SWAP13
// SWAP14 op
SWAP14
// SWAP15 op
SWAP15
// SWAP16 op
SWAP16
)
const (
// 生成日志
// LOG0 生成日志
LOG0 OpCode = 0xa0 + iota
// LOG1 op
LOG1
// LOG2 op
LOG2
// LOG3 op
LOG3
// LOG4 op
LOG4
)
const (
// 过程调用
// CREATE 过程调用
CREATE OpCode = 0xf0 + iota
// CALL op
CALL
// CALLCODE op
CALLCODE
// RETURN op
RETURN
// DELEGATECALL op
DELEGATECALL
// STATICCALL op
STATICCALL = 0xfa
// REVERT op
REVERT = 0xfd
// SELFDESTRUCT op
SELFDESTRUCT = 0xff
)
......@@ -12,8 +12,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 本文件用来存储硬分叉中需要用到的数据
// BlockData 本文件用来存储硬分叉中需要用到的数据
type BlockData struct {
blockHeight int64
testnet bool
......@@ -21,9 +20,11 @@ type BlockData struct {
txs map[string]*TxData
}
// TxData 交易数据
type TxData struct {
// KV 交易生成的KV数据
KV map[string][]byte
// Key 为logType_logIndex
// Logs Key 为logType_logIndex
Logs map[string][]byte
}
......@@ -47,6 +48,7 @@ func makeLogReceiptKey(logType int32, logIndex int) string {
return fmt.Sprintf("%v_%v", logType, logIndex)
}
// InitForkData 初始化硬分叉数据
func InitForkData() {
forkData = make(map[int64]*BlockData)
......@@ -72,6 +74,7 @@ func InitForkData() {
forkData[556294] = data
}
// ProcessFork 处理硬分叉逻辑
func ProcessFork(blockHeight int64, txHash []byte, receipt *types.Receipt) {
if types.IsLocal() {
return
......
......@@ -9,69 +9,69 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model"
)
// 状态数据库封装,面向EVM业务执行逻辑;
// EVMStateDB 状态数据库封装,面向EVM业务执行逻辑;
// 生命周期为一个区块,在同一个区块内多个交易执行时使用的是同一个StateDB实例;
// StateDB包含区块的状态和交易的状态(当前上下文),所以不支持并发操作,区块内的多个交易只能按顺序单线程执行;
// StateDB除了查询状态数据,还会保留在交易执行时对数据的变更信息,每个交易完成之后会返回变更影响的数据给执行器;
type StateDB interface {
// 创建新的合约对象
type EVMStateDB interface {
// CreateAccount 创建新的合约对象
CreateAccount(string, string, string, string)
// 从指定地址扣除金额
// SubBalance 从指定地址扣除金额
SubBalance(string, string, uint64)
// 向指定地址增加金额
// AddBalance 向指定地址增加金额
AddBalance(string, string, uint64)
// 获取指定地址的余额
// GetBalance 获取指定地址的余额
GetBalance(string) uint64
// 获取nonce值(只有合约对象有,外部对象为0)
// GetNonce 获取nonce值(只有合约对象有,外部对象为0)
GetNonce(string) uint64
// 设置nonce值(只有合约对象有,外部对象为0)
// SetNonce 设置nonce值(只有合约对象有,外部对象为0)
SetNonce(string, uint64)
// 获取指定地址合约的代码哈希
// GetCodeHash 获取指定地址合约的代码哈希
GetCodeHash(string) common.Hash
// 获取指定地址合约代码
// GetCode 获取指定地址合约代码
GetCode(string) []byte
// 设置指定地址合约代码
// SetCode 设置指定地址合约代码
SetCode(string, []byte)
// 获取指定地址合约代码大小
// GetCodeSize 获取指定地址合约代码大小
GetCodeSize(string) int
// 合约Gas奖励回馈
// AddRefund 合约Gas奖励回馈
AddRefund(uint64)
// 获取合约Gas奖励
// GetRefund 获取合约Gas奖励
GetRefund() uint64
// 获取合约状态数据
// GetState 获取合约状态数据
GetState(string, common.Hash) common.Hash
// 设置合约状态数据
// SetState 设置合约状态数据
SetState(string, common.Hash, common.Hash)
// 合约自销毁
// Suicide 合约自销毁
Suicide(string) bool
// 合约是否已经销毁
// HasSuicided 合约是否已经销毁
HasSuicided(string) bool
// 判断一个合约地址是否存在(已经销毁的合约地址对象依然存在)
// Exist 判断一个合约地址是否存在(已经销毁的合约地址对象依然存在)
Exist(string) bool
// 判断一个合约地址是否为空(不包含任何代码、也没有余额的合约为空)
// Empty 判断一个合约地址是否为空(不包含任何代码、也没有余额的合约为空)
Empty(string) bool
// 回滚到制定版本(从当前版本到回滚版本之间的数据变更全部撤销)
// RevertToSnapshot 回滚到制定版本(从当前版本到回滚版本之间的数据变更全部撤销)
RevertToSnapshot(int)
// 生成一个新版本号(递增操作)
// Snapshot 生成一个新版本号(递增操作)
Snapshot() int
// 转换合约状态数据存储
// TransferStateData 转换合约状态数据存储
TransferStateData(addr string)
// 添加新的日志信息
// AddLog 添加新的日志信息
AddLog(*model.ContractLog)
// 添加sha3记录
// AddPreimage 添加sha3记录
AddPreimage(common.Hash, []byte)
// 当前账户余额是否足够转账
// CanTransfer 当前账户余额是否足够转账
CanTransfer(sender, recipient string, amount uint64) bool
// 转账交易
// Transfer 转账交易
Transfer(sender, recipient string, amount uint64) bool
}
......@@ -12,7 +12,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 数据状态变更接口
// DataChange 数据状态变更接口
// 所有的数据状态变更事件实现此接口,并且封装各自的变更数据以及回滚动作
// 在调用合约时(具体的Tx执行时),会根据操作生成对应的变更对象并缓存下来
// 如果合约执行出错,会按生成顺序的倒序,依次调用变更对象的回滚接口进行数据回滚,并同步删除变更对象缓存
......@@ -23,14 +23,15 @@ type DataChange interface {
getLog(mdb *MemoryStateDB) []*types.ReceiptLog
}
// 版本结构,包含版本号以及当前版本包含的变更对象在变更序列中的开始序号
// Snapshot 版本结构,包含版本号以及当前版本包含的变更对象在变更序列中的开始序号
type Snapshot struct {
id int
entries []DataChange
statedb *MemoryStateDB
}
func (ver *Snapshot) GetId() int {
// GetID 获取ID
func (ver *Snapshot) GetID() int {
return ver.id
}
......
......@@ -32,35 +32,39 @@ func init() {
types.RegisterDappFork(ExecutorName, "Enable", 500000)
}
// EvmType EVM类型定义
type EvmType struct {
types.ExecTypeBase
}
// NewType 新建EVM类型对象
func NewType() *EvmType {
c := &EvmType{}
c.SetChild(c)
return c
}
// GetPayload 获取消息负载结构
func (evm *EvmType) GetPayload() types.Message {
return &EVMContractAction{}
}
// ActionName 获取ActionName
func (evm EvmType) ActionName(tx *types.Transaction) string {
// 这个需要通过合约交易目标地址来判断Action
// 如果目标地址为空,或为evm的固定合约地址,则为创建合约,否则为调用合约
if strings.EqualFold(tx.To, address.ExecAddress(types.ExecName(ExecutorName))) {
return "createEvmContract"
} else {
return "callEvmContract"
}
return "unknown"
return "callEvmContract"
}
// GetTypeMap 获取类型映射
func (evm *EvmType) GetTypeMap() map[string]int32 {
return actionName
}
// GetRealToAddr 获取实际地址
func (evm EvmType) GetRealToAddr(tx *types.Transaction) string {
if string(tx.Execer) == ExecutorName {
return tx.To
......@@ -73,13 +77,14 @@ func (evm EvmType) GetRealToAddr(tx *types.Transaction) string {
return tx.To
}
// Amount 获取金额
func (evm EvmType) Amount(tx *types.Transaction) (int64, error) {
return 0, nil
}
// CreateTx 创建交易对象
func (evm EvmType) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
elog.Debug("evm.CreateTx", "action", action)
var tx *types.Transaction
if action == "CreateCall" {
var param CreateCallTx
err := json.Unmarshal(message, &param)
......@@ -87,76 +92,25 @@ func (evm EvmType) CreateTx(action string, message json.RawMessage) (*types.Tran
elog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawEvmCreateCallTx(&param)
} else {
return nil, types.ErrNotSupport
return createRawEvmCreateCallTx(&param)
}
return tx, nil
return nil, types.ErrNotSupport
}
// GetLogMap 获取日志类型映射
func (evm *EvmType) GetLogMap() map[int64]*types.LogInfo {
return logInfo
}
type EvmCheckAddrExists struct {
}
func (t *EvmCheckAddrExists) JsonToProto(message json.RawMessage) ([]byte, error) {
var req CheckEVMAddrReq
err := json.Unmarshal(message, &req)
if err != nil {
return nil, err
}
return types.Encode(&req), nil
}
func (t *EvmCheckAddrExists) ProtoToJson(reply *types.Message) (interface{}, error) {
return reply, nil
}
type EvmEstimateGas struct {
}
func (t *EvmEstimateGas) JsonToProto(message json.RawMessage) ([]byte, error) {
var req EstimateEVMGasReq
err := json.Unmarshal(message, &req)
if err != nil {
return nil, err
}
return types.Encode(&req), nil
}
func (t *EvmEstimateGas) ProtoToJson(reply *types.Message) (interface{}, error) {
return reply, nil
}
type EvmDebug struct {
}
func (t *EvmDebug) JsonToProto(message json.RawMessage) ([]byte, error) {
var req EvmDebugReq
err := json.Unmarshal(message, &req)
if err != nil {
return nil, err
}
return types.Encode(&req), nil
}
func (t *EvmDebug) ProtoToJson(reply *types.Message) (interface{}, error) {
return reply, nil
}
//different with other exector, the name is defined by parm
func CreateRawEvmCreateCallTx(parm *CreateCallTx) (*types.Transaction, error) {
func createRawEvmCreateCallTx(parm *CreateCallTx) (*types.Transaction, error) {
if parm == nil {
elog.Error("CreateRawEvmCreateCallTx", "parm", parm)
elog.Error("createRawEvmCreateCallTx", "parm", parm)
return nil, types.ErrInvalidParam
}
bCode, err := common.FromHex(parm.Code)
if err != nil {
elog.Error("CreateRawEvmCreateCallTx", "parm.Code", parm.Code)
elog.Error("createRawEvmCreateCallTx", "parm.Code", parm.Code)
return nil, err
}
......
......@@ -4,14 +4,24 @@
package types
// CreateCallTx 创建或调用合约交易结构
type CreateCallTx struct {
// Amount 金额
Amount uint64 `json:"amount"`
// Code 合约代码
Code string `json:"code"`
// GasLimit gas限制
GasLimit uint64 `json:"gasLimit"`
// GasPrice gas定价
GasPrice uint32 `json:"gasPrice"`
// Note 备注
Note string `json:"note"`
// Alias 合约别名
Alias string `json:"alias"`
// Fee 交易手续费
Fee int64 `json:"fee"`
// Name 交易名称
Name string `json:"name"`
// IsCreate 是否创建合约
IsCreate bool `json:"isCreate"`
}
......@@ -11,40 +11,39 @@ import (
)
const (
// EvmCreateAction 创建合约
EvmCreateAction = 1
// EvmCallAction 调用合约
EvmCallAction = 2
// 合约代码变更日志
// TyLogContractData 合约代码变更日志
TyLogContractData = 601
// 合约状态数据变更日志
// TyLogContractState 合约状态数据变更日志
TyLogContractState = 602
// 合约状态数据变更日志
// TyLogCallContract 合约状态数据变更日志
TyLogCallContract = 603
// 合约状态数据变更项日志
// TyLogEVMStateChangeItem 合约状态数据变更项日志
TyLogEVMStateChangeItem = 604
// 查询方法
FuncCheckAddrExists = "CheckAddrExists"
FuncEstimateGas = "EstimateGas"
FuncEvmDebug = "EvmDebug"
// 最大Gas消耗上限
// MaxGasLimit 最大Gas消耗上限
MaxGasLimit = 10000000
)
var (
// 本执行器前缀
// EvmPrefix 本执行器前缀
EvmPrefix = "user.evm."
// 本执行器名称
// ExecutorName 本执行器名称
ExecutorName = "evm"
// ExecerEvm EVM执行器名称
ExecerEvm = []byte(ExecutorName)
// UserPrefix 执行器前缀
UserPrefix = []byte(EvmPrefix)
logInfo = map[int64]*types.LogInfo{
TyLogCallContract: {reflect.TypeOf(ReceiptEVMContract{}), "LogCallContract"},
TyLogContractData: {reflect.TypeOf(EVMContractData{}), "LogContractData"},
TyLogContractState: {reflect.TypeOf(EVMContractState{}), "LogContractState"},
TyLogEVMStateChangeItem: {reflect.TypeOf(EVMStateChangeItem{}), "LogEVMStateChangeItem"},
TyLogCallContract: {Ty: reflect.TypeOf(ReceiptEVMContract{}), Name: "LogCallContract"},
TyLogContractData: {Ty: reflect.TypeOf(EVMContractData{}), Name: "LogContractData"},
TyLogContractState: {Ty: reflect.TypeOf(EVMContractState{}), Name: "LogContractState"},
TyLogEVMStateChangeItem: {Ty: reflect.TypeOf(EVMStateChangeItem{}), Name: "LogEVMStateChangeItem"},
}
)
......@@ -6,6 +6,7 @@ package commands
import "github.com/spf13/cobra"
// Cmd The command line is not used.
func Cmd() *cobra.Command {
return nil
}
......@@ -26,3 +26,8 @@ status: Create 1 -> Match 2 -> Cancel 3 -> Close 4
//1. 我的所有赌局,按照状态进行分类 (按照地址查询)
//2. 系统所有正在进行的赌局 (按照时间进行排序)
*/
//game 的状态变化:
// staus == 1 (创建,开始猜拳游戏)
// status == 2 (匹配,参与)
// status == 3 (取消)
// status == 4 (Close的情况)
......@@ -9,21 +9,25 @@ import (
gt "github.com/33cn/plugin/plugin/dapp/game/types"
)
// Exec_Create Create game
func (g *Game) Exec_Create(payload *gt.GameCreate, tx *types.Transaction, index int) (*types.Receipt, error) {
action := NewAction(g, tx, index)
return action.GameCreate(payload)
}
// Exec_Cancel Cancel game
func (g *Game) Exec_Cancel(payload *gt.GameCancel, tx *types.Transaction, index int) (*types.Receipt, error) {
action := NewAction(g, tx, index)
return action.GameCancel(payload)
}
// Exec_Close Close game
func (g *Game) Exec_Close(payload *gt.GameClose, tx *types.Transaction, index int) (*types.Receipt, error) {
action := NewAction(g, tx, index)
return action.GameClose(payload)
}
// Exec_Match Match game
func (g *Game) Exec_Match(payload *gt.GameMatch, tx *types.Transaction, index int) (*types.Receipt, error) {
action := NewAction(g, tx, index)
return action.GameMatch(payload)
......
......@@ -9,6 +9,7 @@ import (
gt "github.com/33cn/plugin/plugin/dapp/game/types"
)
// roll back local db data
func (g *Game) execDelLocal(receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
if receiptData.GetTy() != types.ExecOk {
......@@ -28,18 +29,22 @@ func (g *Game) execDelLocal(receiptData *types.ReceiptData) (*types.LocalDBSet,
return dbSet, nil
}
// ExecDelLocal_Create roll back local db data for create
func (g *Game) ExecDelLocal_Create(payload *gt.GameCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execDelLocal(receiptData)
}
// ExecDelLocal_Cancel roll back local db data for cancel
func (g *Game) ExecDelLocal_Cancel(payload *gt.GameCancel, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execDelLocal(receiptData)
}
// ExecDelLocal_Close roll back local db data for close
func (g *Game) ExecDelLocal_Close(payload *gt.GameClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execDelLocal(receiptData)
}
// ExecDelLocal_Match roll back local db data for match
func (g *Game) ExecDelLocal_Match(payload *gt.GameMatch, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execDelLocal(receiptData)
}
......@@ -9,6 +9,7 @@ import (
gt "github.com/33cn/plugin/plugin/dapp/game/types"
)
// save receiptData to local db
func (g *Game) execLocal(receiptData *types.ReceiptData) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
if receiptData.GetTy() != types.ExecOk {
......@@ -28,18 +29,22 @@ func (g *Game) execLocal(receiptData *types.ReceiptData) (*types.LocalDBSet, err
return dbSet, nil
}
// ExecLocal_Create save receiptData for create
func (g *Game) ExecLocal_Create(payload *gt.GameCreate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execLocal(receiptData)
}
// ExecLocal_Cancel save receiptData for cancel
func (g *Game) ExecLocal_Cancel(payload *gt.GameCancel, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execLocal(receiptData)
}
// ExecLocal_Close save receiptData for close
func (g *Game) ExecLocal_Close(payload *gt.GameClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execLocal(receiptData)
}
// ExecLocal_Match save receiptData for Match
func (g *Game) ExecLocal_Match(payload *gt.GameMatch, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return g.execLocal(receiptData)
}
......@@ -22,32 +22,36 @@ func init() {
ety.InitFuncList(types.ListMethod(&Game{}))
}
// Init register dapp
func Init(name string, sub []byte) {
drivers.Register(GetName(), newGame, types.GetDappFork(driverName, "Enable"))
}
// Game the game inherits all the attributes of the driverBase.
type Game struct {
drivers.DriverBase
}
func newGame() drivers.Driver {
t := &Game{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
return t
g := &Game{}
g.SetChild(g)
g.SetExecutorType(types.LoadExecutorType(driverName))
return g
}
// GetName get name
func GetName() string {
return newGame().GetName()
}
// GetDriverName get driver name
func (g *Game) GetDriverName() string {
return driverName
}
//更新索引
// update Index
func (g *Game) updateIndex(log *gt.ReceiptGame) (kvs []*types.KeyValue) {
//先保存本次Action产生的索引
// save the index generated by this action first.
kvs = append(kvs, addGameAddrIndex(log.Status, log.GameId, log.Addr, log.Index))
kvs = append(kvs, addGameStatusIndex(log.Status, log.GameId, log.Index))
if log.Status == gt.GameActionMatch {
......@@ -69,9 +73,9 @@ func (g *Game) updateIndex(log *gt.ReceiptGame) (kvs []*types.KeyValue) {
return kvs
}
//回滚索引
// rollback Index
func (g *Game) rollbackIndex(log *gt.ReceiptGame) (kvs []*types.KeyValue) {
//先删除本次Action产生的索引
kvs = append(kvs, delGameAddrIndex(log.Status, log.Addr, log.Index))
kvs = append(kvs, delGameStatusIndex(log.Status, log.Index))
......@@ -112,21 +116,21 @@ func calcGameAddrIndexPrefix(status int32, addr string) []byte {
key := fmt.Sprintf("LODB-game-addr:%d:%s:", status, addr)
return []byte(key)
}
func addGameStatusIndex(status int32, gameId string, index int64) *types.KeyValue {
func addGameStatusIndex(status int32, gameID string, index int64) *types.KeyValue {
kv := &types.KeyValue{}
kv.Key = calcGameStatusIndexKey(status, index)
record := &gt.GameRecord{
GameId: gameId,
GameId: gameID,
Index: index,
}
kv.Value = types.Encode(record)
return kv
}
func addGameAddrIndex(status int32, gameId, addr string, index int64) *types.KeyValue {
func addGameAddrIndex(status int32, gameID, addr string, index int64) *types.KeyValue {
kv := &types.KeyValue{}
kv.Key = calcGameAddrIndexKey(status, addr, index)
record := &gt.GameRecord{
GameId: gameId,
GameId: gameID,
Index: index,
}
kv.Value = types.Encode(record)
......@@ -146,19 +150,23 @@ func delGameAddrIndex(status int32, addr string, index int64) *types.KeyValue {
return kv
}
// ReplyGameList the data structure returned when querying the game list.
type ReplyGameList struct {
Games []*Game `json:"games"`
}
// ReplyGame the data structure returned when querying a single game.
type ReplyGame struct {
Game *Game `json:"game"`
}
func (c *Game) GetPayloadValue() types.Message {
// GetPayloadValue get payload value
func (g *Game) GetPayloadValue() types.Message {
return &gt.GameAction{}
}
func (c *Game) GetTypeMap() map[string]int32 {
// GetTypeMap get TypeMap
func (g *Game) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": gt.GameActionCreate,
"Match": gt.GameActionMatch,
......
This diff is collapsed.
......@@ -9,18 +9,22 @@ import (
gt "github.com/33cn/plugin/plugin/dapp/game/types"
)
// Query_QueryGameListByIds query game list by gameIDs
func (g *Game) Query_QueryGameListByIds(in *gt.QueryGameInfos) (types.Message, error) {
return Infos(g.GetStateDB(), in)
return QueryGameListByIds(g.GetStateDB(), in)
}
// Query_QueryGameListCount query game count by status and addr
func (g *Game) Query_QueryGameListCount(in *gt.QueryGameListCount) (types.Message, error) {
return QueryGameListCount(g.GetStateDB(), in)
}
// Query_QueryGameListByStatusAndAddr query game list by status and addr
func (g *Game) Query_QueryGameListByStatusAndAddr(in *gt.QueryGameListByStatusAndAddr) (types.Message, error) {
return List(g.GetLocalDB(), g.GetStateDB(), in)
}
// Query_QueryGameById query game by gameID
func (g *Game) Query_QueryGameById(in *gt.QueryGameInfo) (types.Message, error) {
game, err := readGame(g.GetStateDB(), in.GetGameId())
if err != nil {
......
......@@ -26,16 +26,18 @@ var (
ExecerGame = []byte(GameX)
)
// action name
const (
Action_CreateGame = "createGame"
Action_MatchGame = "matchGame"
Action_CancelGame = "cancelGame"
Action_CloseGame = "closeGame"
ActionCreateGame = "createGame"
ActionMatchGame = "matchGame"
ActionCancelGame = "cancelGame"
ActionCloseGame = "closeGame"
)
// query func name
const (
FuncName_QueryGameListByIds = "QueryGameListByIds"
FuncName_QueryGameListCount = "QueryGameListCount"
FuncName_QueryGameListByStatusAndAddr = "QueryGameListByStatusAndAddr"
FuncName_QueryGameById = "QueryGameById"
FuncNameQueryGameListByIds = "QueryGameListByIds"
FuncNameQueryGameListCount = "QueryGameListCount"
FuncNameQueryGameListByStatusAndAddr = "QueryGameListByStatusAndAddr"
FuncNameQueryGameByID = "QueryGameById"
)
......@@ -4,15 +4,16 @@
package types
import "errors"
import "fmt"
// some errors definition
var (
ErrGameCreateAmount = errors.New("You fill in more than the maximum number of games.")
ErrGameCancleAddr = errors.New("You don't have permission to cancel someone else's game.")
ErrGameCloseAddr = errors.New("The game time has not yet expired,You don't have permission to call yet.")
ErrGameTimeOut = errors.New("The game has expired.,You don't have permission to call.")
ErrGameMatchStatus = errors.New("can't join the game, the game has matched or finished!")
ErrGameMatch = errors.New("can't join the game, You can't match the game you created!")
ErrGameCancleStatus = errors.New("can't cancle the game, the game has matched!")
ErrGameCloseStatus = errors.New("can't close the game again, the game has finished!")
ErrGameCreateAmount = fmt.Errorf("%s", "You fill in more than the maximum number of games.")
ErrGameCancleAddr = fmt.Errorf("%s", "You don't have permission to cancel someone else's game.")
ErrGameCloseAddr = fmt.Errorf("%s", "The game time has not yet expired,You don't have permission to call yet.")
ErrGameTimeOut = fmt.Errorf("%s", "The game has expired.,You don't have permission to call.")
ErrGameMatchStatus = fmt.Errorf("%s", "can't join the game, the game has matched or finished!")
ErrGameMatch = fmt.Errorf("%s", "can't join the game, You can't match the game you created!")
ErrGameCancleStatus = fmt.Errorf("%s", "can't cancle the game, the game has matched!")
ErrGameCloseStatus = fmt.Errorf("%s", "can't close the game again, the game has finished!")
)
......@@ -4,6 +4,7 @@
package types
// GamePreCreateTx pre create game,unused
type GamePreCreateTx struct {
//Secret string `json:"secret"`
//下注必须时偶数,不能时级数
......@@ -14,59 +15,23 @@ type GamePreCreateTx struct {
Fee int64 `json:"fee"`
}
// GamePreMatchTx pre match game,unused
type GamePreMatchTx struct {
GameId string `json:"gameId"`
GameID string `json:"gameID"`
Guess int32 `json:"guess"`
Fee int64 `json:"fee"`
}
// GamePreCancelTx pre cancel tx,unused
type GamePreCancelTx struct {
GameId string `json:"gameId"`
GameID string `json:"gameID"`
Fee int64 `json:"fee"`
}
// GamePreCloseTx pre close game, unused
type GamePreCloseTx struct {
GameId string `json:"gameId"`
GameID string `json:"gameID"`
Secret string `json:"secret"`
Result int32 `json:"result"`
Fee int64 `json:"fee"`
}
type GameData struct {
// 默认是由创建这局游戏的txHash作为gameId
GameId string `json:"gameId"`
// create 1 -> Match 2 -> Cancel 3 -> Close 4 Pending 5 //表示有人参与游戏,但还未打包
Status int32 `json:"status"`
// 创建时间
CreateTime int64 `json:"createTime"`
// 匹配时间(何时参与对赌)
MatchTime int64 `json:"matchTime"`
// 状态close的时间(包括cancel)
Closetime int64 `json:"closetime"`
// 赌注
Value int64 `json:"value"`
// 发起者账号地址
CreateAddress string `json:"createAddress"`
// 对赌者账号地址
MatchAddress string `json:"matchAddress"`
// hash 类型,预留字段
HashType string `json:"hashType"`
// 庄家创建游戏时,庄家自己出拳结果加密后的hash值
HashValue []byte `json:"hashValue"`
// 用来公布庄家出拳结果的私钥
Secret string `json:"secret"`
// 1平局,2 庄家获胜,3 matcher获胜,4 庄家开奖超时,matcher获胜,并获得本局所有赌资
Result int32 `json:"result"`
// matcher 出拳结果
MatcherGuess int32 `json:"matcherGuess"`
// create txHash
CreateTxHash string `json:"createTxHash"`
// matche交易hash
MatchTxHash string `json:"matchTxHash"`
// close txhash
CloseTxHash string `json:"closeTxHash"`
// cancel txhash
CancelTxHash string `json:"cancelTxHash"`
CreatorGuess int32 `json:"creatorGuess"`
Index int64 `json:"index"`
}
......@@ -30,18 +30,20 @@ func getRealExecName(paraName string) string {
return types.ExecName(paraName + GameX)
}
// NewType new type
func NewType() *GameType {
c := &GameType{}
c.SetChild(c)
return c
}
// exec
// GameType execType
type GameType struct {
types.ExecTypeBase
}
func (at *GameType) GetLogMap() map[int64]*types.LogInfo {
// GetLogMap get log
func (gt *GameType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
TyLogCreateGame: {reflect.TypeOf(ReceiptGame{}), "LogLotteryCreate"},
TyLogCancleGame: {reflect.TypeOf(ReceiptGame{}), "LogCancleGame"},
......@@ -50,11 +52,13 @@ func (at *GameType) GetLogMap() map[int64]*types.LogInfo {
}
}
func (g *GameType) GetPayload() types.Message {
// GetPayload get payload
func (gt *GameType) GetPayload() types.Message {
return &GameAction{}
}
func (g *GameType) GetTypeMap() map[string]int32 {
// GetTypeMap get typeMap
func (gt *GameType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": GameActionCreate,
"Cancel": GameActionCancel,
......@@ -63,11 +67,10 @@ func (g *GameType) GetTypeMap() map[string]int32 {
}
}
// TODO createTx接口暂时没法用,作为一个预留接口
func (game GameType) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
// CreateTx unused,just empty implementation
func (gt GameType) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
tlog.Debug("Game.CreateTx", "action", action)
var tx *types.Transaction
if action == Action_CreateGame {
if action == ActionCreateGame {
var param GamePreCreateTx
err := json.Unmarshal(message, &param)
if err != nil {
......@@ -76,7 +79,7 @@ func (game GameType) CreateTx(action string, message json.RawMessage) (*types.Tr
}
return CreateRawGamePreCreateTx(&param)
} else if action == Action_MatchGame {
} else if action == ActionMatchGame {
var param GamePreMatchTx
err := json.Unmarshal(message, &param)
if err != nil {
......@@ -85,7 +88,7 @@ func (game GameType) CreateTx(action string, message json.RawMessage) (*types.Tr
}
return CreateRawGamePreMatchTx(&param)
} else if action == Action_CancelGame {
} else if action == ActionCancelGame {
var param GamePreCancelTx
err := json.Unmarshal(message, &param)
if err != nil {
......@@ -94,7 +97,7 @@ func (game GameType) CreateTx(action string, message json.RawMessage) (*types.Tr
}
return CreateRawGamePreCancelTx(&param)
} else if action == Action_CloseGame {
} else if action == ActionCloseGame {
var param GamePreCloseTx
err := json.Unmarshal(message, &param)
if err != nil {
......@@ -103,13 +106,11 @@ func (game GameType) CreateTx(action string, message json.RawMessage) (*types.Tr
}
return CreateRawGamePreCloseTx(&param)
} else {
return nil, types.ErrNotSupport
}
return tx, nil
return nil, types.ErrNotSupport
}
// CreateRawGamePreCreateTx unused,just empty implementation
func CreateRawGamePreCreateTx(parm *GamePreCreateTx) (*types.Transaction, error) {
if parm == nil {
tlog.Error("CreateRawGamePreCreateTx", "parm", parm)
......@@ -139,13 +140,14 @@ func CreateRawGamePreCreateTx(parm *GamePreCreateTx) (*types.Transaction, error)
return tx, nil
}
// CreateRawGamePreMatchTx unused,just empty implementation
func CreateRawGamePreMatchTx(parm *GamePreMatchTx) (*types.Transaction, error) {
if parm == nil {
return nil, types.ErrInvalidParam
}
v := &GameMatch{
GameId: parm.GameId,
GameId: parm.GameID,
Guess: parm.Guess,
}
game := &GameAction{
......@@ -166,12 +168,13 @@ func CreateRawGamePreMatchTx(parm *GamePreMatchTx) (*types.Transaction, error) {
return tx, nil
}
// CreateRawGamePreCancelTx unused,just empty implementation
func CreateRawGamePreCancelTx(parm *GamePreCancelTx) (*types.Transaction, error) {
if parm == nil {
return nil, types.ErrInvalidParam
}
v := &GameCancel{
GameId: parm.GameId,
GameId: parm.GameID,
}
cancel := &GameAction{
Ty: GameActionCancel,
......@@ -191,13 +194,13 @@ func CreateRawGamePreCancelTx(parm *GamePreCancelTx) (*types.Transaction, error)
return tx, nil
}
//CreateRawGamePreCloseTx
// CreateRawGamePreCloseTx unused,just empty implementation
func CreateRawGamePreCloseTx(parm *GamePreCloseTx) (*types.Transaction, error) {
if parm == nil {
return nil, types.ErrInvalidParam
}
v := &GameClose{
GameId: parm.GameId,
GameId: parm.GameID,
Secret: parm.Secret,
}
close := &GameAction{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment