Skip to content

Commit

Permalink
add evm EventWitness system contract (#1396)
Browse files Browse the repository at this point in the history
* ttt

* add evm EventWitness system contract

* add license

* use merkle leaf hash scheme in EventWitness.sol

* update solc output

* expose jsonrpc api
  • Loading branch information
laizy authored Mar 24, 2022
1 parent 67f36a3 commit 3b47282
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 9 deletions.
26 changes: 22 additions & 4 deletions core/store/ledgerstore/ledger_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import (
"github.com/ontio/ontology/smartcontract/event"
"github.com/ontio/ontology/smartcontract/service/evm"
types4 "github.com/ontio/ontology/smartcontract/service/evm/types"
"github.com/ontio/ontology/smartcontract/service/evm/witness"
"github.com/ontio/ontology/smartcontract/service/native/ong"
"github.com/ontio/ontology/smartcontract/service/native/utils"
"github.com/ontio/ontology/smartcontract/service/neovm"
Expand Down Expand Up @@ -743,6 +744,7 @@ func (this *LedgerStoreImp) saveBlockToBlockStore(block *types.Block) error {

func (this *LedgerStoreImp) executeBlock(block *types.Block) (result store.ExecuteResult, err error) {
overlay := this.stateStore.NewOverlayDB()
var evmWitness common2.Address
if block.Header.Height != 0 {
config := &smartcontract.Config{
Time: block.Header.Timestamp,
Expand All @@ -754,6 +756,7 @@ func (this *LedgerStoreImp) executeBlock(block *types.Block) (result store.Execu
if err != nil {
return
}
evmWitness = getEvmSystemWitnessAddress(config, storage.NewCacheDB(this.stateStore.NewOverlayDB()), this)
}
gasTable := make(map[string]uint64)
neovm.GAS_TABLE.Range(func(k, value interface{}) bool {
Expand All @@ -766,7 +769,7 @@ func (this *LedgerStoreImp) executeBlock(block *types.Block) (result store.Execu
cache := storage.NewCacheDB(overlay)
for i, tx := range block.Transactions {
cache.Reset()
notify, crossStateHashes, e := this.handleTransaction(overlay, cache, gasTable, block, tx, uint32(i))
notify, crossStateHashes, e := this.handleTransaction(overlay, cache, gasTable, block, tx, uint32(i), evmWitness)
if e != nil {
err = e
return
Expand Down Expand Up @@ -1023,7 +1026,7 @@ func (this *LedgerStoreImp) saveBlock(block *types.Block, ccMsg *types.CrossChai
}

func (this *LedgerStoreImp) handleTransaction(overlay *overlaydb.OverlayDB, cache *storage.CacheDB, gasTable map[string]uint64,
block *types.Block, tx *types.Transaction, txIndex uint32) (*event.ExecuteNotify, []common.Uint256, error) {
block *types.Block, tx *types.Transaction, txIndex uint32, evmWitness common2.Address) (*event.ExecuteNotify, []common.Uint256, error) {
txHash := tx.Hash()
notify := &event.ExecuteNotify{TxHash: txHash, State: event.CONTRACT_STATE_FAIL, TxIndex: txIndex}
var crossStateHashes []common.Uint256
Expand Down Expand Up @@ -1057,13 +1060,24 @@ func (this *LedgerStoreImp) handleTransaction(overlay *overlaydb.OverlayDB, cach
Height: block.Header.Height,
Timestamp: block.Header.Timestamp,
}
_, err = this.stateStore.HandleEIP155Transaction(this, cache, eiptx, ctx, notify, true)
_, receipt, err := this.stateStore.HandleEIP155Transaction(this, cache, eiptx, ctx, notify, true)
if overlay.Error() != nil {
return nil, nil, fmt.Errorf("HandleInvokeTransaction tx %s error %s", txHash.ToHexString(), overlay.Error())
}
if err != nil {
log.Debugf("HandleInvokeTransaction tx %s error %s", txHash.ToHexString(), err)
}
for _, log := range receipt.Logs {
if log.Address != evmWitness {
continue
}
event, err := witness.DecodeEventWitness(log)
if err != nil {
continue
}

crossStateHashes = append(crossStateHashes, event.Hash)
}
}
return notify, crossStateHashes, nil
}
Expand Down Expand Up @@ -1122,6 +1136,10 @@ func (this *LedgerStoreImp) GetBlockRootWithNewTxRoots(startHeight uint32, txRoo
return this.stateStore.GetBlockRootWithNewTxRoots(needs)
}

func (this *LedgerStoreImp) GetCrossStates(height uint32) ([]common.Uint256, error) {
return this.stateStore.GetCrossStates(height)
}

func (this *LedgerStoreImp) GetCrossStatesRoot(height uint32) (common.Uint256, error) {
return this.stateStore.GetCrossStatesRoot(height)
}
Expand Down Expand Up @@ -1265,7 +1283,7 @@ func (this *LedgerStoreImp) PreExecuteEIP155(tx *types3.Transaction, ctx Eip155C
cache := storage.NewCacheDB(overlay)

notify := &event.ExecuteNotify{State: event.CONTRACT_STATE_FAIL, TxIndex: ctx.TxIndex}
result, err := this.stateStore.HandleEIP155Transaction(this, cache, tx, ctx, notify, false)
result, _, err := this.stateStore.HandleEIP155Transaction(this, cache, tx, ctx, notify, false)
return result, notify, err
}

Expand Down
40 changes: 36 additions & 4 deletions core/store/ledgerstore/tx_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/ontio/ontology/smartcontract/event"
evm2 "github.com/ontio/ontology/smartcontract/service/evm"
types3 "github.com/ontio/ontology/smartcontract/service/evm/types"
"github.com/ontio/ontology/smartcontract/service/evm/witness"
"github.com/ontio/ontology/smartcontract/service/native/global_params"
ninit "github.com/ontio/ontology/smartcontract/service/native/init"
"github.com/ontio/ontology/smartcontract/service/native/ong"
Expand Down Expand Up @@ -339,6 +340,37 @@ func chargeCostGas(payer common.Address, gas uint64, config *smartcontract.Confi
return sc.Notifications, nil
}

func getEvmSystemWitnessAddress(config *smartcontract.Config, cache *storage.CacheDB, store store.LedgerStore) common2.Address {
sink := common.NewZeroCopySink(nil)
utils.EncodeVarUint(sink, 1)
sink.WriteString(witness.WitnessGlobalParamKey)

sc := smartcontract.SmartContract{
Config: config,
CacheDB: cache,
Store: store,
Gas: math.MaxUint64,
}

service, _ := sc.NewNativeService()
result, err := service.NativeCall(utils.ParamContractAddress, "getGlobalParam", sink.Bytes())
if err != nil {
log.Errorf("get witness address error: %s", err)
return common2.Address{}
}
params := new(global_params.Params)
if err := params.Deserialization(common.NewZeroCopySource(result)); err != nil {
log.Errorf("deserialize global params error:%s", err)
return common2.Address{}
}
n, ps := params.GetParam(witness.WitnessGlobalParamKey)
if n != -1 && ps.Value != "" {
return common2.HexToAddress(ps.Value)
}

return common2.Address{}
}

func refreshGlobalParam(config *smartcontract.Config, cache *storage.CacheDB, store store.LedgerStore) error {
sink := common.NewZeroCopySink(nil)
utils.EncodeVarUint(sink, uint64(len(neovm.GAS_TABLE_KEYS)))
Expand Down Expand Up @@ -420,7 +452,7 @@ type Eip155Context struct {
}

func (self *StateStore) HandleEIP155Transaction(store store.LedgerStore, cache *storage.CacheDB,
tx *types2.Transaction, ctx Eip155Context, notify *event.ExecuteNotify, checkNonce bool) (*types3.ExecutionResult, error) {
tx *types2.Transaction, ctx Eip155Context, notify *event.ExecuteNotify, checkNonce bool) (*types3.ExecutionResult, *types.Receipt, error) {
usedGas := uint64(0)
config := params.GetChainConfig(sysconfig.DefConfig.P2PNode.EVMChainId)
statedb := storage.NewStateDB(cache, tx.Hash(), common2.Hash(ctx.BlockHash), ong.OngBalanceHandle{})
Expand All @@ -429,15 +461,15 @@ func (self *StateStore) HandleEIP155Transaction(store store.LedgerStore, cache *

if err != nil {
cache.SetDbErr(err)
return nil, err
return nil, nil, err
}
if err = statedb.DbErr(); err != nil {
cache.SetDbErr(err)
return nil, err
return nil, nil, err
}
receipt.TxIndex = ctx.TxIndex

*notify = *event.ExecuteNotifyFromEthReceipt(receipt)

return result, nil
return result, receipt, nil
}
1 change: 1 addition & 0 deletions core/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type LedgerStore interface {
GetEthAccount(address common2.Address) (*storage.EthAccount, error)
//cross chain states root
GetCrossStatesRoot(height uint32) (common.Uint256, error)
GetCrossStates(height uint32) ([]common.Uint256, error)
GetCrossChainMsg(height uint32) (*types.CrossChainMsg, error)
GetCrossStatesProof(height uint32, key []byte) ([]byte, error)
EnableBlockPrune(numBeforeCurr uint32)
Expand Down
4 changes: 4 additions & 0 deletions http/base/actor/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ func GetCrossChainMsg(height uint32) (*types.CrossChainMsg, error) {
return ledger.DefLedger.GetCrossChainMsg(height)
}

func GetCrossStatesLeafHashes(height uint32) ([]common.Uint256, error) {
return ledger.DefLedger.GetCrossStates(height)
}

func GetCrossStatesProof(height uint32, key []byte) ([]byte, error) {
return ledger.DefLedger.GetCrossStatesProof(height, key)
}
Expand Down
5 changes: 5 additions & 0 deletions http/base/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ type CrossStatesProof struct {
AuditPath string
}

type CrossStatesLeafHashes struct {
Height uint32
Hashes []string
}

type Transactions struct {
Version byte
Nonce uint32
Expand Down
3 changes: 2 additions & 1 deletion http/ethrpc/web3/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ontio/ontology/common/config"
)

// PublicWeb3API is the web3_ prefixed set of APIs in the Web3 JSON-RPC spec.
Expand All @@ -34,7 +35,7 @@ func NewAPI() *PublicWeb3API {

// ClientVersion returns the client version in the Web3 user agent format.
func (PublicWeb3API) ClientVersion() string {
return fmt.Sprintf("%s-%s", "Ontology", "1.0.0")
return fmt.Sprintf("%s-%s", "Ontology", config.Version)
}

// Sha3 returns the keccak-256 hash of the passed-in input.
Expand Down
20 changes: 20 additions & 0 deletions http/jsonrpc/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,26 @@ func GetCrossChainMsg(params []interface{}) map[string]interface{} {
return rpc.ResponseSuccess(bcomn.TransferCrossChainMsg(msg, header.Bookkeepers))
}

func GetCrossStatesLeafHashes(params []interface{}) map[string]interface{} {
if len(params) < 1 {
return rpc.ResponsePack(berr.INVALID_PARAMS, "")
}
height, ok := (params[0]).(float64)
if !ok {
return rpc.ResponsePack(berr.INVALID_PARAMS, "")
}
hashes, err := bactor.GetCrossStatesLeafHashes(uint32(height))
if err != nil {
log.Errorf("GetCrossStateLeafHashes error: %s", err)
return rpc.ResponsePack(berr.INTERNAL_ERROR, "")
}
var hexHashes []string
for _, v := range hashes {
hexHashes = append(hexHashes, v.ToHexString())
}
return rpc.ResponseSuccess(bcomn.CrossStatesLeafHashes{Height: uint32(height), Hashes: hexHashes})
}

//get cross chain state proof
func GetCrossStatesProof(params []interface{}) map[string]interface{} {
if len(params) < 1 {
Expand Down
1 change: 1 addition & 0 deletions http/jsonrpc/rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func StartRPCServer() error {

rpc.HandleFunc("getcrosschainmsg", GetCrossChainMsg)
rpc.HandleFunc("getcrossstatesproof", GetCrossStatesProof)
rpc.HandleFunc("getcrossstatesleafhashes", GetCrossStatesLeafHashes)

err := http.ListenAndServe(":"+strconv.Itoa(int(cfg.DefConfig.Rpc.HttpJsonPort)), nil)
if err != nil {
Expand Down
44 changes: 44 additions & 0 deletions smartcontract/service/evm/witness/EventWitness.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"abi": [
{
"type": "function",
"name": "witness",
"inputs": [
{
"internalType": "bytes",
"name": "evt",
"type": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "EventWitnessed",
"inputs": [
{
"name": "sender",
"type": "address",
"indexed": true
},
{
"name": "hash",
"type": "bytes32",
"indexed": true
}
],
"anonymous": false
}
],
"bytecode": {
"object": "0x608060405234801561001057600080fd5b50610232806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806301520d3714610030575b600080fd5b61004361003e3660046100f8565b610045565b005b60405160009061005f90829033908690869060200161016a565b6040516020818303038152906040529050600060028260405161008291906101a8565b602060405180830381855afa15801561009f573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906100c291906101e3565b604051909150819033907f79898126427c5e89fd1ee4f972f2a7555a74aa1248b7a0e1e50b8e0180be00bd90600090a350505050565b6000806020838503121561010b57600080fd5b823567ffffffffffffffff8082111561012357600080fd5b818501915085601f83011261013757600080fd5b81358181111561014657600080fd5b86602082850101111561015857600080fd5b60209290920196919550909350505050565b6001600160f81b031985168152606084901b6bffffffffffffffffffffffff1916600182015281836015830137600091016015019081529392505050565b6000825160005b818110156101c957602081860181015185830152016101af565b818111156101d8576000828501525b509190910192915050565b6000602082840312156101f557600080fd5b505191905056fea2646970667358221220261559f20ea5fce40c92f04e51feb223d0c0b5ed0f4f82e98eda6922b001bb3f64736f6c634300080a0033",
"sourceMap": "64:460:1:-:0;;;;;;;;;;;;;;;;;;;",
"linkReferences": {}
},
"deployed_bytecode": {
"object": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806301520d3714610030575b600080fd5b61004361003e3660046100f8565b610045565b005b60405160009061005f90829033908690869060200161016a565b6040516020818303038152906040529050600060028260405161008291906101a8565b602060405180830381855afa15801561009f573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906100c291906101e3565b604051909150819033907f79898126427c5e89fd1ee4f972f2a7555a74aa1248b7a0e1e50b8e0180be00bd90600090a350505050565b6000806020838503121561010b57600080fd5b823567ffffffffffffffff8082111561012357600080fd5b818501915085601f83011261013757600080fd5b81358181111561014657600080fd5b86602082850101111561015857600080fd5b60209290920196919550909350505050565b6001600160f81b031985168152606084901b6bffffffffffffffffffffffff1916600182015281836015830137600091016015019081529392505050565b6000825160005b818110156101c957602081860181015185830152016101af565b818111156101d8576000828501525b509190910192915050565b6000602082840312156101f557600080fd5b505191905056fea2646970667358221220261559f20ea5fce40c92f04e51feb223d0c0b5ed0f4f82e98eda6922b001bb3f64736f6c634300080a0033",
"sourceMap": "64:460:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;165:357;;;;;;:::i;:::-;;:::i;:::-;;;360:44;;333:24;;360:44;;333:24;;388:10;;400:3;;;;360:44;;;:::i;:::-;;;;;;;;;;;;;333:71;;414:22;439:19;446:11;439:19;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;473:42;;414:44;;-1:-1:-1;414:44:1;;488:10;;473:42;;;;;211:311;;165:357;;:::o;14:591:4:-;84:6;92;145:2;133:9;124:7;120:23;116:32;113:52;;;161:1;158;151:12;113:52;201:9;188:23;230:18;271:2;263:6;260:14;257:34;;;287:1;284;277:12;257:34;325:6;314:9;310:22;300:32;;370:7;363:4;359:2;355:13;351:27;341:55;;392:1;389;382:12;341:55;432:2;419:16;458:2;450:6;447:14;444:34;;;474:1;471;464:12;444:34;519:7;514:2;505:6;501:2;497:15;493:24;490:37;487:57;;;540:1;537;530:12;487:57;571:2;563:11;;;;;593:6;;-1:-1:-1;14:591:4;;-1:-1:-1;;;;14:591:4:o;610:474::-;-1:-1:-1;;;;;;833:26:4;;821:39;;897:2;893:15;;;-1:-1:-1;;889:53:4;885:1;876:11;;869:74;987:6;979;974:2;965:12;;952:42;803:3;1017:16;;1035:2;1013:25;1047:13;;;1013:25;610:474;-1:-1:-1;;;610:474:4:o;1089:426::-;1218:3;1256:6;1250:13;1281:1;1291:129;1305:6;1302:1;1299:13;1291:129;;;1403:4;1387:14;;;1383:25;;1377:32;1364:11;;;1357:53;1320:12;1291:129;;;1438:6;1435:1;1432:13;1429:48;;;1473:1;1464:6;1459:3;1455:16;1448:27;1429:48;-1:-1:-1;1493:16:4;;;;;1089:426;-1:-1:-1;;1089:426:4:o;1520:184::-;1590:6;1643:2;1631:9;1622:7;1618:23;1614:32;1611:52;;;1659:1;1656;1649:12;1611:52;-1:-1:-1;1682:16:4;;1520:184;-1:-1:-1;1520:184:4:o",
"linkReferences": {}
}
}
14 changes: 14 additions & 0 deletions smartcontract/service/evm/witness/EventWitness.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

contract EventWitness {
event EventWitnessed(address indexed sender, bytes32 indexed hash);

function witness(bytes calldata evt) external {
// ugly hack: append byte1(0) since we are hashing a merkle leaf. see: ontology/merkle/merkle_hasher.go
bytes memory leafData = abi.encodePacked(bytes1(0), msg.sender, evt);
bytes32 merkleLeafHash = sha256(leafData);
emit EventWitnessed(msg.sender, merkleLeafHash);
}
}

54 changes: 54 additions & 0 deletions smartcontract/service/evm/witness/witness.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (C) 2021 The Ontology Authors
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package witness

import (
"errors"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ontio/ontology/common"
"github.com/ontio/ontology/core/types"
)

const WitnessGlobalParamKey = "evm.witness" // value is the deployed hex addresss(evm form) of witness contract.

var EventWitnessedEventID = crypto.Keccak256Hash([]byte("EventWitnessed(address,bytes32)"))

type EventWitnessEvent struct {
Sender common.Address
Hash common.Uint256
}

func DecodeEventWitness(log *types.StorageLog) (*EventWitnessEvent, error) {
if len(log.Topics) != 3 {
return nil, errors.New("witness: wrong topic number")
}
if log.Topics[0] != EventWitnessedEventID {
return nil, errors.New("witness: wrong event id")
}

sender, err := common.AddressParseFromBytes(log.Topics[1][12:])
if err != nil {
return nil, err
}

return &EventWitnessEvent{
Sender: sender,
Hash: common.Uint256(log.Topics[2]),
}, nil
}

0 comments on commit 3b47282

Please sign in to comment.