Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi pretransaction support #1026

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions common/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ func GetStateHashCheckHeight(id uint32) uint32 {
return STATE_HASH_CHECK_HEIGHT[id]
}

var OPCODE_UPDATE_CHECK_HEIGHT = map[uint32]uint32{
NETWORK_ID_MAIN_NET: constants.OPCODE_HEIGHT_UPDATE_FIRST_MAINNET, //Network main
NETWORK_ID_POLARIS_NET: constants.OPCODE_HEIGHT_UPDATE_FIRST_POLARIS, //Network polaris
NETWORK_ID_SOLO_NET: 0, //Network solo
}

func GetOpcodeUpdateCheckHeight(id uint32) uint32 {
return OPCODE_UPDATE_CHECK_HEIGHT[id]
}

func GetNetworkName(id uint32) string {
name, ok := NETWORK_NAME[id]
if ok {
Expand Down
4 changes: 4 additions & 0 deletions common/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,7 @@ const (
// ledger state hash check height
const STATE_HASH_HEIGHT_MAINNET = 3000000
const STATE_HASH_HEIGHT_POLARIS = 850000

// neovm opcode update check height
const OPCODE_HEIGHT_UPDATE_FIRST_MAINNET = 6000000
const OPCODE_HEIGHT_UPDATE_FIRST_POLARIS = 2100000
28 changes: 28 additions & 0 deletions consensus/vbft/msg_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,31 @@ func TestBlockFetchRespMsgDeserialize(t *testing.T) {
}
t.Logf("BlockFetchRespMsg Serialize succ: %v\n", respmsg.BlockNumber)
}

func TestBlockSerialization(t *testing.T) {
blk, err := constructBlock()
if err != nil {
t.Errorf("constructBlock failed: %v", err)
return
}

data, err := blk.Serialize()
if err != nil {
t.Fatalf("serialize blk: %s", err)
}

blk2 := &Block{}
if err := blk2.Deserialize(data); err != nil {
t.Fatalf("deserialize blk: %s", err)
}

blk.EmptyBlock = nil
data2, err := blk.Serialize()
if err != nil {
t.Fatalf("serialize blk2: %s", err)
}
blk3 := &Block{}
if err := blk3.Deserialize(data2); err != nil {
t.Fatalf("deserialize blk2: %s", err)
}
}
2 changes: 1 addition & 1 deletion consensus/vbft/node_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func testCalcParticipantPeers(t *testing.T, n, c int) {
for _, p := range pc {
peers[p] = true
}
if len(peers) <= 2*c+1 {
if len(peers) < 2*c+1 {
t.Fatalf("peers(%d, %d, %d, %d, %d, %d): %v, %v, %v", n, c, len(peers), len(pp), len(pe), len(pc), pp, pe, pc)
}
}
33 changes: 20 additions & 13 deletions consensus/vbft/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"io"

"github.com/ontio/ontology/common"
"github.com/ontio/ontology/common/log"
"github.com/ontio/ontology/consensus/vbft/config"
"github.com/ontio/ontology/core/types"
)
Expand Down Expand Up @@ -78,6 +77,7 @@ func (blk *Block) Serialize() ([]byte, error) {
payload := common.NewZeroCopySink(nil)
payload.WriteVarBytes(sink.Bytes())

payload.WriteBool(blk.EmptyBlock != nil)
if blk.EmptyBlock != nil {
sink2 := common.NewZeroCopySink(nil)
blk.EmptyBlock.Serialization(sink2)
Expand Down Expand Up @@ -109,22 +109,29 @@ func (blk *Block) Deserialize(data []byte) error {
}

var emptyBlock *types.Block
if source.Len() > 0 {
hasEmptyBlock, irr, eof := source.NextBool()
if irr {
return fmt.Errorf("read empty-block-bool: %s", common.ErrIrregularData)
}
if eof {
return fmt.Errorf("read empty-block-bool: %s", io.ErrUnexpectedEOF)
}
if hasEmptyBlock {
buf2, _, irregular, eof := source.NextVarBytes()
if irregular == false && eof == false {
block2, err := types.BlockFromRawBytes(buf2)
if err == nil {
emptyBlock = block2
}
if irregular || eof {
return fmt.Errorf("read empty block failed: %v, %v", irregular, eof)
}
block2, err := types.BlockFromRawBytes(buf2)
if err != nil {
return fmt.Errorf("deserialize empty blk failed: %s", err)
}
emptyBlock = block2
}

var merkleRoot common.Uint256
if source.Len() > 0 {
merkleRoot, eof = source.NextHash()
if eof {
log.Errorf("Block Deserialize merkleRoot")
return io.ErrUnexpectedEOF
}
merkleRoot, eof = source.NextHash()
if eof {
return fmt.Errorf("block deserialize merkleRoot: %s", io.ErrUnexpectedEOF)
}
blk.Block = block
blk.EmptyBlock = emptyBlock
Expand Down
39 changes: 39 additions & 0 deletions http/base/rest/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,45 @@ func SendRawTransaction(cmd map[string]interface{}) map[string]interface{} {
return resp
}

// multi pre tx, [tx1, tx2,tx3]
func MultiPreTransaction(params map[string]interface{}) map[string]interface{} {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename as "PreexecuteMultiTransactions" ?

if len(params) < 1 {
return ResponsePack(berr.INVALID_PARAMS)
}
paras, ok := params["Data"].([]interface{})
if !ok || len(paras) < 1 {
return ResponsePack(berr.INVALID_PARAMS)
}
res := make([]interface{}, 0)
for _, param := range paras {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set a limit on len(paras)

txStr, ok := param.(string)
if !ok {
return ResponsePack(berr.INVALID_PARAMS)
}
raw, err := common.HexToBytes(txStr)
if err != nil {
return ResponsePack(berr.INVALID_PARAMS)
}
txn, err := types.TransactionFromRawBytes(raw)
if err != nil {
return ResponsePack(berr.INVALID_TRANSACTION)
}
hash := txn.Hash()
log.Debugf("SendRawTransaction recv %s", hash.ToHexString())
if txn.TxType == types.Invoke || txn.TxType == types.Deploy {
result, err := bactor.PreExecuteContract(txn)
if err != nil {
log.Infof("PreExec: ", err)
return ResponsePack(berr.SMARTCODE_ERROR)
}
res = append(res, result)
}
}
resp := ResponsePack(berr.SUCCESS)
resp["result"] = res
return resp
}

//get smartcontract event by height
func GetSmartCodeEventTxsByHeight(cmd map[string]interface{}) map[string]interface{} {
resp := ResponsePack(berr.SUCCESS)
Expand Down
33 changes: 33 additions & 0 deletions http/base/rpc/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,39 @@ func SendRawTransaction(params []interface{}) map[string]interface{} {
return responseSuccess(hash.ToHexString())
}

// multi pre tx, [tx1, tx2,tx3]
func MultiPreTransaction(params []interface{}) map[string]interface{} {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not reuse the above function?

if len(params) < 1 {
return responsePack(berr.INVALID_PARAMS, nil)
}
res := make([]interface{}, 0)
for _, param := range params {
txStr, ok := param.(string)
if !ok {
return responsePack(berr.INVALID_PARAMS, "")
}
raw, err := common.HexToBytes(txStr)
if err != nil {
return responsePack(berr.INVALID_PARAMS, err.Error())
}
txn, err := types.TransactionFromRawBytes(raw)
if err != nil {
return responsePack(berr.INVALID_TRANSACTION, "")
}
hash := txn.Hash()
log.Debugf("SendRawTransaction recv %s", hash.ToHexString())
if txn.TxType == types.Invoke || txn.TxType == types.Deploy {
result, err := bactor.PreExecuteContract(txn)
if err != nil {
log.Infof("PreExec: ", err)
return responsePack(berr.SMARTCODE_ERROR, err.Error())
}
res = append(res, result)
}
}
return responseSuccess(res)
}

//get node version
func GetNodeVersion(params []interface{}) map[string]interface{} {
return responseSuccess(config.Version)
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 @@ -42,6 +42,7 @@ func StartRPCServer() error {

rpc.HandleFunc("getrawtransaction", rpc.GetRawTransaction)
rpc.HandleFunc("sendrawtransaction", rpc.SendRawTransaction)
rpc.HandleFunc("multipretransaction", rpc.MultiPreTransaction)
rpc.HandleFunc("getstorage", rpc.GetStorage)
rpc.HandleFunc("getversion", rpc.GetNodeVersion)
rpc.HandleFunc("getnetworkid", rpc.GetNetworkId)
Expand Down
8 changes: 6 additions & 2 deletions http/restful/restful/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ const (
GET_VERSION = "/api/v1/version"
GET_NETWORKID = "/api/v1/networkid"

POST_RAW_TX = "/api/v1/transaction"
POST_RAW_TX = "/api/v1/transaction"
POST_MULTI_RAW_TX = "/api/v1/multitransaction"
)

//init restful server
Expand Down Expand Up @@ -158,7 +159,8 @@ func (this *restServer) registryMethod() {
}

postMethodMap := map[string]Action{
POST_RAW_TX: {name: "sendrawtransaction", handler: rest.SendRawTransaction},
POST_RAW_TX: {name: "sendrawtransaction", handler: rest.SendRawTransaction},
POST_MULTI_RAW_TX: {name: "multipretransaction", handler: rest.MultiPreTransaction},
}
this.postMap = postMethodMap
this.getMap = getMethodMap
Expand Down Expand Up @@ -220,6 +222,8 @@ func (this *restServer) getParams(r *http.Request, url string, req map[string]in
req["Hash"], req["Raw"] = getParam(r, "hash"), r.FormValue("raw")
case POST_RAW_TX:
req["PreExec"] = r.FormValue("preExec")
case POST_MULTI_RAW_TX:
req["PreExec"] = r.FormValue("preExec")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MULTI_RAW_TX only supports preExec ?

case GET_STORAGE:
req["Hash"], req["Key"] = getParam(r, "hash"), getParam(r, "key")
case GET_SMTCOCE_EVT_TXS:
Expand Down
4 changes: 2 additions & 2 deletions smartcontract/service/neovm/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func TestStructRef(t *testing.T) {
}

func TestRuntimeBase58ToAddress(t *testing.T) {
vm := neovm.NewExecutionEngine()
vm := neovm.NewExecutionEngine(0)

acc := account.NewAccount("")
addr := acc.Address
Expand All @@ -152,7 +152,7 @@ func TestRuntimeBase58ToAddress(t *testing.T) {
}

func TestRuntimeAddressToBase58(t *testing.T) {
vm := neovm.NewExecutionEngine()
vm := neovm.NewExecutionEngine(0)

acc := account.NewAccount("")
addr := acc.Address
Expand Down
3 changes: 2 additions & 1 deletion smartcontract/smart_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func (this *SmartContract) NewExecuteEngine(code []byte) (context.Engine, error)
if !this.checkContexts() {
return nil, fmt.Errorf("%s", "engine over max limit!")
}

service := &neovm.NeoVmService{
Store: this.Store,
CacheDB: this.CacheDB,
Expand All @@ -135,7 +136,7 @@ func (this *SmartContract) NewExecuteEngine(code []byte) (context.Engine, error)
Time: this.Config.Time,
Height: this.Config.Height,
BlockHash: this.Config.BlockHash,
Engine: vm.NewExecutionEngine(),
Engine: vm.NewExecutionEngine(this.Config.Height),
PreExec: this.PreExec,
}
return service, nil
Expand Down
65 changes: 65 additions & 0 deletions smartcontract/test/height_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2018 The ontology Authors
* This file is part of The ontology library.
*
* The ontology 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 ontology 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 ontology. If not, see <http://www.gnu.org/licenses/>.
*/

package test

import (
"github.com/ontio/ontology/smartcontract"
"github.com/ontio/ontology/vm/neovm"
"github.com/ontio/ontology/vm/neovm/errors"
"github.com/stretchr/testify/assert"
"testing"
)

func TestHeight(t *testing.T) {
byteCode0 := []byte{
byte(neovm.NEWMAP),
byte(neovm.PUSH0),
byte(neovm.HASKEY),
}

byteCode1 := []byte{
byte(neovm.NEWMAP),
byte(neovm.KEYS),
}

byteCode2 := []byte{
byte(neovm.NEWMAP),
byte(neovm.VALUES),
}

bytecode := [...][]byte{byteCode0, byteCode1, byteCode2}

for i := 0; i < 3; i++ {
config := &smartcontract.Config{
Time: 10,
Height: 10,
//Tx: &types.Transaction{},
}
sc := smartcontract.SmartContract{
Config: config,
Gas: 100,
CacheDB: nil,
}
engine, err := sc.NewExecuteEngine(bytecode[i])

_, err = engine.Invoke()

assert.EqualError(t, err, "[NeoVmService] vm execution error!: "+errors.ERR_NOT_SUPPORT_OPCODE.Error())
}
}
2 changes: 1 addition & 1 deletion vm/neovm/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
)

func TestHash(t *testing.T) {
engine := NewExecutionEngine()
engine := NewExecutionEngine(0)
engine.OpCode = HASH160

data := []byte{1, 2, 3, 4, 5, 6, 7, 8}
Expand Down
4 changes: 3 additions & 1 deletion vm/neovm/execution_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (
"github.com/ontio/ontology/vm/neovm/errors"
)

func NewExecutionEngine() *ExecutionEngine {
func NewExecutionEngine(BlockHeight uint32) *ExecutionEngine {
var engine ExecutionEngine
engine.EvaluationStack = NewRandAccessStack()
engine.AltStack = NewRandAccessStack()
engine.State = BREAK
engine.OpCode = 0
engine.BlockHeight = BlockHeight
return &engine
}

Expand All @@ -37,6 +38,7 @@ type ExecutionEngine struct {
State VMState
Contexts []*ExecutionContext
Context *ExecutionContext
BlockHeight uint32
OpCode OpCode
OpExec OpExec
}
Expand Down
2 changes: 1 addition & 1 deletion vm/neovm/func_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func opPickItem(e *ExecutionEngine) (VMState, error) {
PushData(e, s[i])
case *types.Map:
PushData(e, items.(*types.Map).TryGetValue(index))
case *types.ByteArray:
default:
bi, _ := index.GetBigInteger()
i := int(bi.Int64())
a, _ := items.GetByteArray()
Expand Down
Loading