长安链源码学习-智能合约 (八)

智能合约包括系统合约、业务合约,这节将阐述长安链合约是如何分类的,以及智能合约执行流程。

1. 合约分类

系统合约

1) 系统合约名称:

var ContractName_value = map[string]int32{
    "SYSTEM_CONTRACT_CHAIN_CONFIG": 0,
    "SYSTEM_CONTRACT_QUERY":        1,
    "SYSTEM_CONTRACT_CERT_MANAGE":  2,
    "SYSTEM_CONTRACT_GOVERNANCE":   3,
    "SYSTEM_CONTRACT_MULTI_SIGN":   4,
    "SYSTEM_CONTRACT_STATE":        5,
}

2) 系统合约支持的类型:

commonPb.TxType_QUERY_SYSTEM_CONTRACT,
commonPb.TxType_INVOKE_SYSTEM_CONTRACT,
commonPb.TxType_UPDATE_CHAIN_CONFIG:
用户合约

支持的类型:

commonPb.TxType_MANAGE_USER_CONTRACT,
commonPb.TxType_INVOKE_USER_CONTRACT,
commonPb.TxType_QUERY_USER_CONTRACT:

2. 合约执行流程

智能合约的执行在提案以及区块验证期间都会调用,用以生成读写集。

  1. txSimContext
       在节点提案过程中,会并发生成读写集。调用函数runVM(tx *commonpb.Transaction, txSimContext protocol.TxSimContext), 变量txSimContext一直贯穿着智能合约执行流程,需要优先分析。
       TxSimContext是一个接口主要实现以下方法。Get方法优先从读写集读取变量,如果不存在从数据库中进行读取。Put方法用于构造读写集map,存储在缓存。runVM函数传入的txSimContext表示本次提案的交易集合中已经生成读写集的集合。
type TxSimContext interface {
    // Get key from cache
    Get(name string, key []byte) ([]byte, error)
    // Put key into cache
    Put(name string, key []byte, value []byte) error
}
  1. 接下来分析runVM函数。
    1)判断参数tx.Header.TxType是否是上述的交易类型之一
    2)交易参数不得多于50个
    3)交易参数每个Key不得长于64个字节,Value不得长于1M
    4)运行RunContract执行智能合约,将执行结果返回

PS: runVM即使返回有err 也会直接记录提案中,并且会清空读写集。

  1. 分析RunContract函数。
    1)如果智能合约状态为Revoke,返回执行失败
    2)如果是Native合约(目前系统合约注册为Native合约),则执行调用合约框架的Invoke方法,Invoke方法将找到调用方法并执行(这里用的并不是反射,而是在合约中直接注册方法),RunContract执行结束。例如:
func (c *BlockContact) getMethod(methodName string) ContractFunc {
    return c.methods[methodName]
}

func registerBlockContactMethods(log *logger.CMLogger) map[string]ContractFunc {
    queryMethodMap := make(map[string]ContractFunc, 64)
    blockRuntime := &BlockRuntime{log: log}
    queryMethodMap[commonPb.QueryFunction_GET_BLOCK_BY_HEIGHT.String()] = blockRuntime.GetBlockByHeight
    queryMethodMap[commonPb.QueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HEIGHT.String()] = blockRuntime.GetBlockWithTxRWSetsByHeight
    queryMethodMap[commonPb.QueryFunction_GET_BLOCK_BY_HASH.String()] = blockRuntime.GetBlockByHash
    queryMethodMap[commonPb.QueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HASH.String()] = blockRuntime.GetBlockWithTxRWSetsByHash
    queryMethodMap[commonPb.QueryFunction_GET_BLOCK_BY_TX_ID.String()] = blockRuntime.GetBlockByTxId
    queryMethodMap[commonPb.QueryFunction_GET_TX_BY_TX_ID.String()] = blockRuntime.GetTxByTxId
    queryMethodMap[commonPb.QueryFunction_GET_LAST_CONFIG_BLOCK.String()] = blockRuntime.GetLastConfigBlock
    queryMethodMap[commonPb.QueryFunction_GET_LAST_BLOCK.String()] = blockRuntime.GetLastBlock
    queryMethodMap[commonPb.QueryFunction_GET_CHAIN_INFO.String()] = blockRuntime.GetChainInfo
    queryMethodMap[commonPb.QueryFunction_GET_NODE_CHAIN_LIST.String()] = blockRuntime.GetNodeChainList
    return queryMethodMap
}

3)如果是用户合约,则判断该合约是否已经冻结,如果冻结则返回。判断合约版本是否存在,不存在则返回。获取合约类型(native、wasmer、wxvm、gasm、evm等)。逻辑在runUserContract函数。
4)如果执行的方法是init合约、update合约,则存储合约字节码、合约版本、合约类型等字段。如果是冻结、解冻合约、Revoke合约,则执行设置合约状态,并返回。逻辑在runUserContract函数。
5)如果不是第四步的方法,则调用invokeUserContractByRuntime执行合约方法。

  1. 分析invokeUserContractByRuntime函数
    1)在执行智能合约方法前,先植入系统参数parameters:包括交易发送者、合约创建者、txid、区块高度,此处可以进行扩展,填补参数。
if senderMember, err := m.AccessControl.NewMemberFromProto(sender); err != nil {
        contractResult.Message = fmt.Sprintf("failed to unmarshal sender %q", runtimeType)
        return contractResult, commonPb.TxStatusCode_UNMARSHAL_SENDER_FAILED
    } else {
        parameters[protocol.ContractSenderOrgIdParam] = senderMember.GetOrgId()
        parameters[protocol.ContractSenderRoleParam] = string(senderMember.GetRole()[0])
        parameters[protocol.ContractSenderPkParam] = hex.EncodeToString(senderMember.GetSKI())
    }

    // Get three items in the certificate: orgid PK role
    if creatorMember, err := m.AccessControl.NewMemberFromProto(creator); err != nil {
        contractResult.Message = fmt.Sprintf("failed to unmarshal creator %q", creator)
        return contractResult, commonPb.TxStatusCode_UNMARSHAL_CREATOR_FAILED
    } else {
        parameters[protocol.ContractCreatorOrgIdParam] = creator.OrgId
        parameters[protocol.ContractCreatorRoleParam] = string(creatorMember.GetRole()[0])
        parameters[protocol.ContractCreatorPkParam] = hex.EncodeToString(creatorMember.GetSKI())
    }

    parameters[protocol.ContractTxIdParam] = txId
    parameters[protocol.ContractBlockHeightParam] = strconv.FormatInt(txContext.GetBlockHeight(), 10)

2)调用虚拟机的runtimeInstance.Invoke方法,不同的虚拟机执行引擎都将要实现Invoke方法,从Invoke方法为分界线,Invoke方法后都属于虚拟机执行引擎的范畴,后面章节将以gasm为例,分析虚拟机执行原理。

结尾思考:

用户交易类型中包含TxType_MANAGE_USER_CONTRACT类型,该类型包括合约冻结、解冻、revoke等,不在智能合约中执行,属于合约管理动作。目前该管理动作放在invokeUserContractByRuntime流程中散落执行,是否可以抽象成一个系统合约,合约的管理动作由这个系统合约进行处理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容