diff --git a/Makefile b/Makefile index 440004d985..f66ba6917b 100644 --- a/Makefile +++ b/Makefile @@ -63,32 +63,13 @@ all-cross: ontology-cross tools-cross abi format: $(GOFMT) -w main.go -docker/payload: docker/build/bin/ontology docker/Dockerfile - @echo "Building ontology payload" - @mkdir -p $@ - @cp docker/Dockerfile $@ - @cp docker/build/bin/ontology $@ - @touch $@ - -docker/build/bin/%: Makefile - @echo "Building ontology in docker" - @mkdir -p docker/build/bin docker/build/pkg - @$(DRUN) --rm \ - -v $(abspath docker/build/bin):/go/bin \ - -v $(abspath docker/build/pkg):/go/pkg \ - -v $(GOPATH)/src:/go/src \ - -w /go/src/github.com/ontio/ontology \ - golang:1.9.5-stretch \ - $(GC) $(BUILD_NODE_PAR) -o docker/build/bin/ontology main.go - @touch $@ -docker: Makefile docker/payload docker/Dockerfile +docker: Makefile @echo "Building ontology docker" - @$(DBUILD) -t $(DOCKER_NS)/ontology docker/payload - @docker tag $(DOCKER_NS)/ontology $(DOCKER_NS)/ontology:$(DOCKER_TAG) + @$(DBUILD) --no-cache -t $(DOCKER_NS)/ontology:$(DOCKER_TAG) - < docker/Dockerfile @touch $@ clean: rm -rf *.8 *.o *.out *.6 *exe coverage - rm -rf ontology ontology-* tools docker/payload docker/build + rm -rf ontology ontology-* tools diff --git a/cmd/abi/native_abi_script/governance.json b/cmd/abi/native_abi_script/governance.json index e3b8725af9..ea5c04dd01 100644 --- a/cmd/abi/native_abi_script/governance.json +++ b/cmd/abi/native_abi_script/governance.json @@ -443,6 +443,29 @@ ], "returnType":"Bool" }, + { + "name":"setFeePercentage", + "parameters": + [ + { + "name":"PeerPubkey", + "type":"String" + }, + { + "name":"Address", + "type":"Address" + }, + { + "name":"PeerCost", + "type":"Int" + }, + { + "name":"StakeCost", + "type":"Int" + } + ], + "returnType":"Bool" + }, { "name":"withdrawFee", "parameters": @@ -556,38 +579,9 @@ } ], "returnType":"Bool" - }, - { - "name":"getPeerPool", - "parameters": - [ - ], - "returnType":"ByteArray" - }, - { - "name":"getPeerInfo", - "parameters": - [ - { - "name":"PeerPublicKey", - "type":"String" - } - ], - "returnType":"ByteArray" - }, - { - "name":"getPeerPoolByAddress", - "parameters": - [ - { - "name":"Address", - "type":"Address" - } - ], - "returnType":"ByteArray" } ], "events": [ ] -} +} \ No newline at end of file diff --git a/cmd/account.go b/cmd/account.go index fac1818216..d9aa660574 100644 --- a/cmd/account.go +++ b/cmd/account.go @@ -108,7 +108,7 @@ var schemeMap = map[string]schemeInfo{ // wait for user to choose options func chooseKeyType(reader *bufio.Reader) string { common.PrintNotice("key type") - for true { + for { tmp, _ := reader.ReadString('\n') tmp = strings.TrimSpace(tmp) _, ok := keyTypeMap[tmp] @@ -123,7 +123,7 @@ func chooseKeyType(reader *bufio.Reader) string { } func chooseScheme(reader *bufio.Reader) string { common.PrintNotice("signature-scheme") - for true { + for { tmp, _ := reader.ReadString('\n') tmp = strings.TrimSpace(tmp) @@ -139,7 +139,7 @@ func chooseScheme(reader *bufio.Reader) string { } func chooseCurve(reader *bufio.Reader) string { common.PrintNotice("curve") - for true { + for { tmp, _ := reader.ReadString('\n') tmp = strings.TrimSpace(tmp) _, ok := curveMap[tmp] @@ -217,15 +217,12 @@ func checkCurve(ctx *cli.Context, reader *bufio.Reader, t *string) string { } else { c = chooseCurve(reader) } - break case "sm2": fmt.Println("Use curve sm2p256v1 with key length of 256 bits.") c = "SM2P256V1" - break case "ed25519": fmt.Println("Use curve 25519 with key length of 256 bits.") c = "ED25519" - break default: return "" } @@ -247,15 +244,12 @@ func checkScheme(ctx *cli.Context, reader *bufio.Reader, t *string) string { } else { sch = chooseScheme(reader) } - break case "sm2": fmt.Println("Use SM3withSM2 as the signature scheme.") sch = "SM3withSM2" - break case "ed25519": fmt.Println("Use SHA512withEdDSA as the signature scheme.") sch = "SHA512withEdDSA" - break default: return "" } diff --git a/cmd/common/notice.go b/cmd/common/notice.go index f50f731fb9..1f5ac08ad0 100644 --- a/cmd/common/notice.go +++ b/cmd/common/notice.go @@ -32,7 +32,6 @@ Select a signature algorithm from the following: 3 Ed25519 [default is 1]: `) - break case "curve": fmt.Printf(` @@ -46,7 +45,6 @@ Select a curve from the following: 4 | P-521 | 521 This determines the length of the private key [default is 2]: `) - break case "signature-scheme": fmt.Printf(` @@ -63,7 +61,6 @@ Select a signature scheme from the following: 9 RIPEMD160withECDSA This can be changed later [default is 2]: `) - break default: } diff --git a/cmd/config.go b/cmd/config.go index b53b252323..0e6c1de913 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -40,10 +40,12 @@ func SetOntologyConfig(ctx *cli.Context) (*config.OntologyConfig, error) { setP2PNodeConfig(ctx, cfg.P2PNode) setRpcConfig(ctx, cfg.Rpc) setRestfulConfig(ctx, cfg.Restful) + setGraphQLConfig(ctx, cfg.GraphQL) setWebSocketConfig(ctx, cfg.Ws) if cfg.Genesis.ConsensusType == config.CONSENSUS_TYPE_SOLO { cfg.Ws.EnableHttpWs = true cfg.Restful.EnableHttpRestful = true + cfg.GraphQL.EnableGraphQL = true cfg.Consensus.EnableConsensus = true cfg.P2PNode.NetworkId = config.NETWORK_ID_SOLO_NET cfg.P2PNode.NetworkName = config.GetNetworkName(cfg.P2PNode.NetworkId) @@ -187,6 +189,12 @@ func setRestfulConfig(ctx *cli.Context, cfg *config.RestfulConfig) { cfg.HttpMaxConnections = ctx.Uint(utils.GetFlagName(utils.RestfulMaxConnsFlag)) } +func setGraphQLConfig(ctx *cli.Context, cfg *config.GraphQLConfig) { + cfg.EnableGraphQL = ctx.Bool(utils.GetFlagName(utils.GraphQLEnableFlag)) + cfg.GraphQLPort = ctx.Uint(utils.GetFlagName(utils.GraphQLPortFlag)) + cfg.MaxConnections = ctx.Uint(utils.GetFlagName(utils.GraphQLMaxConnsFlag)) +} + func setWebSocketConfig(ctx *cli.Context, cfg *config.WebSocketConfig) { cfg.EnableHttpWs = ctx.Bool(utils.GetFlagName(utils.WsEnabledFlag)) cfg.HttpWsPort = ctx.Uint(utils.GetFlagName(utils.WsPortFlag)) diff --git a/cmd/contract_cmd.go b/cmd/contract_cmd.go index 03a8d483ea..1fd76127d2 100644 --- a/cmd/contract_cmd.go +++ b/cmd/contract_cmd.go @@ -156,7 +156,7 @@ func deployContract(ctx *cli.Context) error { gasPrice = 0 } - cversion := fmt.Sprintf("%s", version) + cversion := version if ctx.IsSet(utils.GetFlagName(utils.ContractPrepareDeployFlag)) { preResult, err := utils.PrepareDeployContract(vmtype, code, name, cversion, author, email, desc) diff --git a/cmd/sig_tx_cmd.go b/cmd/sig_tx_cmd.go index b8ea22eb8c..14c6718308 100644 --- a/cmd/sig_tx_cmd.go +++ b/cmd/sig_tx_cmd.go @@ -93,6 +93,9 @@ func genMultiSigAddress(ctx *cli.Context) error { continue } data, err := hex.DecodeString(pk) + if err != nil { + return err + } pubKey, err := keypair.DeserializePublicKey(data) if err != nil { return fmt.Errorf("invalid pub key:%s", pk) @@ -141,6 +144,9 @@ func multiSigToTx(ctx *cli.Context) error { continue } data, err := hex.DecodeString(pk) + if err != nil { + return err + } pubKey, err := keypair.DeserializePublicKey(data) if err != nil { return fmt.Errorf("invalid pub key:%s", pk) diff --git a/cmd/tx_cmd.go b/cmd/tx_cmd.go index df2bb7356b..60163a6b8f 100644 --- a/cmd/tx_cmd.go +++ b/cmd/tx_cmd.go @@ -205,10 +205,10 @@ func transferTx(ctx *cli.Context) error { switch strings.ToLower(asset) { case "ont": amount = utils.ParseOnt(amountStr) - amountStr = utils.FormatOnt(amount) + // amountStr = utils.FormatOnt(amount) case "ong": amount = utils.ParseOng(amountStr) - amountStr = utils.FormatOng(amount) + // amountStr = utils.FormatOng(amount) default: return fmt.Errorf("unsupport asset:%s", asset) } @@ -277,10 +277,10 @@ func approveTx(ctx *cli.Context) error { switch strings.ToLower(asset) { case "ont": amount = utils.ParseOnt(amountStr) - amountStr = utils.FormatOnt(amount) + // amountStr = utils.FormatOnt(amount) case "ong": amount = utils.ParseOng(amountStr) - amountStr = utils.FormatOng(amount) + // amountStr = utils.FormatOng(amount) default: return fmt.Errorf("unsupport asset:%s", asset) } @@ -363,10 +363,9 @@ func transferFromTx(ctx *cli.Context) error { switch strings.ToLower(asset) { case "ont": amount = utils.ParseOnt(amountStr) - amountStr = utils.FormatOnt(amount) case "ong": amount = utils.ParseOng(amountStr) - amountStr = utils.FormatOng(amount) + // amountStr = utils.FormatOng(amount) default: return fmt.Errorf("unsupport asset:%s", asset) } @@ -425,13 +424,13 @@ func withdrawONGTx(ctx *cli.Context) error { if amount <= 0 { return fmt.Errorf("haven't unbound ong") } - amountStr = utils.FormatOng(amount) + // amountStr = utils.FormatOng(amount) } else { amount = utils.ParseOng(amountStr) if amount <= 0 { return fmt.Errorf("haven't unbound ong") } - amountStr = utils.FormatOng(amount) + // amountStr = utils.FormatOng(amount) } var payer common.Address diff --git a/cmd/usage.go b/cmd/usage.go index 62177473bb..5f3a8c896e 100644 --- a/cmd/usage.go +++ b/cmd/usage.go @@ -177,6 +177,14 @@ var AppHelpFlagGroups = []flagGroup{ utils.RestfulMaxConnsFlag, }, }, + { + Name: "GRAPHQL", + Flags: []cli.Flag{ + utils.GraphQLEnableFlag, + utils.GraphQLPortFlag, + utils.GraphQLMaxConnsFlag, + }, + }, { Name: "WEB SOCKET", Flags: []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5c90f187d9..58e2e918f6 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -82,7 +82,6 @@ var ( Usage: "Block data storage ``", Value: config.DEFAULT_DATA_DIR, } - //Consensus setting EnableConsensusFlag = cli.BoolFlag{ Name: "enable-consensus", @@ -103,7 +102,6 @@ var ( Usage: "Min gas price `` of transaction to be accepted by tx pool.", Value: config.DEFAULT_GAS_PRICE, } - //Test Mode setting EnableTestModeFlag = cli.BoolFlag{ Name: "testmode", @@ -199,7 +197,23 @@ var ( RestfulMaxConnsFlag = cli.UintFlag{ Name: "restmaxconns", Usage: "Restful server maximum connections ``", - Value: config.DEFAULT_REST_MAX_CONN, + Value: config.DEFAULT_HTTP_MAX_CONN, + } + + //GraphQL setting + GraphQLEnableFlag = cli.BoolFlag{ + Name: "graphql", + Usage: "Enable graphql api server", + } + GraphQLPortFlag = cli.UintFlag{ + Name: "graphql-port", + Usage: "GraphQL server listening port ``", + Value: config.DEFAULT_GRAPHQL_PORT, + } + GraphQLMaxConnsFlag = cli.UintFlag{ + Name: "graphql-max-connection", + Usage: "GraphQL server maximum connections ``", + Value: config.DEFAULT_HTTP_MAX_CONN, } //Account setting diff --git a/cmd/utils/ont.go b/cmd/utils/ont.go index 2aba7b5b67..cda40a90cf 100644 --- a/cmd/utils/ont.go +++ b/cmd/utils/ont.go @@ -41,7 +41,6 @@ import ( "github.com/ontio/ontology/core/types" cutils "github.com/ontio/ontology/core/utils" httpcom "github.com/ontio/ontology/http/base/common" - rpccommon "github.com/ontio/ontology/http/base/common" "github.com/ontio/ontology/smartcontract/service/native/ont" "github.com/ontio/ontology/smartcontract/service/native/utils" ) @@ -454,12 +453,12 @@ func SendRawTransactionData(txData string) (string, error) { return hexHash, nil } -func PrepareSendRawTransaction(txData string) (*rpccommon.PreExecuteResult, error) { +func PrepareSendRawTransaction(txData string) (*httpcom.PreExecuteResult, error) { data, ontErr := sendRpcRequest("sendrawtransaction", []interface{}{txData, 1}) if ontErr != nil { return nil, ontErr.Error } - preResult := &rpccommon.PreExecuteResult{} + preResult := &httpcom.PreExecuteResult{} err := json.Unmarshal(data, &preResult) if err != nil { return nil, fmt.Errorf("json.Unmarshal PreExecResult:%s error:%s", data, err) @@ -468,7 +467,7 @@ func PrepareSendRawTransaction(txData string) (*rpccommon.PreExecuteResult, erro } //GetSmartContractEvent return smart contract event execute by invoke transaction by hex string code -func GetSmartContractEvent(txHash string) (*rpccommon.ExecuteNotify, error) { +func GetSmartContractEvent(txHash string) (*httpcom.ExecuteNotify, error) { data, ontErr := sendRpcRequest("getsmartcodeevent", []interface{}{txHash}) if ontErr != nil { switch ontErr.ErrorCode { @@ -477,7 +476,7 @@ func GetSmartContractEvent(txHash string) (*rpccommon.ExecuteNotify, error) { } return nil, ontErr.Error } - notifies := &rpccommon.ExecuteNotify{} + notifies := &httpcom.ExecuteNotify{} err := json.Unmarshal(data, ¬ifies) if err != nil { return nil, fmt.Errorf("json.Unmarshal SmartContactEvent:%s error:%s", data, err) @@ -714,7 +713,7 @@ func InvokeSmartContract(signer *account.Account, tx *types.MutableTransaction) func PrepareInvokeNeoVMContract( contractAddress common.Address, params []interface{}, -) (*rpccommon.PreExecuteResult, error) { +) (*httpcom.PreExecuteResult, error) { mutable, err := httpcom.NewNeovmInvokeTransaction(0, 0, contractAddress, params) if err != nil { return nil, err @@ -729,7 +728,7 @@ func PrepareInvokeNeoVMContract( return PrepareSendRawTransaction(txData) } -func PrepareInvokeCodeNeoVMContract(code []byte) (*rpccommon.PreExecuteResult, error) { +func PrepareInvokeCodeNeoVMContract(code []byte) (*httpcom.PreExecuteResult, error) { mutable, err := httpcom.NewSmartContractTransaction(0, 0, code) if err != nil { return nil, err @@ -743,7 +742,7 @@ func PrepareInvokeCodeNeoVMContract(code []byte) (*rpccommon.PreExecuteResult, e } //prepare invoke wasm -func PrepareInvokeWasmVMContract(contractAddress common.Address, params []interface{}) (*rpccommon.PreExecuteResult, error) { +func PrepareInvokeWasmVMContract(contractAddress common.Address, params []interface{}) (*httpcom.PreExecuteResult, error) { mutable, err := cutils.NewWasmVMInvokeTransaction(0, 0, contractAddress, params) if err != nil { return nil, err diff --git a/common/common.go b/common/common.go index c8a2f4023e..7101a5fb0e 100644 --- a/common/common.go +++ b/common/common.go @@ -20,8 +20,11 @@ package common import ( "encoding/hex" + "fmt" "math/rand" "os" + + "github.com/ontio/ontology-crypto/keypair" ) // GetNonce returns random nonce @@ -55,3 +58,20 @@ func FileExisted(filename string) bool { _, err := os.Stat(filename) return err == nil || os.IsExist(err) } + +func PubKeyToHex(pub keypair.PublicKey) string { + nodeid := hex.EncodeToString(keypair.SerializePublicKey(pub)) + return nodeid +} + +func PubKeyFromHex(nodeid string) (keypair.PublicKey, error) { + pubKey, err := hex.DecodeString(nodeid) + if err != nil { + return nil, err + } + pk, err := keypair.DeserializePublicKey(pubKey) + if err != nil { + return nil, fmt.Errorf("deserialize failed: %s", err) + } + return pk, err +} diff --git a/common/config/config.go b/common/config/config.go index 4af797fe44..044ba990b3 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -60,9 +60,10 @@ const ( DEFAULT_NODE_PORT = 20338 DEFAULT_RPC_PORT = 20336 DEFAULT_RPC_LOCAL_PORT = 20337 + DEFAULT_GRAPHQL_PORT = 20333 DEFAULT_REST_PORT = 20334 DEFAULT_WS_PORT = 20335 - DEFAULT_REST_MAX_CONN = 1024 + DEFAULT_HTTP_MAX_CONN = 1024 DEFAULT_MAX_CONN_IN_BOUND = 1024 DEFAULT_MAX_CONN_OUT_BOUND = 1024 DEFAULT_MAX_CONN_IN_BOUND_FOR_SINGLE_IP = 16 @@ -648,6 +649,12 @@ type RestfulConfig struct { HttpKeyPath string } +type GraphQLConfig struct { + EnableGraphQL bool + GraphQLPort uint + MaxConnections uint +} + type WebSocketConfig struct { EnableHttpWs bool HttpWsPort uint @@ -662,6 +669,7 @@ type OntologyConfig struct { P2PNode *P2PNodeConfig Rpc *RpcConfig Restful *RestfulConfig + GraphQL *GraphQLConfig Ws *WebSocketConfig } @@ -706,6 +714,10 @@ func NewOntologyConfig() *OntologyConfig { EnableHttpRestful: true, HttpRestPort: DEFAULT_REST_PORT, }, + GraphQL: &GraphQLConfig{ + EnableGraphQL: false, + GraphQLPort: DEFAULT_GRAPHQL_PORT, + }, Ws: &WebSocketConfig{ EnableHttpWs: true, HttpWsPort: DEFAULT_WS_PORT, @@ -731,6 +743,9 @@ func (this *OntologyConfig) GetBookkeepers() ([]keypair.PublicKey, error) { pubKeys := make([]keypair.PublicKey, 0, len(bookKeepers)) for _, key := range bookKeepers { pubKey, err := hex.DecodeString(key) + if err != nil { + return nil, err + } k, err := keypair.DeserializePublicKey(pubKey) if err != nil { return nil, fmt.Errorf("Incorrectly book keepers key:%s", key) diff --git a/common/constants/constants.go b/common/constants/constants.go index 87356efbb7..18ece8c507 100644 --- a/common/constants/constants.go +++ b/common/constants/constants.go @@ -94,4 +94,4 @@ const BLOCKHEIGHT_CC_POLARIS = 13130000 //new node cost height const BLOCKHEIGHT_NEW_PEER_COST_MAINNET = 9400000 -const BLOCKHEIGHT_NEW_PEER_COST_POLARIS = 13360000 +const BLOCKHEIGHT_NEW_PEER_COST_POLARIS = 13400000 diff --git a/consensus/dbft/block_signatures.go b/consensus/dbft/block_signatures.go index 96cff06b96..21ba4001b8 100644 --- a/consensus/dbft/block_signatures.go +++ b/consensus/dbft/block_signatures.go @@ -62,6 +62,10 @@ func (self *BlockSignatures) Deserialization(source *common.ZeroCopySource) erro sig := SignaturesData{} sig.Signature, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } diff --git a/consensus/dbft/consensus_message.go b/consensus/dbft/consensus_message.go index 1833512dac..363d0e6bfc 100644 --- a/consensus/dbft/consensus_message.go +++ b/consensus/dbft/consensus_message.go @@ -98,6 +98,10 @@ func (cd *ConsensusMessageData) Deserialization(source *common.ZeroCopySource) e var eof bool var temp byte temp, eof = source.NextByte() + if eof { + return io.ErrUnexpectedEOF + } + cd.Type = ConsensusMessageType(temp) cd.ViewNumber, eof = source.NextByte() if eof { diff --git a/consensus/dbft/dbft_service.go b/consensus/dbft/dbft_service.go index 4acdd5cb02..42a0dea775 100644 --- a/consensus/dbft/dbft_service.go +++ b/consensus/dbft/dbft_service.go @@ -96,7 +96,7 @@ func NewDbftService(bkAccount *account.Account, txpool *actor.PID, p2p p2p.P2P) } func (this *DbftService) Receive(context actor.Context) { - if _, ok := context.Message().(*actorTypes.StartConsensus); this.started == false && ok == false { + if _, ok := context.Message().(*actorTypes.StartConsensus); !this.started && !ok { return } @@ -359,22 +359,18 @@ func (ds *DbftService) NewConsensusPayload(payload *p2pmsg.ConsensusPayload) { if cv, ok := message.(*ChangeView); ok { ds.ChangeViewReceived(payload, cv) } - break case PrepareRequestMsg: if pr, ok := message.(*PrepareRequest); ok { ds.PrepareRequestReceived(payload, pr) } - break case PrepareResponseMsg: if pres, ok := message.(*PrepareResponse); ok { ds.PrepareResponseReceived(payload, pres) } - break case BlockSignaturesMsg: if blockSigs, ok := message.(*BlockSignatures); ok { ds.BlockSignaturesReceived(payload, blockSigs) } - break default: log.Warn("unknown consensus message type") } diff --git a/consensus/dbft/prepare_request.go b/consensus/dbft/prepare_request.go index 28caed11f3..ec45b40ca2 100644 --- a/consensus/dbft/prepare_request.go +++ b/consensus/dbft/prepare_request.go @@ -62,9 +62,16 @@ func (pr *PrepareRequest) Deserialization(source *common.ZeroCopySource) error { } pr.Nonce = nonce pr.NextBookkeeper, eof = source.NextAddress() + if eof { + return io.ErrUnexpectedEOF + } var length uint64 length, _, irregular, eof = source.NextVarUint() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } diff --git a/consensus/vbft/block_pool.go b/consensus/vbft/block_pool.go index 1a990928b1..6a8651d295 100644 --- a/consensus/vbft/block_pool.go +++ b/consensus/vbft/block_pool.go @@ -111,9 +111,9 @@ func (pool *BlockPool) clean() { func (pool *BlockPool) getCandidateInfoLocked(blkNum uint32) *CandidateInfo { // NOTE: call this function only when pool.lock locked - if candidate, present := pool.candidateBlocks[blkNum]; !present { + if _, present := pool.candidateBlocks[blkNum]; !present { // new candiateInfo for blockNum - candidate = &CandidateInfo{ + candidate := &CandidateInfo{ Proposals: make([]*blockProposalMsg, 0), CommitMsgs: make([]*blockCommitMsg, 0), EndorseSigs: make(map[uint32][]*CandidateEndorseSigInfo), @@ -137,7 +137,7 @@ func (pool *BlockPool) newBlockProposal(msg *blockProposalMsg) error { // check dup-proposal from same proposer for _, p := range candidate.Proposals { if p.Block.getProposer() == msg.Block.getProposer() { - if bytes.Compare(p.BlockProposerSig, msg.BlockProposerSig) == 0 { + if bytes.Equal(p.BlockProposerSig, msg.BlockProposerSig) { return nil } return errDupProposal @@ -287,7 +287,6 @@ func (pool *BlockPool) addBlockEndorsementLocked(blkNum uint32, endorser uint32, } else { candidate.EndorseSigs[endorser] = []*CandidateEndorseSigInfo{eSig} } - return } // diff --git a/consensus/vbft/chain_store.go b/consensus/vbft/chain_store.go index 59fcd65d1f..c9c3a44db6 100644 --- a/consensus/vbft/chain_store.go +++ b/consensus/vbft/chain_store.go @@ -176,14 +176,12 @@ func (self *ChainStore) submitBlock(blkNum uint32) error { if blkNum == 0 { return nil } - if submitBlk, present := self.pendingBlocks[blkNum]; submitBlk != nil && submitBlk.hasSubmitted == false && present { + if submitBlk, present := self.pendingBlocks[blkNum]; submitBlk != nil && !submitBlk.hasSubmitted && present { err := self.db.SubmitBlock(submitBlk.block.Block, submitBlk.block.CrossChainMsg, *submitBlk.execResult) if err != nil { return fmt.Errorf("ledger add submitBlk (%d, %d, %d) failed: %s", blkNum, self.GetChainedBlockNum(), self.db.GetCurrentBlockHeight(), err) } - if _, present := self.pendingBlocks[blkNum-1]; present { - delete(self.pendingBlocks, blkNum-1) - } + delete(self.pendingBlocks, blkNum-1) submitBlk.hasSubmitted = true } return nil diff --git a/consensus/vbft/config/types.go b/consensus/vbft/config/types.go index 3234b35f62..51b593f818 100644 --- a/consensus/vbft/config/types.go +++ b/consensus/vbft/config/types.go @@ -19,30 +19,21 @@ package vconfig import ( - "encoding/hex" "encoding/json" "fmt" "github.com/ontio/ontology-crypto/keypair" + "github.com/ontio/ontology/common" "github.com/ontio/ontology/core/types" ) // PubkeyID returns a marshaled representation of the given public key. func PubkeyID(pub keypair.PublicKey) string { - nodeid := hex.EncodeToString(keypair.SerializePublicKey(pub)) - return nodeid + return common.PubKeyToHex(pub) } func Pubkey(nodeid string) (keypair.PublicKey, error) { - pubKey, err := hex.DecodeString(nodeid) - if err != nil { - return nil, err - } - pk, err := keypair.DeserializePublicKey(pubKey) - if err != nil { - return nil, fmt.Errorf("deserialize failed: %s", err) - } - return pk, err + return common.PubKeyFromHex(nodeid) } func VbftBlock(header *types.Header) (*VbftBlockInfo, error) { diff --git a/consensus/vbft/event_timer.go b/consensus/vbft/event_timer.go index 718906dc71..4f7a8bab23 100644 --- a/consensus/vbft/event_timer.go +++ b/consensus/vbft/event_timer.go @@ -62,7 +62,7 @@ type SendMsgEvent struct { type TimerEvent struct { evtType TimerEventType - blockNum uint32 + blockNum uint32 // peer index when evtType == EventPeerHeartbeat msg ConsensusMsg } diff --git a/consensus/vbft/msg_builder.go b/consensus/vbft/msg_builder.go index d6e210041a..27937699a7 100644 --- a/consensus/vbft/msg_builder.go +++ b/consensus/vbft/msg_builder.go @@ -21,6 +21,7 @@ package vbft import ( "encoding/json" "fmt" + "math" "time" "github.com/ontio/ontology-crypto/keypair" @@ -184,7 +185,7 @@ func (self *Server) constructHeartbeatMsg() (*peerHeartbeatMsg, error) { return msg, nil } -func (self *Server) constructBlock(blkNum uint32, prevBlkHash common.Uint256, txs []*types.Transaction, consensusPayload []byte, blocktimestamp uint32) (*types.Block, error) { +func (self *Server) constructBlock(blkNum uint32, prevBlkHash common.Uint256, txs []*types.Transaction, consensusPayload []byte, blocktimestamp uint32, empty bool) (*types.Block, error) { txHash := []common.Uint256{} for _, t := range txs { txHash = append(txHash, t.Hash()) @@ -204,9 +205,11 @@ func (self *Server) constructBlock(blkNum uint32, prevBlkHash common.Uint256, tx BlockRoot: blockRoot, Timestamp: blocktimestamp, Height: blkNum, - ConsensusData: common.GetNonce(), ConsensusPayload: consensusPayload, } + if !empty { + blkHeader.ConsensusData = common.GetNonce() + } blk := &types.Block{ Header: blkHeader, Transactions: txs, @@ -268,6 +271,17 @@ func (self *Server) constructProposalMsg(blkNum uint32, sysTxs, userTxs []*types if chainconfig != nil { lastConfigBlkNum = blkNum } + + vbftBlkInfoEmpty := &vconfig.VbftBlockInfo{ + Proposer: math.MaxUint32, + LastConfigBlockNum: lastConfigBlkNum, + NewChainConfig: chainconfig, + } + consensusPayloadEmpty, err := json.Marshal(vbftBlkInfoEmpty) + if err != nil { + return nil, err + } + vbftBlkInfo := &vconfig.VbftBlockInfo{ Proposer: self.Index, VrfValue: vrfValue, @@ -280,11 +294,11 @@ func (self *Server) constructProposalMsg(blkNum uint32, sysTxs, userTxs []*types return nil, err } - emptyBlk, err := self.constructBlock(blkNum, prevBlkHash, sysTxs, consensusPayload, blocktimestamp) + emptyBlk, err := self.constructBlock(blkNum, prevBlkHash, sysTxs, consensusPayloadEmpty, prevBlk.Block.Header.Timestamp+1, true) if err != nil { return nil, fmt.Errorf("failed to construct empty block: %s", err) } - blk, err := self.constructBlock(blkNum, prevBlkHash, append(sysTxs, userTxs...), consensusPayload, blocktimestamp) + blk, err := self.constructBlock(blkNum, prevBlkHash, append(sysTxs, userTxs...), consensusPayload, blocktimestamp, false) if err != nil { return nil, fmt.Errorf("failed to constuct blk: %s", err) } diff --git a/consensus/vbft/node_sync.go b/consensus/vbft/node_sync.go index ec9b7de690..fc739bad5e 100644 --- a/consensus/vbft/node_sync.go +++ b/consensus/vbft/node_sync.go @@ -153,9 +153,9 @@ func (self *Syncer) run() { // report err p.msgC <- nil } - } else { - // report error - } + } // else { + // // report error + // } case blkMsgFromPeer := <-self.blockFromPeerC: blkNum := blkMsgFromPeer.block.getBlockNum() @@ -312,12 +312,7 @@ func (self *Syncer) onNewBlockSyncReq(req *BlockSyncReq) { self.nextReqBlkNum = req.startBlockNum } self.targetBlkNum = req.targetBlockNum - peers := req.targetPeers - if len(peers) == 0 { - for p := range self.peers { - peers = append(peers, p) - } - } + // } for _, peerIdx := range req.targetPeers { if p, present := self.peers[peerIdx]; !present || !p.active { @@ -434,7 +429,7 @@ func (self *PeerSyncer) requestBlock(blkNum uint32) (*Block, error) { case BlockFetchRespMessage: pMsg, ok := msg.(*BlockFetchRespMsg) if !ok { - // log error + return nil, fmt.Errorf("expect request type: BlockFetchMessage") } return pMsg.BlockData, nil } @@ -465,7 +460,7 @@ func (self *PeerSyncer) requestBlockInfo(startBlkNum uint32) ([]*BlockInfo_, err case BlockInfoFetchRespMessage: pMsg, ok := msg.(*BlockInfoFetchRespMsg) if !ok { - // log error + return nil, fmt.Errorf("expect request type: BlockInfoFetchRespMessage") } return pMsg.Blocks, nil } diff --git a/consensus/vbft/service.go b/consensus/vbft/service.go index 089de9d072..628f5c7118 100644 --- a/consensus/vbft/service.go +++ b/consensus/vbft/service.go @@ -485,8 +485,8 @@ func (self *Server) initialize() error { go self.msgSendLoop() go self.timerLoop() go self.actionLoop() + self.quitWg.Add(1) go func() { - self.quitWg.Add(1) defer self.quitWg.Done() for { @@ -1226,9 +1226,9 @@ func (self *Server) processMsgEvent() error { if msgBlkNum == self.GetCurrentBlockNo() { // add proposal to block-pool if err := self.blockPool.newBlockProposal(pMsg); err != nil { - if err == errDupProposal { - // TODO: faulty proposer detected - } + // if err == errDupProposal { + // // TODO: faulty proposer detected + // } log.Errorf("failed to add block proposal (%d): %s", msgBlkNum, err) return nil } @@ -1263,13 +1263,13 @@ func (self *Server) processMsgEvent() error { } // makeProposalTimeout handles non-leader proposals } - } else { - // process new proposal when - // 1. we have endorsed for current BlockNum - // 2. proposal is from next potential-leader + } // else { + // // process new proposal when + // // 1. we have endorsed for current BlockNum + // // 2. proposal is from next potential-leader - // TODO - } + // // TODO + // } case BlockEndorseMessage: pMsg := msg.(*blockEndorseMsg) @@ -1314,12 +1314,12 @@ func (self *Server) processMsgEvent() error { return nil } } - } else { - // wait until endorse timeout - } - } else { - // makeEndorsementTimeout handles non-endorser endorsements - } + } // else { + // // wait until endorse timeout + // } + } // else { + // // makeEndorsementTimeout handles non-endorser endorsements + // } if self.blockPool.endorseFailed(msgBlkNum, self.GetChainConfig().C) { // endorse failed, start empty endorsing self.timer.C <- &TimerEvent{ @@ -1327,11 +1327,11 @@ func (self *Server) processMsgEvent() error { blockNum: msgBlkNum, } } - } else { - // process new endorsement when - // 1. we have committed for current BlockNum - // 2. endorsed proposal is from next potential-leader - } + } // else { + // // process new endorsement when + // // 1. we have committed for current BlockNum + // // 2. endorsed proposal is from next potential-leader + // } case BlockCommitMessage: pMsg := msg.(*blockCommitMsg) @@ -1376,15 +1376,15 @@ func (self *Server) processMsgEvent() error { if err := self.makeSealed(proposal, forEmpty); err != nil { log.Errorf("failed to seal block %d, err: %s", msgBlkNum, err) } - } else { - // wait commit timeout, nothing to do - } + } // else { + // // wait commit timeout, nothing to do + // } - } else { - // nothing to do besides adding to msg pool + } // else { + // // nothing to do besides adding to msg pool - // FIXME: add msg from msg-pool to block-pool when starting new block-round - } + // // FIXME: add msg from msg-pool to block-pool when starting new block-round + // } } case <-self.quitC: @@ -2212,8 +2212,7 @@ func (self *Server) makeProposal(blkNum uint32, forEmpty bool) error { userTxs := make([]*types.Transaction, 0) //check need upate chainconfig - cfg := &vconfig.ChainConfig{} - cfg = nil + var cfg *vconfig.ChainConfig if self.checkNeedUpdateChainConfig(blkNum) || self.checkUpdateChainConfig(blkNum) { chainconfig, err := getChainConfig(self.blockPool.getExecWriteSet(blkNum-1), blkNum) if err != nil { diff --git a/consensus/vbft/state_mgmt.go b/consensus/vbft/state_mgmt.go index cf770f3c3d..a0caf4a63e 100644 --- a/consensus/vbft/state_mgmt.go +++ b/consensus/vbft/state_mgmt.go @@ -385,41 +385,48 @@ func (self *StateMgr) checkStartSyncing(startBlkNum uint32, forceSync bool) { // non-consensus node, block-syncer do the syncing return } + var maxCommitted uint32 - peers := make(map[uint32][]uint32) for _, p := range self.peers { n := p.committedBlockNum - if n > startBlkNum { - if _, present := peers[n]; !present { - peers[n] = make([]uint32, 0) - } - for k := range peers { - if n >= k { - peers[k] = append(peers[k], p.peerIdx) + if n > startBlkNum && n > maxCommitted { + peerCount := 0 + for _, k := range self.peers { + if k.committedBlockNum >= n { + peerCount++ } } - if len(peers[n]) > int(self.server.GetChainConfig().C) { + if peerCount > int(self.server.GetChainConfig().C) { maxCommitted = n } } } + var maxCommittedPeers []uint32 + if maxCommitted > 0 { + for _, k := range self.peers { + if k.committedBlockNum >= maxCommitted { + maxCommittedPeers = append(maxCommittedPeers, k.peerIdx) + } + } + } + if maxCommitted > startBlkNum || forceSync { self.setState(Syncing) startBlkNum = self.server.GetCommittedBlockNo() + 1 if maxCommitted > self.server.syncer.getCurrentTargetBlockNum() { // syncer is much slower than peer-update, too much SyncReq can make channel full - log.Infof("server %d, start syncing %d - %d, with %v", self.server.Index, startBlkNum, maxCommitted, peers) + log.Infof("server %d, start syncing %d - %d, with %v, %v", self.server.Index, startBlkNum, maxCommitted, maxCommittedPeers, self.peers) self.lastBlockSyncReqHeight = maxCommitted self.server.syncer.blockSyncReqC <- &BlockSyncReq{ - targetPeers: peers[maxCommitted], + targetPeers: maxCommittedPeers, startBlockNum: startBlkNum, targetBlockNum: maxCommitted, } } } else if self.getState() == Synced { - log.Infof("server %d, start syncing check %v, %d", self.server.Index, peers, self.server.GetCurrentBlockNo()) + log.Infof("server %d, start syncing check %v, %v %d", self.server.Index, maxCommittedPeers, self.peers, self.server.GetCurrentBlockNo()) self.setState(SyncingCheck) } } @@ -431,20 +438,21 @@ func (self *StateMgr) getConsensusedCommittedBlockNum() (uint32, bool) { consensused := false var maxCommitted uint32 myCommitted := self.server.GetCommittedBlockNo() - peers := make(map[uint32][]uint32) + for _, p := range self.peers { n := p.committedBlockNum - if n >= myCommitted { - if _, present := peers[n]; !present { - peers[n] = make([]uint32, 0) - } - for k := range peers { - if n >= k { - peers[k] = append(peers[k], p.peerIdx) + if n >= myCommitted && n > maxCommitted { + + peerCount := 0 + for _, k := range self.peers { + if k.committedBlockNum >= n { + peerCount++ } } - if len(peers[n]) > C { + if peerCount > C { + maxCommitted = n + consensused = true } } diff --git a/consensus/vbft/state_mgmt_test.go b/consensus/vbft/state_mgmt_test.go index 1d0750e071..1c49943085 100644 --- a/consensus/vbft/state_mgmt_test.go +++ b/consensus/vbft/state_mgmt_test.go @@ -233,6 +233,60 @@ func TestStateMgr_getConsensusedCommittedBlockNum(t *testing.T) { t.Logf("TestgetConsensusedCommittedBlockNum maxcommitted:%v, consensused:%v", maxcomit, flag) } +func TestStateMgr_getConsensusedCommittedBlockNum_contrived(t *testing.T) { + + f := func() (uint32, bool) { + C := 3 + + consensused := false + var maxCommitted uint32 + myCommitted := uint32(10) + peersOrdered := []*PeerState{&PeerState{ + committedBlockNum: 89, + }, &PeerState{ + committedBlockNum: 23, + }, &PeerState{ + committedBlockNum: 25, + }, &PeerState{ + committedBlockNum: 79, + }, &PeerState{ + committedBlockNum: 56, + }, &PeerState{ + committedBlockNum: 49, + }, &PeerState{ + committedBlockNum: 22, + }, &PeerState{ + committedBlockNum: 91, + }, &PeerState{ + committedBlockNum: 74, + }, &PeerState{ + committedBlockNum: 13, + }} + for _, p := range peersOrdered { + n := p.committedBlockNum + if n >= myCommitted && n > maxCommitted { + peerCount := 0 + for _, k := range peersOrdered { + if k.committedBlockNum >= n { + peerCount++ + } + } + if peerCount > C { + maxCommitted = n + consensused = true + } + } + } + + return maxCommitted, consensused + } + + maxCommitted, consensused := f() + if !(consensused && maxCommitted == 74) { + t.Fail() + } +} + func TestPeerState_String(t *testing.T) { peers := make(map[uint32]*PeerState) for i := uint32(0); i < 10; i++ { diff --git a/consensus/vbft/utils.go b/consensus/vbft/utils.go index 1d819889f5..bbcdc0ad37 100644 --- a/consensus/vbft/utils.go +++ b/consensus/vbft/utils.go @@ -146,7 +146,7 @@ func GetVbftConfigInfo(memdb *overlaydb.MemDB) (*config.VBFTConfig, error) { } } - chainconfig := new(config.VBFTConfig) + var chainconfig *config.VBFTConfig if preCfg.SetView == goveranceview.View { chainconfig = &config.VBFTConfig{ N: uint32(preCfg.Configuration.N), diff --git a/core/payload/deploy_code.go b/core/payload/deploy_code.go index baaa6fe68c..40212ec243 100644 --- a/core/payload/deploy_code.go +++ b/core/payload/deploy_code.go @@ -140,27 +140,51 @@ func (dc *DeployCode) Serialization(sink *common.ZeroCopySink) { func (dc *DeployCode) Deserialization(source *common.ZeroCopySource) error { var eof, irregular bool dc.code, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } dc.vmFlags, eof = source.NextByte() + if eof { + return io.ErrUnexpectedEOF + } + dc.Name, _, irregular, eof = source.NextString() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } dc.Version, _, irregular, eof = source.NextString() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } dc.Author, _, irregular, eof = source.NextString() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } dc.Email, _, irregular, eof = source.NextString() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } diff --git a/core/program/program.go b/core/program/program.go index 5c148e904b..8b8a2815d6 100644 --- a/core/program/program.go +++ b/core/program/program.go @@ -356,7 +356,7 @@ func GetParamInfo(program []byte) ([][]byte, error) { parser := programParser{source: common.NewZeroCopySource(program)} var signatures [][]byte - for parser.IsEOF() == false { + for !parser.IsEOF() { sig, err := parser.ReadBytes() if err != nil { return nil, err diff --git a/core/signature/signature.go b/core/signature/signature.go index 46be381364..3f60e73205 100644 --- a/core/signature/signature.go +++ b/core/signature/signature.go @@ -76,7 +76,7 @@ func VerifyMultiSignature(data []byte, keys []keypair.PublicKey, m int, sigs [][ } } - if valid == false { + if !valid { return errors.New("multi-signature verification failed") } } diff --git a/core/store/ledgerstore/ledger_store.go b/core/store/ledgerstore/ledger_store.go index b2838f5812..cac164c7b1 100644 --- a/core/store/ledgerstore/ledger_store.go +++ b/core/store/ledgerstore/ledger_store.go @@ -385,7 +385,6 @@ func (this *LedgerStoreImp) setCurrentBlock(height uint32, blockHash common.Uint defer this.lock.Unlock() this.currBlockHash = blockHash this.currBlockHeight = height - return } //GetCurrentBlock return the current block height, and block hash. diff --git a/core/store/ledgerstore/state_store.go b/core/store/ledgerstore/state_store.go index 40fa169d96..62dc053338 100644 --- a/core/store/ledgerstore/state_store.go +++ b/core/store/ledgerstore/state_store.go @@ -176,6 +176,9 @@ func (self *StateStore) GetStateMerkleRoot(height uint32) (result common.Uint256 } source := common.NewZeroCopySource(value) _, eof := source.NextHash() + if eof { + err = io.ErrUnexpectedEOF + } result, eof = source.NextHash() if eof { err = io.ErrUnexpectedEOF diff --git a/core/store/overlaydb/iterator.go b/core/store/overlaydb/iterator.go index f04325e7d8..09c5587f64 100644 --- a/core/store/overlaydb/iterator.go +++ b/core/store/overlaydb/iterator.go @@ -50,11 +50,11 @@ func NewJoinIter(memIter, backendIter common.StoreIterator) *JoinIter { func (iter *JoinIter) First() bool { f := iter.first() - if f == false { + if !f { return false } for len(iter.value) == 0 { - if iter.next() == false { + if !iter.next() { return false } } @@ -73,7 +73,7 @@ func (iter *JoinIter) first() bool { if back { bkey = iter.backend.Key() bval = iter.backend.Value() - if mem == false { + if !mem { iter.key = bkey iter.value = bval iter.keyOrigin = FromBack @@ -117,12 +117,12 @@ func (iter *JoinIter) Value() []byte { func (iter *JoinIter) Next() bool { f := iter.next() - if f == false { + if !f { return false } for len(iter.value) == 0 { - if iter.next() == false { + if !iter.next() { return false } } @@ -131,10 +131,10 @@ func (iter *JoinIter) Next() bool { } func (iter *JoinIter) next() bool { - if (iter.keyOrigin == FromMem || iter.keyOrigin == FromBoth) && iter.nextMemEnd == false { + if (iter.keyOrigin == FromMem || iter.keyOrigin == FromBoth) && !iter.nextMemEnd { iter.nextMemEnd = !iter.memdb.Next() } - if (iter.keyOrigin == FromBack || iter.keyOrigin == FromBoth) && iter.nextBackEnd == false { + if (iter.keyOrigin == FromBack || iter.keyOrigin == FromBoth) && !iter.nextBackEnd { iter.nextBackEnd = !iter.backend.Next() } diff --git a/core/store/overlaydb/memdb.go b/core/store/overlaydb/memdb.go index ed305e9afc..f2cebf7c77 100644 --- a/core/store/overlaydb/memdb.go +++ b/core/store/overlaydb/memdb.go @@ -312,7 +312,6 @@ func (p *MemDB) Put(key []byte, value []byte) { p.kvSize += len(key) + len(value) p.n++ - return } // Delete deletes the value for the given key. diff --git a/core/store/overlaydb/overlaydb.go b/core/store/overlaydb/overlaydb.go index 06f989279b..a0eceab21a 100644 --- a/core/store/overlaydb/overlaydb.go +++ b/core/store/overlaydb/overlaydb.go @@ -58,7 +58,7 @@ func (self *OverlayDB) SetError(err error) { func (self *OverlayDB) Get(key []byte) (value []byte, err error) { var unknown bool value, unknown = self.memdb.Get(key) - if unknown == false { + if !unknown { return value, nil } diff --git a/core/types/header.go b/core/types/header.go index 3f96880011..97845a5e54 100644 --- a/core/types/header.go +++ b/core/types/header.go @@ -93,6 +93,10 @@ func (self *RawHeader) deserializationUnsigned(source *common.ZeroCopySource) er source.Skip(8) // ConsensusPayload _, _, irregular, eof := source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } @@ -224,14 +228,43 @@ func (bd *Header) deserializationUnsigned(source *common.ZeroCopySource) error { var irregular, eof bool bd.Version, eof = source.NextUint32() + if eof { + return io.ErrUnexpectedEOF + } bd.PrevBlockHash, eof = source.NextHash() + if eof { + return io.ErrUnexpectedEOF + } bd.TransactionsRoot, eof = source.NextHash() + if eof { + return io.ErrUnexpectedEOF + } + bd.BlockRoot, eof = source.NextHash() + if eof { + return io.ErrUnexpectedEOF + } + bd.Timestamp, eof = source.NextUint32() + if eof { + return io.ErrUnexpectedEOF + } + bd.Height, eof = source.NextUint32() + if eof { + return io.ErrUnexpectedEOF + } + bd.ConsensusData, eof = source.NextUint64() + if eof { + return io.ErrUnexpectedEOF + } bd.ConsensusPayload, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } + if irregular { return common.ErrIrregularData } diff --git a/core/types/transaction.go b/core/types/transaction.go index d1aa28ddaf..3dc64d4641 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -47,8 +47,9 @@ type Transaction struct { Raw []byte // raw transaction data - hash common.Uint256 - SignedAddr []common.Address // this is assigned when passed signature verification + hashUnsigned common.Uint256 + hash common.Uint256 + SignedAddr []common.Address // this is assigned when passed signature verification nonDirectConstracted bool // used to check literal construction like `tx := &Transaction{...}` } @@ -78,8 +79,8 @@ func (tx *Transaction) Deserialization(source *common.ZeroCopySource) error { lenUnsigned := pos - pstart source.BackUp(lenUnsigned) rawUnsigned, _ := source.NextBytes(lenUnsigned) - temp := sha256.Sum256(rawUnsigned) - tx.hash = common.Uint256(sha256.Sum256(temp[:])) + tx.hashUnsigned = sha256.Sum256(rawUnsigned) + tx.hash = common.Uint256(sha256.Sum256(tx.hashUnsigned[:])) // tx sigs length, _, irregular, eof := source.NextVarUint() @@ -142,12 +143,27 @@ func (tx *Transaction) IntoMutable() (*MutableTransaction, error) { func (tx *Transaction) deserializationUnsigned(source *common.ZeroCopySource) error { var irregular, eof bool tx.Version, eof = source.NextByte() + if eof { + return io.ErrUnexpectedEOF + } var txtype byte txtype, eof = source.NextByte() + if eof { + return io.ErrUnexpectedEOF + } tx.TxType = TransactionType(txtype) tx.Nonce, eof = source.NextUint32() + if eof { + return io.ErrUnexpectedEOF + } tx.GasPrice, eof = source.NextUint64() + if eof { + return io.ErrUnexpectedEOF + } tx.GasLimit, eof = source.NextUint64() + if eof { + return io.ErrUnexpectedEOF + } var buf []byte buf, eof = source.NextBytes(common.ADDR_LEN) if eof { @@ -205,10 +221,16 @@ func (self *RawSig) Serialization(sink *common.ZeroCopySink) error { func (self *RawSig) Deserialization(source *common.ZeroCopySource) error { var eof, irregular bool self.Invoke, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } if irregular { return common.ErrIrregularData } self.Verify, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } if irregular { return common.ErrIrregularData } @@ -307,7 +329,7 @@ type Payload interface { } func (tx *Transaction) Serialization(sink *common.ZeroCopySink) { - if tx.nonDirectConstracted == false || len(tx.Raw) == 0 { + if !tx.nonDirectConstracted || len(tx.Raw) == 0 { panic("wrong constructed transaction") } sink.WriteBytes(tx.Raw) @@ -321,7 +343,14 @@ func (tx *Transaction) Hash() common.Uint256 { return tx.hash } -func (tx *Transaction) Verify() error { - panic("unimplemented ") - return nil +// calculate a hash for another chain to sign. +// and take the chain id of ontology as 0. +func (tx *Transaction) SigHashForChain(id uint32) common.Uint256 { + sink := common.NewZeroCopySink(nil) + sink.WriteHash(tx.hashUnsigned) + if id != 0 { + sink.WriteUint32(id) + } + + return common.Uint256(sha256.Sum256(sink.Bytes())) } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go new file mode 100644 index 0000000000..1cb830cf97 --- /dev/null +++ b/core/types/transaction_test.go @@ -0,0 +1,41 @@ +/* + * 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 . + */ + +package types + +import ( + "math" + "testing" + + "github.com/ontio/ontology/core/payload" + "github.com/stretchr/testify/assert" +) + +func TestTransaction_SigHashForChain(t *testing.T) { + mutable := &MutableTransaction{ + TxType: InvokeNeo, + Payload: &payload.InvokeCode{}, + } + + tx, err := mutable.IntoImmutable() + assert.Nil(t, err) + + assert.Equal(t, tx.Hash(), tx.SigHashForChain(0)) + assert.NotEqual(t, tx.Hash(), tx.SigHashForChain(1)) + assert.NotEqual(t, tx.Hash(), tx.SigHashForChain(math.MaxUint32)) +} diff --git a/core/validation/block_validator.go b/core/validation/block_validator.go index 210e758bc6..49155105df 100644 --- a/core/validation/block_validator.go +++ b/core/validation/block_validator.go @@ -66,11 +66,11 @@ func VerifyBlock(block *types.Block, ld *ledger.Ledger, completely bool) error { */ for _, txVerify := range block.Transactions { if errCode := VerifyTransaction(txVerify); errCode != ontErrors.ErrNoError { - return errors.New(fmt.Sprintf("VerifyTransaction failed when verifiy block")) + return errors.New("VerifyTransaction failed when verifiy block") } if errCode := VerifyTransactionWithLedger(txVerify, ld); errCode != ontErrors.ErrNoError { - return errors.New(fmt.Sprintf("VerifyTransaction failed when verifiy block")) + return errors.New("VerifyTransaction failed when verifiy block") } } } diff --git a/core/validation/transaction_validator.go b/core/validation/transaction_validator.go index e7b3b0ceee..66a39f19b7 100644 --- a/core/validation/transaction_validator.go +++ b/core/validation/transaction_validator.go @@ -98,7 +98,7 @@ func checkTransactionSignatures(tx *types.Transaction) error { } // check payer in address - if address[tx.Payer] == false { + if !address[tx.Payer] { return errors.New("signature missing for payer: " + tx.Payer.ToBase58()) } diff --git a/docker/Dockerfile b/docker/Dockerfile index 3f94ca85c5..1e4747cdac 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,9 +1,17 @@ +# 1. Stage one: build ontology +FROM golang:1.13 AS build +WORKDIR /app +RUN git clone https://github.com/ontio/ontology.git && \ + cd ontology && \ + make + +# 2. Stage two: copy compiled binary from prev builded container(referenced by name build) +FROM ubuntu:18.04 +WORKDIR /app +COPY --from=build /app/ontology/ontology ontology -FROM tianon/ubuntu-core:14.04 -ENV ONTOLOGY_PATH /var/ontology -RUN mkdir -p $ONTOLOGY_PATH -COPY ontology $ONTOLOGY_PATH -EXPOSE 20334 20335 20336 20337 20338 20339 -WORKDIR $ONTOLOGY_PATH -ENTRYPOINT ["./ontology"] +EXPOSE 20334 20335 20336 20337 20338 20339 +#NOTE! we highly recommand that you put data dir to a mounted volume, e.g. --data-dir /data/Chain +#write data to docker image is *not* a best practice +CMD ["/app/ontology"] diff --git a/errors/callstack.go b/errors/callstack.go index 7b55e58b27..0f59e69066 100644 --- a/errors/callstack.go +++ b/errors/callstack.go @@ -42,7 +42,7 @@ func GetCallStacks(err error) *CallStack { func CallStacksString(call *CallStack) string { buf := bytes.Buffer{} if call == nil { - return fmt.Sprintf("No call stack available") + return "No call stack available" } for _, stack := range call.Stacks { diff --git a/go.mod b/go.mod index 07b455ec29..db8e813165 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( github.com/blang/semver v3.5.1+incompatible github.com/emirpasic/gods v1.12.0 // indirect github.com/ethereum/go-ethereum v1.9.13 - github.com/gogo/protobuf v1.3.1 // indirect github.com/gorilla/websocket v1.4.1 github.com/gosuri/uilive v0.0.3 // indirect github.com/gosuri/uiprogress v0.0.1 + github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 github.com/hashicorp/golang-lru v0.5.3 github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c github.com/itchyny/base58-go v0.1.0 diff --git a/go.sum b/go.sum index 0e9c55686c..59d54c8936 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -101,6 +102,7 @@ github.com/gosuri/uilive v0.0.3 h1:kvo6aB3pez9Wbudij8srWo4iY6SFTTxTKOkb+uRCE8I= github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8= github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJSxw= github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 h1:E0whKxgp2ojts0FDgUA8dl62bmH0LxKanMoBr6MDTDM= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -156,6 +158,7 @@ github.com/ontio/ontology-eventbus v0.9.1 h1:nt3AXWx3gOyqtLiU4EwI92Yc4ik/pWHu9xR github.com/ontio/ontology-eventbus v0.9.1/go.mod h1:hCQIlbdPckcfykMeVUdWrqHZ8d30TBdmLfXCVWGkYhM= github.com/ontio/wagon v0.4.1 h1:3A8BxTMVGrQnyWxD1h8w5PLvN9GZMWjC75Jw+5Vgpe0= github.com/ontio/wagon v0.4.1/go.mod h1:oTPdgWT7WfPlEyzVaHSn1vQPMSbOpQPv+WphxibWlhg= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw= github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= diff --git a/http/base/common/common.go b/http/base/common/common.go index cc9683d8ff..d838bda8ab 100644 --- a/http/base/common/common.go +++ b/http/base/common/common.go @@ -54,6 +54,16 @@ type BalanceOfRsp struct { Height string `json:"height"` } +type Oep4BalanceOfRsp struct { + Oep4 []Oep4Balance `json:"oep4"` + Height string `json:"height"` +} + +type Oep4Balance struct { + Addr string `json:"addr"` + Balance string `json:"balance"` +} + type MerkleProof struct { Type string TransactionsRoot string @@ -312,6 +322,24 @@ func GetBalance(address common.Address) (*BalanceOfRsp, error) { }, nil } +func GetOep4Balance(contractAddress common.Address, addrs []common.Address) (*Oep4BalanceOfRsp, error) { + balances, height, err := GetOep4ContractBalance(contractAddress, addrs, true) + if err != nil { + return nil, fmt.Errorf("get ont balance error:%s", err) + } + res := make([]Oep4Balance, len(addrs)) + for i, addr := range addrs { + res[i] = Oep4Balance{ + Addr: addr.ToBase58(), + Balance: balances[i], + } + } + return &Oep4BalanceOfRsp{ + Oep4: res, + Height: fmt.Sprintf("%d", height), + }, nil +} + func GetGrantOng(addr common.Address) (string, error) { key := append([]byte(ont.UNBOUND_TIME_OFFSET), addr[:]...) value, err := ledger.DefLedger.GetStorageItem(utils.OntContractAddress, key) @@ -355,6 +383,7 @@ func GetContractBalance(cVersion byte, contractAddres []common.Address, accAddr if err != nil { return nil, 0, fmt.Errorf("NewNativeInvokeTransaction error:%s", err) } + tx, err := mutable.IntoImmutable() if err != nil { return nil, 0, err @@ -384,6 +413,45 @@ func GetContractBalance(cVersion byte, contractAddres []common.Address, accAddr return balances, height, nil } +func GetOep4ContractBalance(contractAddr common.Address, accAddr []common.Address, atomic bool) ([]string, uint32, error) { + txes := make([]*types.Transaction, 0, len(accAddr)) + var mutable *types.MutableTransaction + var err error + for _, userAcc := range accAddr { + mutable, err = NewNeovmInvokeTransaction(0, 0, contractAddr, []interface{}{"balanceOf", []interface{}{userAcc}}) + if err != nil { + return nil, 0, fmt.Errorf("NewNeovmInvokeTransaction error:%s", err) + } + + tx, err := mutable.IntoImmutable() + if err != nil { + return nil, 0, err + } + + txes = append(txes, tx) + } + + results, height, err := bactor.PreExecuteContractBatch(txes, atomic) + if err != nil { + return nil, 0, fmt.Errorf("PrepareInvokeContract error:%s", err) + } + balances := make([]string, 0, len(contractAddr)) + for _, result := range results { + if result.State == 0 { + return nil, 0, fmt.Errorf("prepare invoke failed") + } + data, err := hex.DecodeString(result.Result.(string)) + if err != nil { + return nil, 0, fmt.Errorf("hex.DecodeString error:%s", err) + } + + balance := common.BigIntFromNeoBytes(data) + balances = append(balances, balance.String()) + } + + return balances, height, nil +} + func GetContractAllowance(cVersion byte, contractAddr, fromAddr, toAddr common.Address) (uint64, error) { type allowanceStruct struct { From common.Address diff --git a/http/base/rpc/result.go b/http/base/rpc/result.go index 89d7e66854..b091d13383 100644 --- a/http/base/rpc/result.go +++ b/http/base/rpc/result.go @@ -22,10 +22,10 @@ import ( Err "github.com/ontio/ontology/http/base/error" ) -func responseSuccess(result interface{}) map[string]interface{} { - return responsePack(Err.SUCCESS, result) +func ResponseSuccess(result interface{}) map[string]interface{} { + return ResponsePack(Err.SUCCESS, result) } -func responsePack(errcode int64, result interface{}) map[string]interface{} { +func ResponsePack(errcode int64, result interface{}) map[string]interface{} { resp := map[string]interface{}{ "error": errcode, "desc": Err.ErrMap[errcode], diff --git a/http/base/rpc/rpc.go b/http/base/rpc/rpc.go index 491d16c5c1..f59dcb1a02 100644 --- a/http/base/rpc/rpc.go +++ b/http/base/rpc/rpc.go @@ -30,10 +30,11 @@ import ( "sync" "github.com/ontio/ontology/common/log" - "github.com/ontio/ontology/http/base/common" berr "github.com/ontio/ontology/http/base/error" ) +const MAX_REQUEST_BODY_SIZE = 1 << 20 + func init() { mainMux.m = make(map[string]func([]interface{}) map[string]interface{}) } @@ -95,7 +96,7 @@ func Handle(w http.ResponseWriter, r *http.Request) { } request := make(map[string]interface{}) defer r.Body.Close() - decoder := json.NewDecoder(io.LimitReader(r.Body, common.MAX_REQUEST_BODY_SIZE)) + decoder := json.NewDecoder(io.LimitReader(r.Body, MAX_REQUEST_BODY_SIZE)) err := decoder.Decode(&request) if err != nil { log.Error("HTTP JSON RPC Handle - json.Unmarshal: ", err) diff --git a/http/graphql/scalar.go b/http/graphql/scalar.go new file mode 100644 index 0000000000..637ec5a8ea --- /dev/null +++ b/http/graphql/scalar.go @@ -0,0 +1,171 @@ +/* + * 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 . + */ +package graphql + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/ontio/ontology/common" +) + +type Uint32 uint32 + +func (Uint32) ImplementsGraphQLType(name string) bool { + return name == "Uint32" +} + +func (t *Uint32) UnmarshalGraphQL(input interface{}) error { + switch input := input.(type) { + case uint32: + *t = Uint32(input) + return nil + case int32: + *t = Uint32(input) + return nil + case int64: + *t = Uint32(input) + return nil + default: + return fmt.Errorf("wrong type for Uint32: %T", input) + } +} + +func (t Uint32) MarshalJSON() ([]byte, error) { + return json.Marshal(uint32(t)) +} + +type Uint64 uint64 + +func (Uint64) ImplementsGraphQLType(name string) bool { + return name == "Uint64" +} + +func (t *Uint64) UnmarshalGraphQL(input interface{}) error { + switch input := input.(type) { + case uint32: + *t = Uint64(input) + case int32: + *t = Uint64(input) + case int: + *t = Uint64(input) + case uint: + *t = Uint64(input) + case uint64: + *t = Uint64(input) + case int64: + *t = Uint64(input) + case string: + val, err := strconv.ParseUint(input, 10, 64) + if err != nil { + return fmt.Errorf("wrong type for Uint64: %T", input) + } + *t = Uint64(val) + default: + return fmt.Errorf("wrong type for Uint64: %T", input) + } + return nil +} + +func (t Uint64) MarshalJSON() ([]byte, error) { + return json.Marshal(strconv.FormatUint(uint64(t), 10)) +} + +type Addr struct { + common.Address +} + +func (Addr) ImplementsGraphQLType(name string) bool { + return name == "Address" +} + +func (t *Addr) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + if strings.HasPrefix(input, "0x") { + t.Address, err = common.AddressFromHexString(input[2:]) + } + + if err == nil { + t.Address, err = common.AddressFromBase58(input) + } + default: + return fmt.Errorf("wrong type for Address: %T", input) + } + return err +} + +func (t Addr) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Address.ToBase58()) +} + +type H256 common.Uint256 + +func (H256) ImplementsGraphQLType(name string) bool { + return name == "H256" +} + +func (t *H256) UnmarshalGraphQL(input interface{}) error { + switch input := input.(type) { + case string: + if strings.HasPrefix(input, "0x") { + input = input[2:] + } + + hash, err := common.Uint256FromHexString(input) + if err != nil { + return err + } + *t = H256(hash) + return nil + default: + return fmt.Errorf("wrong type for H256: %T", input) + } +} + +func (t H256) MarshalJSON() ([]byte, error) { + hash := common.Uint256(t) + return json.Marshal(hash.ToHexString()) +} + +type PubKey string + +func (PubKey) ImplementsGraphQLType(name string) bool { + return name == "PubKey" +} + +func (key *PubKey) UnmarshalGraphQL(input interface{}) error { + switch input := input.(type) { + case string: + _, err := common.PubKeyFromHex(input) + if err != nil { + return err + } + *key = PubKey(input) + return nil + default: + return fmt.Errorf("wrong type for PubKey: %T", input) + } +} + +func (key PubKey) MarshalJSON() ([]byte, error) { + return json.Marshal(string(key)) +} diff --git a/http/graphql/schema/bindata.go b/http/graphql/schema/bindata.go new file mode 100644 index 0000000000..7edb879a88 --- /dev/null +++ b/http/graphql/schema/bindata.go @@ -0,0 +1,263 @@ +/* + * 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 . + */ + +// Code generated by go-bindata. (@generated) DO NOT EDIT. + +// Package schema generated by go-bindata.// sources: +// schema.graphql +package schema + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +// Name return file name +func (fi bindataFileInfo) Name() string { + return fi.name +} + +// Size return file size +func (fi bindataFileInfo) Size() int64 { + return fi.size +} + +// Mode return file mode +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} + +// ModTime return file modify time +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} + +// IsDir return file whether a directory +func (fi bindataFileInfo) IsDir() bool { + return fi.mode&os.ModeDir != 0 +} + +// Sys return file is sys mode +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _schemaGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x55\x4d\x6f\xdb\x30\x0c\xbd\xfb\x57\xb0\xc8\xa5\xbb\xf4\xd0\xb5\xc5\xe0\x5b\xb3\x16\x48\xd1\xaf\x6c\xc9\x36\x0c\x45\x31\x30\x32\x6b\x0b\xb1\x25\x4f\x94\xd3\x18\x45\xff\xfb\x20\xcb\x76\xe5\xc4\x1d\xd0\x53\x22\xea\xf1\xe9\x3d\x92\x92\x27\xb0\x42\xa6\xd3\x2f\xa0\x0d\x64\xb4\x05\xb6\x46\xaa\x14\x30\x49\x0c\x31\x47\x2c\x30\x47\x03\xe7\xed\x72\x12\x62\xf4\x13\x64\xc8\xd9\xf1\xe9\x59\x07\x9b\xb9\xff\xbb\x98\xb2\x5a\xe5\x52\xc0\x9a\xea\x0e\x36\xaf\x56\xd7\x54\x47\xdd\xf2\x87\x54\xf6\xf3\x71\x34\x81\x4a\x2a\x7b\x76\x02\xa4\x84\x4e\x28\x01\xe4\x96\x25\x04\x9e\x9d\x44\x11\xa9\xaa\x80\xe5\x76\x59\x97\x04\x2f\x11\x00\xc0\xd5\xdd\xcf\xfb\xeb\xcb\x3f\x77\x97\xf7\xe1\xf2\xd7\xf9\xe2\xb6\x59\x5f\x5c\xce\x6f\xee\x7f\xf7\xdb\xed\xb2\xd9\x7e\x8d\x22\xa9\x2c\x99\x27\x14\x04\x73\xac\x73\x8d\x49\x4b\xea\x54\x40\x0c\x8b\x46\xc3\x81\x43\x5a\x77\xe2\x95\xda\xe8\x35\x7d\x75\x9b\xb2\x28\x73\x2a\x48\x59\x1e\x49\xdd\xcf\xbc\xa0\x32\xd7\xf5\x47\x32\x5d\x64\x53\x38\xa3\xc3\x98\xc2\x62\x17\x45\x86\xa5\x56\xc3\x20\x56\x36\xd3\x66\x18\xa3\x02\x65\x3e\x0c\x25\xc4\x62\xa0\x76\x02\xd6\xa0\x62\x14\x56\x6a\xe5\x9a\x50\x09\x5b\x19\x72\xdd\xd4\xca\xea\x5c\xa7\xb5\x77\xb4\x0c\x60\x2f\x43\x1d\xbe\xab\xfe\x00\x37\x26\x71\x33\x1d\xad\x7c\xad\x04\x0d\x21\x76\xeb\x5d\xfa\xb6\xfa\x58\x8a\x3c\x37\x72\x17\x99\x22\xdf\xc8\x42\xda\x61\xb4\xc4\x9a\x4c\xdc\x0d\x6a\x1f\x73\x95\x8d\xbb\x12\xfb\x28\xcb\x94\x63\x78\x58\xc8\xf4\xe0\xf1\x20\xf2\xfa\x48\xa6\x59\x40\xd8\x35\x6c\x21\xd3\xd6\x16\xcb\xf4\x02\x2d\xba\x3c\x5f\xa6\xc7\xf6\x88\x66\x94\x1d\x9f\x1f\xea\x2e\x7e\x3b\x20\x9b\xc0\x34\xd7\x62\xfd\xbf\x4a\x7a\x80\x3f\x6c\x02\xcb\x8c\x20\x23\x4c\xc8\x38\xa4\xcd\x24\xc3\xca\x01\x8e\x5a\xb9\x6e\x27\x86\x59\xf3\xdb\x7a\xf0\x49\x41\xdf\x38\xc8\x03\xa9\x44\x5e\x25\x94\x78\x82\x10\x15\xc3\x43\xd0\x45\xa7\xbf\x11\xec\xb9\x41\x3a\x96\x50\x0b\x7a\x42\x2f\xba\x05\x85\xaa\xdb\xfe\xf7\xb2\x7d\xe6\xd1\xf8\x6c\x84\x6e\x91\xb3\xd1\xa4\x70\x76\x02\x7c\x69\x68\x23\x75\xd5\xf9\x73\x28\x8f\x77\x1b\xb3\xf1\x1c\x51\x19\x43\xca\x76\x29\x4d\xd3\x8f\x46\x07\x20\xac\xa8\x2c\x88\x2d\x16\x65\x58\xce\x94\x14\x19\xb4\x7d\x3d\x3b\xcc\x28\x43\x41\x66\x9d\xbb\xd6\x10\x81\xd1\xda\xc2\xb3\xb4\x19\xe4\x84\x1b\x62\x78\x32\xba\x68\xe8\xb8\x27\xb7\x7a\xaf\xe3\xcd\xdf\xef\x5a\xdb\x11\x57\x83\x96\x37\xfc\x23\x23\x63\xb7\xfc\x4e\xba\xd0\x8a\x49\x71\xc5\x90\xa0\xc5\xb1\xdc\x1e\xe1\x6f\x80\x7f\x85\x87\x0e\xab\xdc\xca\xee\x9b\xe1\x28\x84\x56\xba\x65\x55\x3a\x21\x86\xe7\x4c\x83\x40\xd5\x17\x0e\x14\x6d\x6d\x78\x88\x5b\x4f\xb5\x5e\xaf\x89\xca\xc1\x45\x1e\x4a\xdd\x67\xed\x19\xf7\x6a\xd6\xb3\x0d\xaf\x67\x40\xc8\x32\x55\xd8\xdd\xc7\x8f\xb1\x8f\x3d\x08\xdd\xb3\x31\xc5\x1c\x95\xe8\xbe\x4d\x5a\xd9\xb7\xa2\xf9\x40\x3a\x0c\xbc\xf7\xfc\x7c\xab\xc8\xd4\x2d\x4b\x4a\xb6\x79\x22\xa6\xf5\xac\x41\x1f\xee\x24\x7d\x8a\xfd\x13\xb2\x0b\x46\xce\x0e\x83\x2b\x34\x0a\xf3\xa0\x3d\xbe\xb7\xf7\x3a\x25\xbb\xdc\xee\xd0\x04\x8f\x46\x4f\xe6\x7d\x1f\xba\x41\x78\xeb\xa0\x3b\xd2\x6f\x34\xce\x58\x64\x54\x60\xeb\xea\xaf\x73\x18\x7b\xa3\xd1\x6b\xf4\x2f\x00\x00\xff\xff\x28\x4d\x93\xb3\x8d\x08\x00\x00") + +func schemaGraphqlBytes() ([]byte, error) { + return bindataRead( + _schemaGraphql, + "schema.graphql", + ) +} + +func schemaGraphql() (*asset, error) { + bytes, err := schemaGraphqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "schema.graphql", size: 2189, mode: os.FileMode(438), modTime: time.Unix(1598341445, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + canonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[canonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + canonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[canonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "schema.graphql": schemaGraphql, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("nonexistent") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + canonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(canonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "schema.graphql": &bintree{schemaGraphql, map[string]*bintree{}}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + canonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) +} diff --git a/http/graphql/schema/generate.go b/http/graphql/schema/generate.go new file mode 100644 index 0000000000..c2c2e42a0c --- /dev/null +++ b/http/graphql/schema/generate.go @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +//go:generate go-bindata -ignore=\.go -pkg=schema -o=bindata.go ./... +package schema diff --git a/http/graphql/schema/schema.graphql b/http/graphql/schema/schema.graphql new file mode 100644 index 0000000000..6e85d3204a --- /dev/null +++ b/http/graphql/schema/schema.graphql @@ -0,0 +1,119 @@ +# base58 or hex string address +scalar Address +# hex string of hash256 +scalar H256 +# hex string of public key +scalar PubKey + +scalar Uint32 +# uint64 encoded as string +scalar Uint64 + +enum TxType { + INVOKE_NEO + INVOKE_WASM + DEPLOY_NEO + DEPLOY_WASM +} + +interface Payload { + code : String! +} + +type InvokeCode implements Payload { + code: String! +} + +type DeployCode implements Payload { + code: String! + vmType: String! + name: String! + version: String! + author: String! + email: String! + desc: String! +} + +# transaction structure of ontology +type Transaction { + version: Uint32! + hash: H256! + nonce: Uint32! + txType: TxType! + gasPrice: Uint32! + gasLimit: Uint32! + payer: Address! + payload: Payload! + sigs: [Sig!]! + + height: Uint32! +} + +type Sig { + sigData: [String!]! + pubKeys: [PubKey!]! + M: Uint32! +} + +# Block structure of ontology +type Block { + # The header of this block. + header: Header! + + # The transactions this block included. + transactions: [Transaction!]! +} + +# Header is the header of a block +type Header { + # The version of this header. + version: Uint32! + + # The hash of this header. + hash: H256! + + # The previous block hash. + prevHash: H256! + + # The current block height. + height: Uint32! + + # The timestamp this block generated. + timestamp: Uint32! + + # The merkle tree root with leaves from genesis block to this block. + blockRoot: H256! + + # The transactions root of this block. + txsRoot: H256! + + # The consensus data of this block. + consensusData: Uint64! + + # The multi address of conosensus nodes who can generate next block. + nextBookkeeper: Address! + + # The conosensus nodes who generate this block. + bookkeepers: [PubKey!]! + + # The signature of conosensus nodes who generate this block. + sigData: [String!]! +} + +type Balance { + ont: Uint64! + ong: Uint64! + height: Uint32! +} + +type Query { + getBlockByHeight(height: Uint32!): Block + getBlockByHash(hash: H256!): Block + getBlockHash(height: Uint32!): H256! + getTx(hash: H256!): Transaction + getBalance(addr: Address!): Balance! +} + +schema { + query: Query +} diff --git a/http/graphql/service.go b/http/graphql/service.go new file mode 100644 index 0000000000..0128f04bd1 --- /dev/null +++ b/http/graphql/service.go @@ -0,0 +1,372 @@ +/* + * 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 . + */ + +package graphql + +import ( + "net" + "net/http" + "strconv" + + "github.com/graph-gophers/graphql-go" + "github.com/graph-gophers/graphql-go/relay" + "github.com/ontio/ontology/common" + "github.com/ontio/ontology/common/config" + "github.com/ontio/ontology/common/log" + "github.com/ontio/ontology/core/payload" + "github.com/ontio/ontology/core/types" + "github.com/ontio/ontology/http/base/actor" + comm "github.com/ontio/ontology/http/base/common" + "github.com/ontio/ontology/http/graphql/schema" + "github.com/ontio/ontology/smartcontract/service/native/utils" + "golang.org/x/net/netutil" +) + +var ontSchema *graphql.Schema + +func init() { + resolver := &resolver{} + s, err := schema.Asset("schema.graphql") + if err != nil { + panic(err) + } + + ontSchema = graphql.MustParseSchema(string(s), resolver, graphql.UseFieldResolvers()) +} + +type resolver struct{} +type block struct { + Header *header + Transactions []*transaction +} + +type header struct { + Version Uint32 + Hash H256 + PrevHash H256 + Height Uint32 + Timestamp Uint32 + BlockRoot H256 + TxsRoot H256 + ConsensusData Uint64 + NextBookkeeper Addr + Bookkeepers []PubKey + SigData []string +} + +type invokeCodePayload struct { + Code string +} + +type deployCodePayload struct { + Code string + VmType string + Name string + Version string + Author string + Email string + Desc string +} + +type TxPayload struct { + pl interface{} +} + +func (self *TxPayload) ToInvokeCode() (*invokeCodePayload, bool) { + pl, ok := self.pl.(*invokeCodePayload) + return pl, ok +} + +func (self *TxPayload) ToDeployCode() (*deployCodePayload, bool) { + pl, ok := self.pl.(*deployCodePayload) + return pl, ok +} + +func (self *TxPayload) Code() string { + switch pd := self.pl.(type) { + case *invokeCodePayload: + return pd.Code + case *deployCodePayload: + return pd.Code + default: + panic("unreachable") + } +} + +func NewTxPayload(pl types.Payload) *TxPayload { + switch val := pl.(type) { + case *payload.InvokeCode: + return &TxPayload{pl: &invokeCodePayload{Code: common.ToHexString(val.Code)}} + case *payload.DeployCode: + vmty := "Neo" + if val.VmType() == payload.WASMVM_TYPE { + vmty = "Wasm" + } + dp := &deployCodePayload{ + Code: common.ToHexString(val.GetRawCode()), + VmType: vmty, + Name: val.Name, + Version: val.Version, + Author: val.Author, + Email: val.Email, + Desc: val.Description, + } + return &TxPayload{pl: dp} + default: + panic("unreachable") + } +} + +func NewTransaction(tx *types.Transaction, height uint32) *transaction { + ty := convTxType(tx) + var sigs []*Sig + for _, val := range tx.Sigs { + sig, err := val.GetSig() + if err == nil { + var sigdata []string + for _, data := range sig.SigData { + sigdata = append(sigdata, common.ToHexString(data)) + } + var pubkey []PubKey + for _, val := range sig.PubKeys { + pubkey = append(pubkey, PubKey(common.PubKeyToHex(val))) + } + sigs = append(sigs, &Sig{ + SigData: sigdata, + PubKeys: pubkey, + M: Uint32(sig.M), + }) + } + } + t := &transaction{ + Version: Uint32(tx.Version), + Hash: H256(tx.Hash()), + Nonce: Uint32(tx.Nonce), + TxType: ty, + GasPrice: Uint32(tx.GasPrice), + GasLimit: Uint32(tx.GasLimit), + Payer: Addr{tx.Payer}, + Payload: NewTxPayload(tx.Payload), + Sigs: sigs, + Height: Uint32(height), + } + + return t +} + +func NewBlock(b *types.Block) *block { + var txs []*transaction + for _, tx := range b.Transactions { + txs = append(txs, NewTransaction(tx, b.Header.Height)) + } + return &block{ + Header: NewHeader(b.Header), + Transactions: txs, + } +} + +func NewHeader(h *types.Header) *header { + var pubKeys []PubKey + for _, k := range h.Bookkeepers { + pubKeys = append(pubKeys, PubKey(common.PubKeyToHex(k))) + } + var sigData []string + for _, sig := range h.SigData { + sigData = append(sigData, common.ToHexString(sig)) + } + + hd := &header{ + Version: Uint32(h.Version), + Hash: H256(h.Hash()), + PrevHash: H256(h.PrevBlockHash), + Height: Uint32(h.Height), + Timestamp: Uint32(h.Timestamp), + BlockRoot: H256(h.BlockRoot), + TxsRoot: H256(h.TransactionsRoot), + ConsensusData: Uint64(h.ConsensusData), + NextBookkeeper: Addr{h.NextBookkeeper}, + Bookkeepers: pubKeys, + SigData: sigData, + } + + return hd +} + +func (self *resolver) GetBlockByHeight(args struct{ Height Uint32 }) (*block, error) { + b, err := actor.GetBlockByHeight(uint32(args.Height)) + if err != nil { + return nil, err + } + + return NewBlock(b), nil +} + +func (self *resolver) GetBlockByHash(args struct{ Hash H256 }) (*block, error) { + b, err := actor.GetBlockFromStore(common.Uint256(args.Hash)) + if err != nil { + return nil, err + } + + return NewBlock(b), nil +} + +func (self *resolver) GetBlockHash(args struct{ Height Uint32 }) H256 { + return H256(actor.GetBlockHashFromStore(uint32(args.Height))) +} + +type balance struct { + Ont Uint64 + Ong Uint64 + Height Uint32 +} + +type TxType string + +const INVOKE_NEO TxType = "INVOKE_NEO" +const INVOKE_WASM TxType = "INVOKE_WASM" +const DEPLOY_NEO TxType = "DEPLOY_NEO" +const DEPLOY_WASM TxType = "DEPLOY_WASM" + +func convTxType(tx *types.Transaction) TxType { + switch pl := tx.Payload.(type) { + case *payload.InvokeCode: + if tx.TxType == types.InvokeNeo { + return INVOKE_NEO + } else { + return INVOKE_WASM + } + case *payload.DeployCode: + switch pl.VmType() { + case payload.NEOVM_TYPE: + return DEPLOY_NEO + case payload.WASMVM_TYPE: + return DEPLOY_WASM + default: + panic("unreachable") + } + default: + panic("unreachable") + } +} + +type transaction struct { + Version Uint32 + Hash H256 + Nonce Uint32 + TxType TxType + GasPrice Uint32 + GasLimit Uint32 + Payer Addr + Payload *TxPayload + Sigs []*Sig + Height Uint32 +} + +type Sig struct { + SigData []string + PubKeys []PubKey + M Uint32 +} + +func (self *resolver) GetTx(args struct{ Hash H256 }) (*transaction, error) { + height, tx, err := actor.GetTxnWithHeightByTxHash(common.Uint256(args.Hash)) + if err != nil { + return nil, err + } + + return NewTransaction(tx, height), nil +} + +func (self *resolver) GetBalance(args struct{ Addr Addr }) (*balance, error) { + balances, height, err := comm.GetContractBalance(0, + []common.Address{utils.OntContractAddress, utils.OngContractAddress}, args.Addr.Address, true) + if err != nil { + return nil, err + } + + return &balance{ + Height: Uint32(height), + Ont: Uint64(balances[0]), + Ong: Uint64(balances[1]), + }, nil +} + +func StartServer(cfg *config.GraphQLConfig) { + if !cfg.EnableGraphQL || cfg.GraphQLPort == 0 { + return + } + + serverMut := http.NewServeMux() + serverMut.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(page) + })) + + serverMut.Handle("/query", &relay.Handler{Schema: ontSchema}) + + server := &http.Server{Handler: serverMut} + listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(cfg.GraphQLPort))) + if err != nil { + log.Error("start graphql server error: %s", err) + return + } + if cfg.MaxConnections > 0 { + listener = netutil.LimitListener(listener, int(cfg.MaxConnections)) + } + + log.Infof("start GraphQL service on %d", cfg.GraphQLPort) + log.Error(server.Serve(listener)) +} + +var page = []byte(` + + + + + + + + + + + +
Loading...
+ + + +`) diff --git a/http/base/rpc/interfaces.go b/http/jsonrpc/interfaces.go similarity index 62% rename from http/base/rpc/interfaces.go rename to http/jsonrpc/interfaces.go index 1ab41efec4..344aaed1ac 100644 --- a/http/base/rpc/interfaces.go +++ b/http/jsonrpc/interfaces.go @@ -16,7 +16,7 @@ * along with The ontology. If not, see . */ -package rpc +package jsonrpc import ( "encoding/hex" @@ -31,13 +31,14 @@ import ( bactor "github.com/ontio/ontology/http/base/actor" bcomn "github.com/ontio/ontology/http/base/common" berr "github.com/ontio/ontology/http/base/error" + "github.com/ontio/ontology/http/base/rpc" "github.com/ontio/ontology/smartcontract/service/native/utils" ) //get best block hash func GetBestBlockHash(params []interface{}) map[string]interface{} { hash := bactor.CurrentBlockHash() - return responseSuccess(hash.ToHexString()) + return rpc.ResponseSuccess(hash.ToHexString()) } // get block by height or hash @@ -46,7 +47,7 @@ func GetBestBlockHash(params []interface{}) map[string]interface{} { // {"jsonrpc": "2.0", "method": "getblock", "params": ["aabbcc.."], "id": 0} func GetBlock(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } var err error var hash common.Uint256 @@ -56,40 +57,40 @@ func GetBlock(params []interface{}) map[string]interface{} { index := uint32(params[0].(float64)) hash = bactor.GetBlockHashFromStore(index) if hash == common.UINT256_EMPTY { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } // block hash case string: str := params[0].(string) hash, err = common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } block, err := bactor.GetBlockFromStore(hash) if err != nil { - return responsePack(berr.UNKNOWN_BLOCK, "unknown block") + return rpc.ResponsePack(berr.UNKNOWN_BLOCK, "unknown block") } if len(params) >= 2 { switch (params[1]).(type) { case float64: json := uint32(params[1].(float64)) if json == 1 { - return responseSuccess(bcomn.GetBlockInfo(block)) + return rpc.ResponseSuccess(bcomn.GetBlockInfo(block)) } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } - return responseSuccess(common.ToHexString(block.ToArray())) + return rpc.ResponseSuccess(common.ToHexString(block.ToArray())) } //get block height func GetBlockCount(params []interface{}) map[string]interface{} { height := bactor.GetCurrentBlockHeight() - return responseSuccess(height + 1) + return rpc.ResponseSuccess(height + 1) } //get block hash @@ -97,25 +98,25 @@ func GetBlockCount(params []interface{}) map[string]interface{} { // {"jsonrpc": "2.0", "method": "getblockhash", "params": [1], "id": 0} func GetBlockHash(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } switch params[0].(type) { case float64: height := uint32(params[0].(float64)) hash := bactor.GetBlockHashFromStore(height) if hash == common.UINT256_EMPTY { - return responsePack(berr.UNKNOWN_BLOCK, "") + return rpc.ResponsePack(berr.UNKNOWN_BLOCK, "") } - return responseSuccess(hash.ToHexString()) + return rpc.ResponseSuccess(hash.ToHexString()) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } //get node connection count func GetConnectionCount(params []interface{}) map[string]interface{} { count := bactor.GetConnectionCnt() - return responseSuccess(count) + return rpc.ResponseSuccess(count) } //get node connection most height @@ -123,10 +124,10 @@ func GetSyncStatus(params []interface{}) map[string]interface{} { status, err := bcomn.GetSyncStatus() if err != nil { log.Errorf("GetSyncStatus error:%s", err) - return responsePack(berr.INTERNAL_ERROR, false) + return rpc.ResponsePack(berr.INTERNAL_ERROR, false) } - return responseSuccess(status) + return rpc.ResponseSuccess(status) } func GetRawMemPool(params []interface{}) map[string]interface{} { @@ -136,53 +137,53 @@ func GetRawMemPool(params []interface{}) map[string]interface{} { txs = append(txs, bcomn.TransArryByteToHexString(t)) } if len(txs) == 0 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } - return responseSuccess(txs) + return rpc.ResponseSuccess(txs) } //get memory pool transaction count func GetMemPoolTxCount(params []interface{}) map[string]interface{} { count, err := bactor.GetTxnCount() if err != nil { - return responsePack(berr.INTERNAL_ERROR, nil) + return rpc.ResponsePack(berr.INTERNAL_ERROR, nil) } - return responseSuccess(count) + return rpc.ResponseSuccess(count) } //get memory pool transaction hash func GetMemPoolTxHashList(params []interface{}) map[string]interface{} { txHashList, err := bactor.GetTxnHashList() if err != nil { - return responsePack(berr.INTERNAL_ERROR, nil) + return rpc.ResponsePack(berr.INTERNAL_ERROR, nil) } - return responseSuccess(txHashList) + return rpc.ResponseSuccess(txHashList) } //get memory pool transaction state func GetMemPoolTxState(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } switch params[0].(type) { case string: str := params[0].(string) hash, err := common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } txEntry, err := bactor.GetTxFromPool(hash) if err != nil { - return responsePack(berr.UNKNOWN_TRANSACTION, "unknown transaction") + return rpc.ResponsePack(berr.UNKNOWN_TRANSACTION, "unknown transaction") } - attrs := []bcomn.TXNAttrInfo{} + var attrs []bcomn.TXNAttrInfo for _, t := range txEntry.Attrs { attrs = append(attrs, bcomn.TXNAttrInfo{t.Height, int(t.Type), int(t.ErrCode)}) } info := bcomn.TXNEntryInfo{attrs} - return responseSuccess(info) + return rpc.ResponseSuccess(info) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } @@ -191,7 +192,7 @@ func GetMemPoolTxState(params []interface{}) map[string]interface{} { // {"jsonrpc": "2.0", "method": "getrawtransaction", "params": ["transactioin hash in hex"], "id": 0} func GetRawTransaction(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } var tx *types.Transaction var height uint32 @@ -200,16 +201,16 @@ func GetRawTransaction(params []interface{}) map[string]interface{} { str := params[0].(string) hash, err := common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } h, t, err := bactor.GetTxnWithHeightByTxHash(hash) if err != nil { - return responsePack(berr.UNKNOWN_TRANSACTION, "unknown transaction") + return rpc.ResponsePack(berr.UNKNOWN_TRANSACTION, "unknown transaction") } height = h tx = t default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } if len(params) >= 2 { @@ -219,21 +220,21 @@ func GetRawTransaction(params []interface{}) map[string]interface{} { if json == 1 { txinfo := bcomn.TransArryByteToHexString(tx) txinfo.Height = height - return responseSuccess(txinfo) + return rpc.ResponseSuccess(txinfo) } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } - return responseSuccess(common.ToHexString(common.SerializeToBytes(tx))) + return rpc.ResponseSuccess(common.ToHexString(common.SerializeToBytes(tx))) } //get storage from contract // {"jsonrpc": "2.0", "method": "getstorage", "params": ["code hash", "key"], "id": 0} func GetStorage(params []interface{}) map[string]interface{} { if len(params) < 2 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } var address common.Address @@ -244,10 +245,10 @@ func GetStorage(params []interface{}) map[string]interface{} { var err error address, err = bcomn.GetAddress(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } switch params[1].(type) { @@ -255,20 +256,20 @@ func GetStorage(params []interface{}) map[string]interface{} { str := params[1].(string) hex, err := hex.DecodeString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } key = hex default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } value, err := bactor.GetStorageItem(address, key) if err != nil { if err == scom.ErrNotFound { - return responseSuccess(nil) + return rpc.ResponseSuccess(nil) } - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(common.ToHexString(value)) + return rpc.ResponseSuccess(common.ToHexString(value)) } //send raw transaction @@ -276,7 +277,7 @@ func GetStorage(params []interface{}) map[string]interface{} { // {"jsonrpc": "2.0", "method": "sendrawtransaction", "params": ["raw transactioin in hex"], "id": 0} func SendRawTransaction(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } var hash common.Uint256 switch params[0].(type) { @@ -284,11 +285,11 @@ func SendRawTransaction(params []interface{}) map[string]interface{} { str := params[0].(string) raw, err := common.HexToBytes(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } txn, err := types.TransactionFromRawBytes(raw) if err != nil { - return responsePack(berr.INVALID_TRANSACTION, "") + return rpc.ResponsePack(berr.INVALID_TRANSACTION, "") } hash = txn.Hash() log.Debugf("SendRawTransaction recv %s", hash.ToHexString()) @@ -299,9 +300,9 @@ func SendRawTransaction(params []interface{}) map[string]interface{} { result, err := bactor.PreExecuteContract(txn) if err != nil { log.Infof("PreExec: ", err) - return responsePack(berr.SMARTCODE_ERROR, err.Error()) + return rpc.ResponsePack(berr.SMARTCODE_ERROR, err.Error()) } - return responseSuccess(bcomn.ConvertPreExecuteResult(result)) + return rpc.ResponseSuccess(bcomn.ConvertPreExecuteResult(result)) } } } @@ -309,29 +310,29 @@ func SendRawTransaction(params []interface{}) map[string]interface{} { log.Debugf("SendRawTransaction send to txpool %s", hash.ToHexString()) if errCode, desc := bcomn.SendTxToPool(txn); errCode != ontErrors.ErrNoError { log.Warnf("SendRawTransaction verified %s error: %s", hash.ToHexString(), desc) - return responsePack(int64(errCode), desc) + return rpc.ResponsePack(int64(errCode), desc) } log.Debugf("SendRawTransaction verified %s", hash.ToHexString()) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(hash.ToHexString()) + return rpc.ResponseSuccess(hash.ToHexString()) } //get node version func GetNodeVersion(params []interface{}) map[string]interface{} { - return responseSuccess(config.Version) + return rpc.ResponseSuccess(config.Version) } // get networkid func GetNetworkId(params []interface{}) map[string]interface{} { - return responseSuccess(config.DefConfig.P2PNode.NetworkId) + return rpc.ResponseSuccess(config.DefConfig.P2PNode.NetworkId) } //get contract state func GetContractState(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } var contract *payload.DeployCode switch params[0].(type) { @@ -339,39 +340,39 @@ func GetContractState(params []interface{}) map[string]interface{} { str := params[0].(string) address, err := bcomn.GetAddress(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } c, err := bactor.GetContractStateFromStore(address) if err != nil { - return responsePack(berr.UNKNOWN_CONTRACT, berr.ErrMap[berr.UNKNOWN_CONTRACT]) + return rpc.ResponsePack(berr.UNKNOWN_CONTRACT, berr.ErrMap[berr.UNKNOWN_CONTRACT]) } contract = c default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } if len(params) >= 2 { switch (params[1]).(type) { case float64: json := uint32(params[1].(float64)) if json == 1 { - return responseSuccess(bcomn.TransPayloadToHex(contract)) + return rpc.ResponseSuccess(bcomn.TransPayloadToHex(contract)) } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } sink := common.NewZeroCopySink(nil) contract.Serialization(sink) - return responseSuccess(common.ToHexString(sink.Bytes())) + return rpc.ResponseSuccess(common.ToHexString(sink.Bytes())) } //get smartconstract event func GetSmartCodeEvent(params []interface{}) map[string]interface{} { if !config.DefConfig.Common.EnableEventLog { - return responsePack(berr.INVALID_METHOD, "") + return rpc.ResponsePack(berr.INVALID_METHOD, "") } if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } switch (params[0]).(type) { @@ -381,42 +382,42 @@ func GetSmartCodeEvent(params []interface{}) map[string]interface{} { eventInfos, err := bactor.GetEventNotifyByHeight(height) if err != nil { if err == scom.ErrNotFound { - return responseSuccess(nil) + return rpc.ResponseSuccess(nil) } - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } eInfos := make([]*bcomn.ExecuteNotify, 0, len(eventInfos)) for _, eventInfo := range eventInfos { _, notify := bcomn.GetExecuteNotify(eventInfo) eInfos = append(eInfos, ¬ify) } - return responseSuccess(eInfos) + return rpc.ResponseSuccess(eInfos) //txhash case string: str := params[0].(string) hash, err := common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } eventInfo, err := bactor.GetEventNotifyByTxHash(hash) if err != nil { if scom.ErrNotFound == err { - return responseSuccess(nil) + return rpc.ResponseSuccess(nil) } - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } _, notify := bcomn.GetExecuteNotify(eventInfo) - return responseSuccess(notify) + return rpc.ResponseSuccess(notify) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } //get block height by transaction hash func GetBlockHeightByTxHash(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } switch (params[0]).(type) { @@ -425,129 +426,166 @@ func GetBlockHeightByTxHash(params []interface{}) map[string]interface{} { str := params[0].(string) hash, err := common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } height, _, err := bactor.GetTxnWithHeightByTxHash(hash) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(height) + return rpc.ResponseSuccess(height) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } //get balance of address func GetBalance(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } addrBase58, ok := params[0].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } address, err := common.AddressFromBase58(addrBase58) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } rsp, err := bcomn.GetBalance(address) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(rsp) + return rpc.ResponseSuccess(rsp) +} + +//get balance of address +func GetOep4Balance(params []interface{}) map[string]interface{} { + if len(params) < 2 { + return rpc.ResponsePack(berr.INVALID_PARAMS, "") + } + + contractAddrHex, ok := params[0].(string) + if !ok { + return rpc.ResponsePack(berr.INVALID_PARAMS, "") + } + contractAddr, err := common.AddressFromHexString(contractAddrHex) + if err != nil { + return rpc.ResponsePack(berr.INVALID_PARAMS, "") + } + addrs, err := parseAddressParam(params[1].([]interface{})) + if err != nil { + return rpc.ResponsePack(berr.INVALID_PARAMS, "") + } + rsp, err := bcomn.GetOep4Balance(contractAddr, addrs) + if err != nil { + return rpc.ResponsePack(berr.INVALID_PARAMS, "") + } + return rpc.ResponseSuccess(rsp) +} + +func parseAddressParam(params []interface{}) ([]common.Address, error) { + res := make([]common.Address, len(params)) + var err error + for i, param := range params { + res[i], err = common.AddressFromBase58(param.(string)) + if err != nil { + return nil, err + } + } + return res, nil } //get allowance func GetAllowance(params []interface{}) map[string]interface{} { if len(params) < 3 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } asset, ok := params[0].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } fromAddrStr, ok := params[1].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } fromAddr, err := bcomn.GetAddress(fromAddrStr) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } toAddrStr, ok := params[2].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } toAddr, err := bcomn.GetAddress(toAddrStr) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } rsp, err := bcomn.GetAllowance(asset, fromAddr, toAddr) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(rsp) + return rpc.ResponseSuccess(rsp) } //get merkle proof by transaction hash func GetMerkleProof(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } str, ok := params[0].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } hash, err := common.Uint256FromHexString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } height, _, err := bactor.GetTxnWithHeightByTxHash(hash) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } header, err := bactor.GetHeaderByHeight(height) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } curHeight := bactor.GetCurrentBlockHeight() curHeader, err := bactor.GetHeaderByHeight(curHeight) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } proof, err := bactor.GetMerkleProof(uint32(height), uint32(curHeight)) if err != nil { - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } var hashes []string for _, v := range proof { hashes = append(hashes, v.ToHexString()) } - return responseSuccess(bcomn.MerkleProof{"MerkleProof", header.TransactionsRoot.ToHexString(), height, + return rpc.ResponseSuccess(bcomn.MerkleProof{"MerkleProof", header.TransactionsRoot.ToHexString(), height, curHeader.BlockRoot.ToHexString(), curHeight, hashes}) } //get block transactions by height func GetBlockTxsByHeight(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } switch params[0].(type) { case float64: height := uint32(params[0].(float64)) hash := bactor.GetBlockHashFromStore(height) if hash == common.UINT256_EMPTY { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } block, err := bactor.GetBlockFromStore(hash) if err != nil { - return responsePack(berr.UNKNOWN_BLOCK, "") + return rpc.ResponsePack(berr.UNKNOWN_BLOCK, "") } - return responseSuccess(bcomn.GetBlockTransactions(block)) + return rpc.ResponseSuccess(bcomn.GetBlockTransactions(block)) default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } } @@ -555,95 +593,95 @@ func GetBlockTxsByHeight(params []interface{}) map[string]interface{} { func GetGasPrice(params []interface{}) map[string]interface{} { result, err := bcomn.GetGasPrice() if err != nil { - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } - return responseSuccess(result) + return rpc.ResponseSuccess(result) } // get unbound ong of address func GetUnboundOng(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } str, ok := params[0].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } toAddr, err := common.AddressFromBase58(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } fromAddr := utils.OntContractAddress rsp, err := bcomn.GetAllowance("ong", fromAddr, toAddr) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responseSuccess(rsp) + return rpc.ResponseSuccess(rsp) } // get grant ong of address func GetGrantOng(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } str, ok := params[0].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } toAddr, err := common.AddressFromBase58(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } rsp, err := bcomn.GetGrantOng(toAddr) if err != nil { - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } - return responseSuccess(rsp) + return rpc.ResponseSuccess(rsp) } //get cross chain message by height func GetCrossChainMsg(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } height, ok := (params[0]).(float64) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } msg, err := bactor.GetCrossChainMsg(uint32(height)) if err != nil { log.Errorf("GetCrossChainMsg, get cross chain msg from db error:%s", err) - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } header, err := bactor.GetHeaderByHeight(uint32(height) + 1) if err != nil { log.Errorf("GetCrossChainMsg, get block by height from db error:%s", err) - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } - return responseSuccess(bcomn.TransferCrossChainMsg(msg, header.Bookkeepers)) + return rpc.ResponseSuccess(bcomn.TransferCrossChainMsg(msg, header.Bookkeepers)) } //get cross chain state proof func GetCrossStatesProof(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, nil) + return rpc.ResponsePack(berr.INVALID_PARAMS, nil) } height, ok := params[0].(float64) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } str, ok := params[1].(string) if !ok { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } key, err := hex.DecodeString(str) if err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } proof, err := bactor.GetCrossStatesProof(uint32(height), key) if err != nil { log.Errorf("GetCrossStatesProof, bactor.GetCrossStatesProof error:%s", err) - return responsePack(berr.INTERNAL_ERROR, "") + return rpc.ResponsePack(berr.INTERNAL_ERROR, "") } - return responseSuccess(bcomn.CrossStatesProof{"CrossStatesProof", hex.EncodeToString(proof)}) + return rpc.ResponseSuccess(bcomn.CrossStatesProof{"CrossStatesProof", hex.EncodeToString(proof)}) } diff --git a/http/jsonrpc/rpc_server.go b/http/jsonrpc/rpc_server.go index be207087fb..89f3b988bd 100644 --- a/http/jsonrpc/rpc_server.go +++ b/http/jsonrpc/rpc_server.go @@ -32,37 +32,38 @@ import ( func StartRPCServer() error { log.Debug() http.HandleFunc("/", rpc.Handle) - rpc.HandleFunc("getbestblockhash", rpc.GetBestBlockHash) - rpc.HandleFunc("getblock", rpc.GetBlock) - rpc.HandleFunc("getblockcount", rpc.GetBlockCount) - rpc.HandleFunc("getblockhash", rpc.GetBlockHash) - rpc.HandleFunc("getconnectioncount", rpc.GetConnectionCount) - rpc.HandleFunc("getsyncstatus", rpc.GetSyncStatus) + rpc.HandleFunc("getbestblockhash", GetBestBlockHash) + rpc.HandleFunc("getblock", GetBlock) + rpc.HandleFunc("getblockcount", GetBlockCount) + rpc.HandleFunc("getblockhash", GetBlockHash) + rpc.HandleFunc("getconnectioncount", GetConnectionCount) + rpc.HandleFunc("getsyncstatus", GetSyncStatus) //HandleFunc("getrawmempool", GetRawMemPool) - rpc.HandleFunc("getrawtransaction", rpc.GetRawTransaction) - rpc.HandleFunc("sendrawtransaction", rpc.SendRawTransaction) - rpc.HandleFunc("getstorage", rpc.GetStorage) - rpc.HandleFunc("getversion", rpc.GetNodeVersion) - rpc.HandleFunc("getnetworkid", rpc.GetNetworkId) + rpc.HandleFunc("getrawtransaction", GetRawTransaction) + rpc.HandleFunc("sendrawtransaction", SendRawTransaction) + rpc.HandleFunc("getstorage", GetStorage) + rpc.HandleFunc("getversion", GetNodeVersion) + rpc.HandleFunc("getnetworkid", GetNetworkId) - rpc.HandleFunc("getcontractstate", rpc.GetContractState) - rpc.HandleFunc("getmempooltxcount", rpc.GetMemPoolTxCount) - rpc.HandleFunc("getmempooltxstate", rpc.GetMemPoolTxState) - rpc.HandleFunc("getmempooltxhashlist", rpc.GetMemPoolTxHashList) - rpc.HandleFunc("getsmartcodeevent", rpc.GetSmartCodeEvent) - rpc.HandleFunc("getblockheightbytxhash", rpc.GetBlockHeightByTxHash) + rpc.HandleFunc("getcontractstate", GetContractState) + rpc.HandleFunc("getmempooltxcount", GetMemPoolTxCount) + rpc.HandleFunc("getmempooltxstate", GetMemPoolTxState) + rpc.HandleFunc("getmempooltxhashlist", GetMemPoolTxHashList) + rpc.HandleFunc("getsmartcodeevent", GetSmartCodeEvent) + rpc.HandleFunc("getblockheightbytxhash", GetBlockHeightByTxHash) - rpc.HandleFunc("getbalance", rpc.GetBalance) - rpc.HandleFunc("getallowance", rpc.GetAllowance) - rpc.HandleFunc("getmerkleproof", rpc.GetMerkleProof) - rpc.HandleFunc("getblocktxsbyheight", rpc.GetBlockTxsByHeight) - rpc.HandleFunc("getgasprice", rpc.GetGasPrice) - rpc.HandleFunc("getunboundong", rpc.GetUnboundOng) - rpc.HandleFunc("getgrantong", rpc.GetGrantOng) + rpc.HandleFunc("getbalance", GetBalance) + rpc.HandleFunc("getoep4balance", GetOep4Balance) + rpc.HandleFunc("getallowance", GetAllowance) + rpc.HandleFunc("getmerkleproof", GetMerkleProof) + rpc.HandleFunc("getblocktxsbyheight", GetBlockTxsByHeight) + rpc.HandleFunc("getgasprice", GetGasPrice) + rpc.HandleFunc("getunboundong", GetUnboundOng) + rpc.HandleFunc("getgrantong", GetGrantOng) - rpc.HandleFunc("getcrosschainmsg", rpc.GetCrossChainMsg) - rpc.HandleFunc("getcrossstatesproof", rpc.GetCrossStatesProof) + rpc.HandleFunc("getcrosschainmsg", GetCrossChainMsg) + rpc.HandleFunc("getcrossstatesproof", GetCrossStatesProof) err := http.ListenAndServe(":"+strconv.Itoa(int(cfg.DefConfig.Rpc.HttpJsonPort)), nil) if err != nil { diff --git a/http/base/rpc/local_interfaces.go b/http/localrpc/local_interfaces.go similarity index 75% rename from http/base/rpc/local_interfaces.go rename to http/localrpc/local_interfaces.go index 5b23dceaa8..652f660b15 100644 --- a/http/base/rpc/local_interfaces.go +++ b/http/localrpc/local_interfaces.go @@ -16,34 +16,21 @@ * along with The ontology. If not, see . */ -package rpc +package localrpc import ( - "os" - "path/filepath" "time" "github.com/ontio/ontology/common/log" bactor "github.com/ontio/ontology/http/base/actor" "github.com/ontio/ontology/http/base/common" berr "github.com/ontio/ontology/http/base/error" + "github.com/ontio/ontology/http/base/rpc" ) -const ( - RANDBYTELEN = 4 -) - -func getCurrentDirectory() string { - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - log.Fatal(err) - } - return dir -} - func GetNeighbor(params []interface{}) map[string]interface{} { addr := bactor.GetNeighborAddrs() - return responseSuccess(addr) + return rpc.ResponseSuccess(addr) } func GetNodeState(params []interface{}) map[string]interface{} { @@ -56,7 +43,7 @@ func GetNodeState(params []interface{}) map[string]interface{} { height := bactor.GetCurrentBlockHeight() txnCnt, err := bactor.GetTxnCount() if err != nil { - return responsePack(berr.INTERNAL_ERROR, false) + return rpc.ResponsePack(berr.INTERNAL_ERROR, false) } n := common.NodeInfo{ NodeTime: t, @@ -68,35 +55,35 @@ func GetNodeState(params []interface{}) map[string]interface{} { Height: height, TxnCnt: txnCnt, } - return responseSuccess(n) + return rpc.ResponseSuccess(n) } func StartConsensus(params []interface{}) map[string]interface{} { if err := bactor.ConsensusSrvStart(); err != nil { - return responsePack(berr.INTERNAL_ERROR, false) + return rpc.ResponsePack(berr.INTERNAL_ERROR, false) } - return responsePack(berr.SUCCESS, true) + return rpc.ResponsePack(berr.SUCCESS, true) } func StopConsensus(params []interface{}) map[string]interface{} { if err := bactor.ConsensusSrvHalt(); err != nil { - return responsePack(berr.INTERNAL_ERROR, false) + return rpc.ResponsePack(berr.INTERNAL_ERROR, false) } - return responsePack(berr.SUCCESS, true) + return rpc.ResponsePack(berr.SUCCESS, true) } func SetDebugInfo(params []interface{}) map[string]interface{} { if len(params) < 1 { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } switch params[0].(type) { case float64: level := params[0].(float64) if err := log.Log().SetDebugLevel(int(level)); err != nil { - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } default: - return responsePack(berr.INVALID_PARAMS, "") + return rpc.ResponsePack(berr.INVALID_PARAMS, "") } - return responsePack(berr.SUCCESS, true) + return rpc.ResponsePack(berr.SUCCESS, true) } diff --git a/http/localrpc/local_server.go b/http/localrpc/local_server.go index 9e93f3cf95..246232c635 100644 --- a/http/localrpc/local_server.go +++ b/http/localrpc/local_server.go @@ -38,11 +38,11 @@ func StartLocalServer() error { log.Debug() http.HandleFunc(LOCAL_DIR, rpc.Handle) - rpc.HandleFunc("getneighbor", rpc.GetNeighbor) - rpc.HandleFunc("getnodestate", rpc.GetNodeState) - rpc.HandleFunc("startconsensus", rpc.StartConsensus) - rpc.HandleFunc("stopconsensus", rpc.StopConsensus) - rpc.HandleFunc("setdebuginfo", rpc.SetDebugInfo) + rpc.HandleFunc("getneighbor", GetNeighbor) + rpc.HandleFunc("getnodestate", GetNodeState) + rpc.HandleFunc("startconsensus", StartConsensus) + rpc.HandleFunc("stopconsensus", StopConsensus) + rpc.HandleFunc("setdebuginfo", SetDebugInfo) // TODO: only listen to local host err := http.ListenAndServe(LOCAL_HOST+":"+strconv.Itoa(int(cfg.DefConfig.Rpc.HttpLocalPort)), nil) diff --git a/http/restful/restful/router.go b/http/restful/restful/router.go index 6a14ad1447..3d5266e8a6 100644 --- a/http/restful/restful/router.go +++ b/http/restful/restful/router.go @@ -48,7 +48,7 @@ func (this *Router) Try(path string, method string) (http.HandlerFunc, paramsMap for _, route := range this.routes { if route.Method == method { match := route.Path.MatchString(path) - if match == false { + if !match { continue } params := paramsMap{} @@ -71,11 +71,9 @@ func (this *Router) add(method string, path string, handler http.HandlerFunc) { if strings.Contains(path, ":") { matches := regexp.MustCompile(`:(\w+)`).FindAllStringSubmatch(path, -1) - if matches != nil { - for _, v := range matches { - route.Params = append(route.Params, v[1]) - path = strings.Replace(path, v[0], `(\w+)`, 1) - } + for _, v := range matches { + route.Params = append(route.Params, v[1]) + path = strings.Replace(path, v[0], `(\w+)`, 1) } } compiledPath, err := regexp.Compile(path) @@ -138,6 +136,6 @@ func parseParams(route *Route, path string) paramsMap { func getParam(r *http.Request, key string) string { ctx := r.Context() params := ctx.Value("params").(paramsMap) - val, _ := params[key] + val := params[key] return val } diff --git a/main.go b/main.go index ec4aeb3d28..293e710ab0 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,7 @@ import ( "github.com/ontio/ontology/core/ledger" "github.com/ontio/ontology/events" bactor "github.com/ontio/ontology/http/base/actor" - hserver "github.com/ontio/ontology/http/base/actor" + "github.com/ontio/ontology/http/graphql" "github.com/ontio/ontology/http/jsonrpc" "github.com/ontio/ontology/http/localrpc" "github.com/ontio/ontology/http/nodeinfo" @@ -124,6 +124,10 @@ func setupAPP() *cli.App { utils.RestfulEnableFlag, utils.RestfulPortFlag, utils.RestfulMaxConnsFlag, + //graphql setting + utils.GraphQLEnableFlag, + utils.GraphQLPortFlag, + utils.GraphQLMaxConnsFlag, //ws setting utils.WsEnabledFlag, utils.WsPortFlag, @@ -190,6 +194,7 @@ func startOntology(ctx *cli.Context) { log.Errorf("initLocalRpc error: %s", err) return } + initGraphQL(ctx) initRestful(ctx) initWs(ctx) initNodeInfo(ctx, p2pSvr) @@ -292,8 +297,8 @@ func initTxPool(ctx *cli.Context) (*proc.TXPoolServer, error) { stfValidator, _ := stateful.NewValidator("stateful_validator") stfValidator.Register(txPoolServer.GetPID(tc.VerifyRspActor)) - hserver.SetTxnPoolPid(txPoolServer.GetPID(tc.TxPoolActor)) - hserver.SetTxPid(txPoolServer.GetPID(tc.TxActor)) + bactor.SetTxnPoolPid(txPoolServer.GetPID(tc.TxPoolActor)) + bactor.SetTxPid(txPoolServer.GetPID(tc.TxActor)) log.Infof("TxPool init success") return txPoolServer, nil @@ -314,7 +319,7 @@ func initP2PNode(ctx *cli.Context, txpoolSvr *proc.TXPoolServer, acct *account.A } netreqactor.SetTxnPoolPid(txpoolSvr.GetPID(tc.TxActor)) txpoolSvr.Net = p2p.GetNetwork() - hserver.SetNetServer(p2p.GetNetwork()) + bactor.SetNetServer(p2p.GetNetwork()) p2p.WaitForPeersStart() log.Infof("P2P init success") return p2p, p2p.GetNetwork(), nil @@ -334,7 +339,7 @@ func initConsensus(ctx *cli.Context, net p2p.P2P, txpoolSvr *proc.TXPoolServer, consensusService.Start() netreqactor.SetConsensusPid(consensusService.GetPID()) - hserver.SetConsensusPid(consensusService.GetPID()) + bactor.SetConsensusPid(consensusService.GetPID()) log.Infof("Consensus init success") return consensusService, nil @@ -389,6 +394,15 @@ func initLocalRpc(ctx *cli.Context) error { return nil } +func initGraphQL(ctx *cli.Context) { + if !config.DefConfig.GraphQL.EnableGraphQL { + return + } + go graphql.StartServer(config.DefConfig.GraphQL) + + log.Infof("GraphQL init success") +} + func initRestful(ctx *cli.Context) { if !config.DefConfig.Restful.EnableHttpRestful { return @@ -408,7 +422,8 @@ func initWs(ctx *cli.Context) { } func initNodeInfo(ctx *cli.Context, p2pSvr *p2pserver.P2PServer) { - if config.DefConfig.P2PNode.HttpInfoPort == 0 { + // testmode has no p2pserver(see function initP2PNode for detail), simply ignore httpInfoPort in testmode + if ctx.Bool(utils.GetFlagName(utils.EnableTestModeFlag)) || config.DefConfig.P2PNode.HttpInfoPort == 0 { return } go nodeinfo.StartServer(p2pSvr.GetNetwork()) diff --git a/merkle/merkle_tree.go b/merkle/merkle_tree.go index 80a275298f..2850260c49 100644 --- a/merkle/merkle_tree.go +++ b/merkle/merkle_tree.go @@ -274,7 +274,7 @@ func (self *CompactMerkleTree) subproof(m, n uint32, b bool) []common.Uint256 { } //assert m == n - if b == false { + if !b { pos := getSubTreePos(n) //assert len(pos) == 1 if len(pos) != 1 { diff --git a/p2pserver/common/p2p_common.go b/p2pserver/common/p2p_common.go index 1adb2b8ce8..8a3e2880c5 100644 --- a/p2pserver/common/p2p_common.go +++ b/p2pserver/common/p2p_common.go @@ -117,6 +117,7 @@ const ( GET_SUBNET_MEMBERS_TYPE = "getmembers" // request subnet members SUBNET_MEMBERS_TYPE = "members" // response subnet members + SUBNET_OFFLINE_TYPE = "offline" // offline witness message ) //ParseIPAddr return ip address diff --git a/p2pserver/message/types/message.go b/p2pserver/message/types/message.go index ad16055650..3cc9279977 100644 --- a/p2pserver/message/types/message.go +++ b/p2pserver/message/types/message.go @@ -201,6 +201,8 @@ func makeEmptyMessage(cmdType string) Message { return &SubnetMembersRequest{} case common.SUBNET_MEMBERS_TYPE: return &SubnetMembers{} + case common.SUBNET_OFFLINE_TYPE: + return &OfflineWitnessMsg{} default: return &UnknownMessage{Cmd: cmdType} } diff --git a/p2pserver/message/types/offline_witness.go b/p2pserver/message/types/offline_witness.go new file mode 100644 index 0000000000..d45949b4e2 --- /dev/null +++ b/p2pserver/message/types/offline_witness.go @@ -0,0 +1,199 @@ +/* + * 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 . + */ + +package types + +import ( + "crypto/sha256" + "errors" + "math" + + "github.com/ontio/ontology/account" + "github.com/ontio/ontology/common" + vconfig "github.com/ontio/ontology/consensus/vbft/config" + "github.com/ontio/ontology/core/signature" + common2 "github.com/ontio/ontology/p2pserver/common" +) + +type OfflineWitnessMsg struct { + Timestamp uint32 `json:"timestamp"` + View uint32 `json:"view"` + NodePubKeys []string `json:"nodePubKeys"` + Proposer string `json:"proposer"` + + ProposerSig []byte `json:"proposerSig"` + + Voters []VoterMsg `json:"voters"` +} + +type VoterMsg struct { + OfflineIndex []uint8 `json:"offlineIndex"` + PubKey string `json:"pubKey"` + Sig []byte `json:"sig"` +} + +func (this *OfflineWitnessMsg) CmdType() string { + return common2.SUBNET_OFFLINE_TYPE +} + +func (self *OfflineWitnessMsg) Serialization(sink *common.ZeroCopySink) { + self.serializeUnsigned(sink) + sink.WriteVarBytes(self.ProposerSig) + + sink.WriteUint32(uint32(len(self.Voters))) + for _, val := range self.Voters { + sink.WriteVarBytes(val.OfflineIndex) + sink.WriteString(val.PubKey) + sink.WriteVarBytes(val.Sig) + } +} + +func (self *OfflineWitnessMsg) Deserialization(source *common.ZeroCopySource) (err error) { + self.Timestamp, err = source.ReadUint32() + if err != nil { + return err + } + self.View, err = source.ReadUint32() + if err != nil { + return err + } + lenPubKeys, err := source.ReadUint32() + if err != nil { + return err + } + if lenPubKeys > math.MaxUint8 { + return errors.New("too many node keys") + } + for i := uint32(0); i < lenPubKeys; i++ { + key, err := source.ReadString() + if err != nil { + return err + } + self.NodePubKeys = append(self.NodePubKeys, key) + } + + self.Proposer, err = source.ReadString() + if err != nil { + return err + } + + lenVoters, err := source.ReadUint32() + if err != nil { + return err + } + + for i := uint32(0); i < lenVoters; i++ { + index, err := source.ReadVarBytes() + if err != nil { + return err + } + for _, idx := range index { + if int(idx) >= len(self.NodePubKeys) { + return errors.New("vote index out of range") + } + } + pubKey, err := source.ReadString() + if err != nil { + return err + } + sig, err := source.ReadVarBytes() + if err != nil { + return err + } + + self.Voters = append(self.Voters, VoterMsg{OfflineIndex: index, PubKey: pubKey, Sig: sig}) + } + + return self.VerifySigs() +} + +func (self *OfflineWitnessMsg) serializeUnsigned(sink *common.ZeroCopySink) { + sink.WriteUint32(self.Timestamp) + sink.WriteUint32(self.View) + sink.WriteUint32(uint32(len(self.NodePubKeys))) + for _, key := range self.NodePubKeys { + sink.WriteString(key) + } + sink.WriteString(self.Proposer) +} + +func (self *OfflineWitnessMsg) Hash() common.Uint256 { + sink := common.NewZeroCopySink(nil) + self.serializeUnsigned(sink) + hash := common.Uint256(sha256.Sum256(sink.Bytes())) + + return hash +} + +func (self *OfflineWitnessMsg) AddProposeSig(acct *account.Account) error { + hash := self.Hash() + sig, err := signature.Sign(acct, hash[:]) + if err != nil { + return err + } + self.ProposerSig = sig + + return nil +} + +func (self *OfflineWitnessMsg) VoteFor(acct *account.Account, index []uint8) error { + sink := common.NewZeroCopySink(nil) + self.serializeUnsigned(sink) + sink.WriteVarBytes(index) + hash := common.Uint256(sha256.Sum256(sink.Bytes())) + sig, err := signature.Sign(acct, hash[:]) + if err != nil { + return err + } + pubkey := vconfig.PubkeyID(acct.PublicKey) + self.Voters = append(self.Voters, VoterMsg{OfflineIndex: index, PubKey: pubkey, Sig: sig}) + + return nil +} + +func (self *OfflineWitnessMsg) VerifySigs() error { + sink := common.NewZeroCopySink(nil) + self.serializeUnsigned(sink) + unsign := sink.Bytes() + data := sha256.Sum256(unsign) + prop, err := vconfig.Pubkey(self.Proposer) + if err != nil { + return err + } + + err = signature.Verify(prop, data[:], self.ProposerSig) + if err != nil { + return err + } + + for _, vote := range self.Voters { + sink = common.NewZeroCopySink(unsign) + sink.WriteVarBytes(vote.OfflineIndex) + data = sha256.Sum256(sink.Bytes()) + key, err := vconfig.Pubkey(vote.PubKey) + if err != nil { + return err + } + err = signature.Verify(key, data[:], vote.Sig) + if err != nil { + return err + } + } + + return nil +} diff --git a/p2pserver/mock/subnet_test.go b/p2pserver/mock/subnet_test.go index 2c1b03aa3b..97ac7ca48c 100644 --- a/p2pserver/mock/subnet_test.go +++ b/p2pserver/mock/subnet_test.go @@ -65,7 +65,7 @@ func TestSubnetAllGovAreSeed(t *testing.T) { net := NewNetwork() var nodes []*netserver.NetServer for i := 0; i < SG; i++ { - seedNode := NewSubnetNode(acct[0], seedList[i], seedList, gov, net, nil, "seedgov") + seedNode := NewSubnetNode(acct[i], seedList[i], seedList, gov, net, nil, "seedgov") go seedNode.Start() nodes = append(nodes, seedNode) } @@ -85,7 +85,7 @@ func TestSubnetAllGovAreSeed(t *testing.T) { //need some time for seed node detected it's identity time.Sleep(time.Second * 20) for i := 0; i < SG; i++ { - assert.Equal(t, len(getSubnetMemberInfo(nodes[i].Protocol())), SG, i) + assert.Equal(t, SG, len(getSubnetMemberInfo(nodes[i].Protocol())), i) } for i := 0; i < T; i++ { assert.Equal(t, uint32(T)-1, nodes[i].GetConnectionCnt(), i) @@ -123,7 +123,7 @@ func TestSubnet(t *testing.T) { net := NewNetwork() var nodes []*netserver.NetServer for i := 0; i < S; i++ { - seedNode := NewSubnetNode(acct[0], seedList[i], seedList, gov, net, nil, "seed") + seedNode := NewSubnetNode(acct[i], seedList[i], seedList, gov, net, nil, "seed") go seedNode.Start() nodes = append(nodes, seedNode) } diff --git a/p2pserver/net/netserver/nbr_peers.go b/p2pserver/net/netserver/nbr_peers.go index cb09bde876..a4250bfe8e 100644 --- a/p2pserver/net/netserver/nbr_peers.go +++ b/p2pserver/net/netserver/nbr_peers.go @@ -92,7 +92,7 @@ func (this *NbrPeers) Broadcast(msg types.Message) { defer this.RUnlock() for _, node := range this.List { if node.Peer.GetRelay() { - go node.Peer.SendRaw(msg.CmdType(), sink.Bytes()) + go node.Peer.SendRaw(sink.Bytes()) } } } diff --git a/p2pserver/peer/peer.go b/p2pserver/peer/peer.go index 260952eaf2..6b42b53969 100644 --- a/p2pserver/peer/peer.go +++ b/p2pserver/peer/peer.go @@ -140,7 +140,7 @@ func (this *Peer) GetPort() uint16 { } //SendTo call sync link to send buffer -func (this *Peer) SendRaw(msgType string, msgPayload []byte) error { +func (this *Peer) SendRaw(msgPayload []byte) error { return this.Link.SendRaw(msgPayload) } @@ -208,7 +208,7 @@ func (this *Peer) Send(msg types.Message) error { sink := comm.NewZeroCopySink(nil) types.WriteMessage(sink, msg) - return this.SendRaw(msg.CmdType(), sink.Bytes()) + return this.SendRaw(sink.Bytes()) } //GetHttpInfoPort return peer`s httpinfo port diff --git a/p2pserver/protocols/msg_handler.go b/p2pserver/protocols/msg_handler.go index 6033854762..f1b5d111c7 100644 --- a/p2pserver/protocols/msg_handler.go +++ b/p2pserver/protocols/msg_handler.go @@ -103,6 +103,8 @@ func (self *MsgHandler) start(net p2p.P2P) { go self.heatBeat.Start() go self.bootstrap.Start() go self.subnet.Start(net) + + RegisterProposeOfflineVote(self.subnet) } func (self *MsgHandler) stop() { @@ -173,6 +175,8 @@ func (self *MsgHandler) HandlePeerMessage(ctx *p2p.Context, msg msgTypes.Message self.subnet.OnMembersRequest(ctx, m) case *msgTypes.SubnetMembers: self.subnet.OnMembersResponse(ctx, m) + case *msgTypes.OfflineWitnessMsg: + self.subnet.OnOfflineWitnessMsg(ctx, m) case *msgTypes.NotFound: log.Debug("[p2p]receive notFound message, hash is ", m.Hash) default: diff --git a/p2pserver/protocols/rpcapi.go b/p2pserver/protocols/rpcapi.go new file mode 100644 index 0000000000..8faddf57ff --- /dev/null +++ b/p2pserver/protocols/rpcapi.go @@ -0,0 +1,54 @@ +/* + * 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 . + */ + +package protocols + +import ( + "github.com/ontio/ontology/http/base/error" + "github.com/ontio/ontology/http/base/rpc" + "github.com/ontio/ontology/p2pserver/protocols/subnet" +) + +func RegisterProposeOfflineVote(subnet *subnet.SubNet) { + // curl http://localhost:20337/local -v -d '{"method":"proposeOfflineVote", "params":["pubkey1", "pubkey2"]}' + rpc.HandleFunc("proposeOfflineVote", func(params []interface{}) map[string]interface{} { + var nodes []string + for _, key := range params { + switch pubKey := key.(type) { + case string: + nodes = append(nodes, pubKey) + default: + return rpc.ResponsePack(error.INVALID_PARAMS, "") + } + } + + err := subnet.ProposeOffline(nodes) + if err != nil { + return rpc.ResponsePack(error.INTERNAL_ERROR, err.Error()) + } + + return rpc.ResponseSuccess(nil) + }) + + // curl http://localhost:20337/local -v -d '{"method":"getOfflineVotes", "params":[]}' + rpc.HandleFunc("getOfflineVotes", func(params []interface{}) map[string]interface{} { + votes := subnet.GetOfflineVotes() + + return rpc.ResponseSuccess(votes) + }) +} diff --git a/p2pserver/protocols/subnet/offline_witness.go b/p2pserver/protocols/subnet/offline_witness.go new file mode 100644 index 0000000000..e9e9951151 --- /dev/null +++ b/p2pserver/protocols/subnet/offline_witness.go @@ -0,0 +1,241 @@ +/* + * 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 . + */ + +package subnet + +import ( + "errors" + "math/rand" + "time" + + common2 "github.com/ontio/ontology/common" + "github.com/ontio/ontology/common/log" + vconfig "github.com/ontio/ontology/consensus/vbft/config" + "github.com/ontio/ontology/p2pserver/common" + "github.com/ontio/ontology/p2pserver/message/types" + p2p "github.com/ontio/ontology/p2pserver/net/protocol" + "github.com/ontio/ontology/p2pserver/protocols/utils" +) + +const MinProposeDuration = uint32(1 * time.Hour / time.Second) +const ExpireOfflineMsgTime = uint32(2 * time.Hour / time.Second) +const DelayUpdateMsgTime = 5 * time.Second + +func (self *SubNet) ProposeOffline(nodes []string) error { + if self.acct == nil { + return errors.New("only consensus node can propose offline witness") + } + key := vconfig.PubkeyID(self.acct.PublicKey) + role, view := self.gov.GetNodeRoleAndView(key) + if role != utils.ConsensusNode { + return errors.New("only consensus node can propose offline witness") + } + now := uint32(time.Now().Unix()) + connected := make(map[string]bool) + for _, val := range self.GetMembersInfo() { + if val.Connected { + connected[val.PubKey] = true + } + } + var leftNodes []string + for _, node := range nodes { + if !self.gov.IsGovNode(node) { + continue + } + if !connected[node] { + leftNodes = append(leftNodes, node) + } + } + + if len(leftNodes) == 0 { + log.Info("do not send offline witness proposal since all nodes are online") + return nil + } + msg := &types.OfflineWitnessMsg{ + Timestamp: now, + View: view, + NodePubKeys: leftNodes, + Proposer: key, + } + err := msg.AddProposeSig(self.acct) + if err != nil { + return err + } + err = self.addProposol(msg) + if err != nil { + return err + } + + self.unparker.Unpark() + return nil +} + +func (self *SubNet) sendOfflineWitness(net p2p.P2P) { + var msgs []struct { + status WitnessStatus + rawMsg []byte + } + var peerIds []common.PeerId + now := uint32(time.Now().Unix()) + self.lock.RLock() + for hash, m := range self.offlineWitness { + if m.Msg.Timestamp+ExpireOfflineMsgTime < now { + delete(self.offlineWitness, hash) + } + if m.Status != UnchangedStatus { + rawMsg := common2.SerializeToBytes(m.Msg) + msgs = append(msgs, struct { + status WitnessStatus + rawMsg []byte + }{status: UnchangedStatus, rawMsg: rawMsg}) + } + } + for _, p := range self.connected { + peerIds = append(peerIds, p.Id) + } + self.lock.RUnlock() + + for _, msg := range msgs { + switch msg.status { + case NewStatus, UpdatedStatus: + for _, peerId := range peerIds { + if p := net.GetPeer(peerId); p != nil { + _ = p.SendRaw(msg.rawMsg) + } + } + } + } +} + +func (self *SubNet) Broadcast(net p2p.P2P, msg types.Message) { + self.lock.RLock() + defer self.lock.RUnlock() + for _, p := range self.connected { + net.SendTo(p.Id, msg) + } +} + +func (self *SubNet) OnOfflineWitnessMsg(ctx *p2p.Context, msg *types.OfflineWitnessMsg) { + status := self.processOfflineWitnessMsg(ctx, msg) + switch status { + case NewStatus: + self.unparker.Unpark() + case UpdatedStatus: + delay := int64(rand.Intn(1000)) * int64(DelayUpdateMsgTime) / 1000 + time.Sleep(time.Duration(delay)) + self.unparker.Unpark() + } +} + +func (self *SubNet) processOfflineWitnessMsg(ctx *p2p.Context, msg *types.OfflineWitnessMsg) WitnessStatus { + now := uint32(time.Now().Unix()) + hash := msg.Hash() + if msg.Timestamp+ExpireOfflineMsgTime < now { + self.logger.Infof("receive expired witness msg: %s", hash.ToHexString()) + return UnchangedStatus + } + role, view := self.gov.GetNodeRoleAndView(msg.Proposer) + if role != utils.ConsensusNode || view != msg.View { + self.logger.Infof("receive expired witness msg: %s, {role: %d, view: %d}, current view: %d", + hash.ToHexString(), role, msg.View, view) + return UnchangedStatus + } + + voters := make(map[string]types.VoterMsg) + for _, voter := range msg.Voters { + if !self.gov.IsGovNode(voter.PubKey) { + self.logger.Infof("receive witness msg: %s with wrong voter: %s", hash.ToHexString(), voter.PubKey) + return UnchangedStatus + } + voters[voter.PubKey] = voter + } + + self.lock.Lock() + defer self.lock.Unlock() + offline := self.offlineWitness[msg.Hash()] + if offline == nil { + govNode := self.acct != nil && self.gov.IsGovNodePubKey(self.acct.PublicKey) + if govNode { + err := msg.VoteFor(self.acct, self.collectOfflineIndexLocked(msg.NodePubKeys)) + if err != nil { + self.logger.Infof("vote for witness msg error: %s", err) + return UnchangedStatus + } + } + offline = &Offline{Status: NewStatus, Msg: msg} + self.offlineWitness[msg.Hash()] = offline + + return NewStatus + } + for _, vote := range offline.Msg.Voters { + delete(voters, vote.PubKey) + } + for _, voter := range voters { + offline.Msg.Voters = append(offline.Msg.Voters, voter) + offline.Status = UpdatedStatus + } + if len(voters) > 0 { + return UpdatedStatus + } + + return UnchangedStatus +} + +func (self *SubNet) collectOfflineIndexLocked(nodes []string) []uint8 { + connected := make(map[string]bool) + for _, val := range self.cleanAndGetMembersInfoLocked() { + if val.Connected { + connected[val.PubKey] = true + } + } + var leftNodes []uint8 + for idx, node := range nodes { + if !connected[node] { + leftNodes = append(leftNodes, uint8(idx)) + } + } + + return leftNodes +} + +func (self *SubNet) addProposol(msg *types.OfflineWitnessMsg) error { + self.lock.Lock() + defer self.lock.Unlock() + for _, m := range self.offlineWitness { + propose := m.Msg + if propose.Proposer == msg.Proposer && (msg.Timestamp < propose.Timestamp+MinProposeDuration) { + return errors.New("have already propose offline witness recently") + } + } + + self.offlineWitness[msg.Hash()] = &Offline{Status: NewStatus, Msg: msg} + return nil +} + +func (self *SubNet) GetOfflineVotes() []*types.OfflineWitnessMsg { + self.lock.RLock() + defer self.lock.RUnlock() + + var voters []*types.OfflineWitnessMsg + for _, m := range self.offlineWitness { + msg := *m.Msg + voters = append(voters, &msg) + } + + return voters +} diff --git a/p2pserver/protocols/subnet/subnet.go b/p2pserver/protocols/subnet/subnet.go index 86a65457b2..5dcb32a86d 100644 --- a/p2pserver/protocols/subnet/subnet.go +++ b/p2pserver/protocols/subnet/subnet.go @@ -26,6 +26,7 @@ import ( "time" "github.com/ontio/ontology/account" + common2 "github.com/ontio/ontology/common" vconfig "github.com/ontio/ontology/consensus/vbft/config" "github.com/ontio/ontology/p2pserver/common" "github.com/ontio/ontology/p2pserver/message/types" @@ -39,6 +40,17 @@ const MaxInactiveTime = 10 * time.Minute var RefreshDuration = 1 * time.Minute +type WitnessStatus = byte + +const NewStatus WitnessStatus = 0 +const UpdatedStatus WitnessStatus = 1 +const UnchangedStatus WitnessStatus = 2 + +type Offline struct { + Status WitnessStatus + Msg *types.OfflineWitnessMsg +} + type SubNet struct { acct *account.Account // nil if conenesus is not enabled seeds *utils.HostsResolver @@ -50,9 +62,10 @@ type SubNet struct { seedNode uint32 // bool acturally closed bool - connected map[string]*peer.PeerInfo // connected seed or gov node, listen address --> PeerInfo - members map[string]*MemberStatus // gov node info, listen address --> pubkey hex string - logger common.Logger + connected map[string]*peer.PeerInfo // connected seed/gov node, listenAddr --> PeerInfo + members map[string]*MemberStatus // gov node info, listenAddr --> pubkey hex string + offlineWitness map[common2.Uint256]*Offline // hash -> msg + logger common.Logger } func NewSubNet(acc *account.Account, seeds *utils.HostsResolver, @@ -64,8 +77,9 @@ func NewSubNet(acc *account.Account, seeds *utils.HostsResolver, unparker: utils.NewParker(), logger: logger, - connected: make(map[string]*peer.PeerInfo), - members: make(map[string]*MemberStatus), + connected: make(map[string]*peer.PeerInfo), + members: make(map[string]*MemberStatus), + offlineWitness: make(map[common2.Uint256]*Offline), } } @@ -187,10 +201,11 @@ func (self *SubNet) OnMembersRequest(ctx *p2p.Context, msg *types.SubnetMembersR } self.lock.Lock() - members := make([]types.MemberInfo, 0, len(self.members)) + memberInfos := self.cleanAndGetMembersInfoLocked() + members := make([]types.MemberInfo, 0, len(memberInfos)) - for addr, status := range self.members { - members = append(members, types.MemberInfo{PubKey: status.PubKey, Addr: addr}) + for _, info := range memberInfos { + members = append(members, types.MemberInfo{PubKey: info.PubKey, Addr: info.ListenAddr}) } //update self.members @@ -356,10 +371,17 @@ func (self *SubNet) maintainLoop(net p2p.P2P) { self.cleanInactiveGovNode() if seedOrGov { + self.sendOfflineWitness(net) + self.sendMembersRequestToRandNodes(net) members := self.GetMembersInfo() buf, _ := json.Marshal(members) self.logger.Infof("[subnet] current members: %s", string(buf)) + votes := self.GetOfflineVotes() + if len(votes) != 0 { + buf, _ = json.Marshal(votes) + self.logger.Infof("[subnet] current offline votes: %s", string(buf)) + } } parker.ParkTimeout(RefreshDuration) @@ -382,12 +404,10 @@ func (self *SubNet) GetMaskAddrFilter() p2p.AddressFilter { } } -//restful api -func (self *SubNet) GetMembersInfo() []common.SubnetMemberInfo { - self.lock.RLock() - defer self.lock.RUnlock() - - var members []common.SubnetMemberInfo +// some gov node may change its listen ip address, +// this function will try to remove old address +func (self *SubNet) cleanAndGetMembersInfoLocked() map[string]common.SubnetMemberInfo { + members := make(map[string]common.SubnetMemberInfo) for addr, mem := range self.members { connected := self.selfAddr == addr height := uint64(0) @@ -397,14 +417,43 @@ func (self *SubNet) GetMembersInfo() []common.SubnetMemberInfo { height = p.Height() version = p.SoftVersion } - members = append(members, common.SubnetMemberInfo{ + + curr := common.SubnetMemberInfo{ PubKey: mem.PubKey, ListenAddr: addr, Connected: connected, Height: height, Version: version, - }) + } + + prev, ok := members[mem.PubKey] + if !ok { + members[mem.PubKey] = curr + } else { // already has one item + if connected && !prev.Connected { // delete prev if curr is connected, but prev is not + delete(self.members, prev.ListenAddr) + members[mem.PubKey] = curr + } else if prev.Connected && !connected { // delete curr if prev is connected, but curr is not + delete(self.members, addr) + } + + // keep both if both not connected, (both connected is not possible because of p2p handshake) + } } return members } + +//restful api +func (self *SubNet) GetMembersInfo() []common.SubnetMemberInfo { + self.lock.Lock() + members := self.cleanAndGetMembersInfoLocked() + self.lock.Unlock() + + result := make([]common.SubnetMemberInfo, 0, len(members)) + for _, info := range members { + result = append(result, info) + } + + return result +} diff --git a/p2pserver/protocols/utils/govnode_resolver.go b/p2pserver/protocols/utils/govnode_resolver.go index dc20ffb5aa..1d7da29cf9 100644 --- a/p2pserver/protocols/utils/govnode_resolver.go +++ b/p2pserver/protocols/utils/govnode_resolver.go @@ -37,9 +37,18 @@ import ( const GovNodeCacheTime = time.Minute * 10 +type NodeRole byte + +const ( + SyncNode NodeRole = iota + CandidateNode = iota + ConsensusNode = iota +) + type GovNodeResolver interface { IsGovNodePubKey(key keypair.PublicKey) bool IsGovNode(key string) bool + GetNodeRoleAndView(key string) (NodeRole, uint32) } type GovNodeMockResolver struct { @@ -61,6 +70,15 @@ func (self *GovNodeMockResolver) IsGovNode(key string) bool { return ok } +func (self *GovNodeMockResolver) GetNodeRoleAndView(key string) (NodeRole, uint32) { + _, ok := self.govNode[key] + if ok { + return CandidateNode, 0 + } + + return SyncNode, 0 +} + func (self *GovNodeMockResolver) IsGovNodePubKey(key keypair.PublicKey) bool { pubKey := vconfig.PubkeyID(key) _, ok := self.govNode[pubKey] @@ -78,13 +96,13 @@ type GovCache struct { view uint32 refreshTime time.Time govNodeNum uint32 - pubkeys map[string]struct{} + pubkeys map[string]bool } func NewGovNodeResolver(db *ledger.Ledger) *GovNodeLedgerResolver { return &GovNodeLedgerResolver{ db: db, - cache: unsafe.Pointer(&GovCache{pubkeys: make(map[string]struct{})}), + cache: unsafe.Pointer(&GovCache{pubkeys: make(map[string]bool)}), } } @@ -94,29 +112,46 @@ func (self *GovNodeLedgerResolver) IsGovNodePubKey(key keypair.PublicKey) bool { } func (self *GovNodeLedgerResolver) IsGovNode(pubKey string) bool { + role, _ := self.GetNodeRoleAndView(pubKey) + + return role != SyncNode +} + +func (self *GovNodeLedgerResolver) GetNodeRoleAndView(pubKey string) (NodeRole, uint32) { view, err := GetGovernanceView(self.db) if err != nil { log.Warnf("[subnet] gov node resolver failed to load view from ledger, err: %v", err) - return false + return SyncNode, 0 } cached := (*GovCache)(atomic.LoadPointer(&self.cache)) if cached != nil && view.View == cached.view && cached.refreshTime.Add(GovNodeCacheTime).After(time.Now()) { - _, ok := cached.pubkeys[pubKey] - return ok + cons, ok := cached.pubkeys[pubKey] + if !ok { + return SyncNode, 0 + } + if cons { + return ConsensusNode, view.View + } + + return CandidateNode, view.View } - govNode := false + nodeRole := SyncNode peers, count, err := GetPeersConfig(self.db, view.View) if err != nil { log.Warnf("[subnet] gov node resolver failed to load peers from ledger, err: %v", err) - return false + return SyncNode, view.View } - pubkeys := make(map[string]struct{}, len(peers)) + pubkeys := make(map[string]bool, len(peers)) for _, peer := range peers { - pubkeys[peer.PeerPubkey] = struct{}{} + pubkeys[peer.PeerPubkey] = peer.ConsNode if peer.PeerPubkey == pubKey { - govNode = true + if peer.ConsNode { + nodeRole = ConsensusNode + } else { + nodeRole = CandidateNode + } } } @@ -130,7 +165,7 @@ func (self *GovNodeLedgerResolver) IsGovNode(pubKey string) bool { view: view.View, })) - return govNode + return nodeRole, view.View } func GetGovernanceView(backend *ledger.Ledger) (*governance.GovernanceView, error) { @@ -146,7 +181,12 @@ func GetGovernanceView(backend *ledger.Ledger) (*governance.GovernanceView, erro return governanceView, nil } -func GetPeersConfig(backend *ledger.Ledger, view uint32) ([]*config.VBFTPeerStakeInfo, uint32, error) { +type GovNodeInfo struct { + ConsNode bool + *config.VBFTPeerStakeInfo +} + +func GetPeersConfig(backend *ledger.Ledger, view uint32) ([]*GovNodeInfo, uint32, error) { viewBytes := governance.GetUint32Bytes(view) key := append([]byte(governance.PEER_POOL), viewBytes...) data, err := backend.GetStorageItem(utils.GovernanceContractAddress, key) @@ -162,8 +202,9 @@ func GetPeersConfig(backend *ledger.Ledger, view uint32) ([]*config.VBFTPeerStak } govCount := uint32(0) - var peerstakes []*config.VBFTPeerStakeInfo + var peerstakes []*GovNodeInfo for _, id := range peerMap.PeerPoolMap { + isConsensus := id.Status == governance.ConsensusStatus || id.Status == governance.QuitConsensusStatus switch id.Status { case governance.CandidateStatus, governance.ConsensusStatus, governance.QuitConsensusStatus: conf := &config.VBFTPeerStakeInfo{ @@ -171,9 +212,12 @@ func GetPeersConfig(backend *ledger.Ledger, view uint32) ([]*config.VBFTPeerStak PeerPubkey: id.PeerPubkey, InitPos: id.InitPos + id.TotalPos, } - peerstakes = append(peerstakes, conf) + peerstakes = append(peerstakes, &GovNodeInfo{ + ConsNode: isConsensus, + VBFTPeerStakeInfo: conf, + }) } - if id.Status == governance.ConsensusStatus || id.Status == governance.QuitConsensusStatus { + if isConsensus { govCount += 1 } } diff --git a/smartcontract/service/native/governance/method.go b/smartcontract/service/native/governance/method.go index d0a07e140c..aa4f82c56b 100644 --- a/smartcontract/service/native/governance/method.go +++ b/smartcontract/service/native/governance/method.go @@ -375,7 +375,7 @@ func normalQuit(native *native.NativeService, contract common.Address, peerPoolI if err := iter.Error(); err != nil { return err } - if flag == false { + if !flag { authorizeInfo := &AuthorizeInfo{ PeerPubkey: peerPoolItem.PeerPubkey, Address: peerPoolItem.Address, @@ -1416,7 +1416,7 @@ func splitNodeFee(native *native.NativeService, contract common.Address, peerPub } var amount uint64 if native.Height > config.GetNewPeerCostHeight() { - stakeFee := new(big.Int).Sub( + stakeFee := new(big.Int).Div( new(big.Int).Mul(new(big.Int).SetUint64(nodeAmount), new(big.Int).SetUint64(totalPos)), new(big.Int).Add(new(big.Int).SetUint64(initPos), new(big.Int).SetUint64(totalPos))).Uint64() nodeFee := nodeAmount - stakeFee diff --git a/smartcontract/service/native/native_service.go b/smartcontract/service/native/native_service.go index 9b10226c3d..f4a31725de 100644 --- a/smartcontract/service/native/native_service.go +++ b/smartcontract/service/native/native_service.go @@ -29,7 +29,6 @@ import ( "github.com/ontio/ontology/smartcontract/context" "github.com/ontio/ontology/smartcontract/event" "github.com/ontio/ontology/smartcontract/states" - sstates "github.com/ontio/ontology/smartcontract/states" "github.com/ontio/ontology/smartcontract/storage" ) @@ -49,7 +48,7 @@ type NativeService struct { CacheDB *storage.CacheDB ServiceMap map[string]Handler Notifications []*event.NotifyEventInfo - InvokeParam sstates.ContractInvokeParam + InvokeParam states.ContractInvokeParam Input []byte Tx *types.Transaction Height uint32 diff --git a/smartcontract/service/native/ong/ong.go b/smartcontract/service/native/ong/ong.go index 4daef89468..0c8640a993 100644 --- a/smartcontract/service/native/ong/ong.go +++ b/smartcontract/service/native/ong/ong.go @@ -97,7 +97,7 @@ func OngApprove(native *native.NativeService) ([]byte, error) { if state.Value > constants.ONG_TOTAL_SUPPLY { return utils.BYTE_FALSE, fmt.Errorf("approve ong amount:%d over totalSupply:%d", state.Value, constants.ONG_TOTAL_SUPPLY) } - if native.ContextRef.CheckWitness(state.From) == false { + if !native.ContextRef.CheckWitness(state.From) { return utils.BYTE_FALSE, errors.NewErr("authentication failed!") } contract := native.ContextRef.CurrentContext().ContractAddress diff --git a/smartcontract/service/native/ont/ont.go b/smartcontract/service/native/ont/ont.go index 09d93cece5..a1dba581a5 100644 --- a/smartcontract/service/native/ont/ont.go +++ b/smartcontract/service/native/ont/ont.go @@ -183,7 +183,7 @@ func OntApprove(native *native.NativeService) ([]byte, error) { if state.Value > constants.ONT_TOTAL_SUPPLY { return utils.BYTE_FALSE, fmt.Errorf("approve ont amount:%d over totalSupply:%d", state.Value, constants.ONT_TOTAL_SUPPLY) } - if native.ContextRef.CheckWitness(state.From) == false { + if !native.ContextRef.CheckWitness(state.From) { return utils.BYTE_FALSE, errors.NewErr("authentication failed!") } contract := native.ContextRef.CurrentContext().ContractAddress diff --git a/smartcontract/service/native/ontfs/app_sdk.go b/smartcontract/service/native/ontfs/app_sdk.go index cd2398da99..00b6e62d7d 100644 --- a/smartcontract/service/native/ontfs/app_sdk.go +++ b/smartcontract/service/native/ontfs/app_sdk.go @@ -859,7 +859,7 @@ func FsTransferFiles(native *native.NativeService) ([]byte, error) { } for _, fileTransfer := range fileTransferList.FilesTransfer { - if native.ContextRef.CheckWitness(fileTransfer.OriOwner) == false { + if !native.ContextRef.CheckWitness(fileTransfer.OriOwner) { errInfos.AddObjectError(string(fileTransfer.FileHash), "[APP SDK] FsTransferFiles CheckFileOwner failed!") continue } diff --git a/smartcontract/service/native/ontid/event.go b/smartcontract/service/native/ontid/event.go index 2fd2cd2ebc..5bb18ce5c6 100644 --- a/smartcontract/service/native/ontid/event.go +++ b/smartcontract/service/native/ontid/event.go @@ -30,7 +30,6 @@ func newEvent(srvc *native.NativeService, st interface{}) { e.ContractAddress = srvc.ContextRef.CurrentContext().ContractAddress e.States = st srvc.Notifications = append(srvc.Notifications, &e) - return } func triggerRegisterEvent(srvc *native.NativeService, id []byte) { diff --git a/smartcontract/service/native/ontid/init.go b/smartcontract/service/native/ontid/init.go index 135398dd6c..faa8b9c13e 100644 --- a/smartcontract/service/native/ontid/init.go +++ b/smartcontract/service/native/ontid/init.go @@ -83,5 +83,4 @@ func RegisterIDContract(srvc *native.NativeService) { srvc.Register("getServiceJson", GetServiceJson) srvc.Register("getControllerJson", GetControllerJson) srvc.Register("getDocumentJson", GetDocumentJson) - return } diff --git a/smartcontract/service/native/ontid/method.go b/smartcontract/service/native/ontid/method.go index 79379e5add..6371882e1a 100644 --- a/smartcontract/service/native/ontid/method.go +++ b/smartcontract/service/native/ontid/method.go @@ -315,6 +315,9 @@ func removeKey(srvc *native.NativeService) ([]byte, error) { } var auth = false rec, err := getOldRecovery(srvc, key) + if err != nil { + return utils.BYTE_FALSE, err + } if len(rec) > 0 { auth = bytes.Equal(rec, arg2) } diff --git a/smartcontract/service/native/utils/operation.go b/smartcontract/service/native/utils/operation.go index 29418b0f10..08787dccbc 100644 --- a/smartcontract/service/native/utils/operation.go +++ b/smartcontract/service/native/utils/operation.go @@ -45,7 +45,7 @@ func ConcatBytes(args ...[]byte) []byte { } func ValidateOwner(native *native.NativeService, address common.Address) error { - if native.ContextRef.CheckWitness(address) == false { + if !native.ContextRef.CheckWitness(address) { return errors.NewErr("validateOwner, authentication failed!") } return nil diff --git a/smartcontract/service/native/utils/serialization.go b/smartcontract/service/native/utils/serialization.go index 8b5d123a2b..fd265e757c 100644 --- a/smartcontract/service/native/utils/serialization.go +++ b/smartcontract/service/native/utils/serialization.go @@ -45,6 +45,7 @@ func EncodeString(sink *common.ZeroCopySink, str string) (size uint64) { func EncodeBool(sink *common.ZeroCopySink, value bool) { sink.WriteBool(value) } + func DecodeVarUint(source *common.ZeroCopySource) (uint64, error) { value, _, irregular, eof := source.NextVarBytes() if eof { diff --git a/smartcontract/service/neovm/runtime.go b/smartcontract/service/neovm/runtime.go index f340d06815..e9f0dea150 100644 --- a/smartcontract/service/neovm/runtime.go +++ b/smartcontract/service/neovm/runtime.go @@ -155,6 +155,9 @@ func RuntimeNotify(service *NeoVmService, engine *vm.Executor) error { // RuntimeLog push smart contract execute event log to client func RuntimeLog(service *NeoVmService, engine *vm.Executor) error { sitem, err := engine.EvalStack.Peek(0) + if err != nil { + return err + } item, err := engine.EvalStack.PopAsBytes() if err != nil { return err diff --git a/smartcontract/service/neovm/wasmvm.go b/smartcontract/service/neovm/wasmvm.go index e0dbe89f94..ec05d31661 100644 --- a/smartcontract/service/neovm/wasmvm.go +++ b/smartcontract/service/neovm/wasmvm.go @@ -63,7 +63,7 @@ func WASMInvoke(service *NeoVmService, engine *vm.Executor) error { } params, ok := list.([]interface{}) - if ok == false { + if !ok { return fmt.Errorf("wasm invoke error: wrong param type:%s", reflect.TypeOf(list).String()) } diff --git a/smartcontract/service/util/util.go b/smartcontract/service/util/util.go index 30a9726681..149e1b06e3 100644 --- a/smartcontract/service/util/util.go +++ b/smartcontract/service/util/util.go @@ -52,7 +52,7 @@ func GenerateNeoVMParamEvalStack(input []byte) (*neovm.ValueStack, error) { } list, ok := params.([]interface{}) - if ok == false { + if !ok { return nil, errors.New("invoke neovm param is not list type") } @@ -66,7 +66,7 @@ func GenerateNeoVMParamEvalStack(input []byte) (*neovm.ValueStack, error) { func SetNeoServiceParamAndEngine(addr common.Address, engine context.Engine, stack *neovm.ValueStack) error { service, ok := engine.(*neovms.NeoVmService) - if ok == false { + if !ok { return errors.New("engine should be NeoVmService") } diff --git a/smartcontract/service/wasmvm/contract.go b/smartcontract/service/wasmvm/contract.go index b9aa6403fc..b96bf37739 100644 --- a/smartcontract/service/wasmvm/contract.go +++ b/smartcontract/service/wasmvm/contract.go @@ -136,6 +136,9 @@ func ContractCreate(proc *exec.Process, self.Service.CacheDB.PutContract(dep) length, err := proc.WriteAt(contractAddr[:], int64(newAddressPtr)) + if err != nil { + panic(err) + } return uint32(length) } diff --git a/smartcontract/service/wasmvm/runtime.go b/smartcontract/service/wasmvm/runtime.go index 8980b099f7..5cc616fd20 100644 --- a/smartcontract/service/wasmvm/runtime.go +++ b/smartcontract/service/wasmvm/runtime.go @@ -604,7 +604,7 @@ func getContractTypeInner(service *WasmVmService, addr common.Address) (Contract return UNKOWN_CONTRACT, err } if dep == nil { - return UNKOWN_CONTRACT, errors.NewErr("contract is not exist.") + return UNKOWN_CONTRACT, fmt.Errorf("contract %s is not exist", addr.ToHexString()) } if dep.VmType() == payload.WASMVM_TYPE { return WASMVM_CONTRACT, nil diff --git a/smartcontract/service/wasmvm/utils.go b/smartcontract/service/wasmvm/utils.go index ebc261f70e..3a9558c838 100644 --- a/smartcontract/service/wasmvm/utils.go +++ b/smartcontract/service/wasmvm/utils.go @@ -55,7 +55,7 @@ func checkOntoWasm(m *wasm.Module) error { } entry, ok := m.Export.Entries["invoke"] - if ok == false { + if !ok { return errors.New("[Validate] invoke entry function does not export.") } diff --git a/smartcontract/service/wasmvm/wasm_service.go b/smartcontract/service/wasmvm/wasm_service.go index 6a2e35a5d6..38a64e8c0b 100644 --- a/smartcontract/service/wasmvm/wasm_service.go +++ b/smartcontract/service/wasmvm/wasm_service.go @@ -198,7 +198,7 @@ func invokeInterpreter(this *WasmVmService, contract *states.WasmContractParam, entry, ok := compiled.RawModule.Export.Entries[entryName] - if ok == false { + if !ok { return nil, errors.NewErr("[Call]Method:" + entryName + " does not exist!") } diff --git a/smartcontract/states/contract.go b/smartcontract/states/contract.go index bec34b03f4..e43930538f 100644 --- a/smartcontract/states/contract.go +++ b/smartcontract/states/contract.go @@ -48,9 +48,18 @@ func (this *ContractInvokeParam) Serialization(sink *common.ZeroCopySink) { func (this *ContractInvokeParam) Deserialization(source *common.ZeroCopySource) error { var irregular, eof bool this.Version, eof = source.NextByte() + if eof { + return io.ErrUnexpectedEOF + } this.Address, eof = source.NextAddress() + if eof { + return io.ErrUnexpectedEOF + } var method []byte method, _, irregular, eof = source.NextVarBytes() + if eof { + return io.ErrUnexpectedEOF + } if irregular { return common.ErrIrregularData } diff --git a/smartcontract/states/wasmContract.go b/smartcontract/states/wasmContract.go index 411746dc8a..723133052a 100644 --- a/smartcontract/states/wasmContract.go +++ b/smartcontract/states/wasmContract.go @@ -38,6 +38,9 @@ func (this *WasmContractParam) Serialization(sink *common.ZeroCopySink) { func (this *WasmContractParam) Deserialization(source *common.ZeroCopySource) error { var irregular, eof bool this.Address, eof = source.NextAddress() + if eof { + return io.ErrUnexpectedEOF + } this.Args, _, irregular, eof = source.NextVarBytes() if irregular { diff --git a/txnpool/proc/txnpool_server.go b/txnpool/proc/txnpool_server.go index c40ee6a04b..c293cf6c6b 100644 --- a/txnpool/proc/txnpool_server.go +++ b/txnpool/proc/txnpool_server.go @@ -611,9 +611,8 @@ func (s *TXPoolServer) getStats() []uint64 { s.stats.RLock() defer s.stats.RUnlock() ret := make([]uint64, 0, len(s.stats.count)) - for _, v := range s.stats.count { - ret = append(ret, v) - } + ret = append(ret, s.stats.count...) + return ret } diff --git a/vm/crossvm_codec/notify_codec.go b/vm/crossvm_codec/notify_codec.go index c1bdfd74c4..b9858a9386 100644 --- a/vm/crossvm_codec/notify_codec.go +++ b/vm/crossvm_codec/notify_codec.go @@ -65,7 +65,7 @@ func stringify(notify interface{}) interface{} { // input byte array should be the following format // evt\0(4byte) + type(1byte) + usize( bytearray or list) (4 bytes) + data... func parseNotify(input []byte) (interface{}, error) { - if bytes.HasPrefix(input, []byte("evt\x00")) == false { + if !bytes.HasPrefix(input, []byte("evt\x00")) { return nil, ERROR_PARAM_FORMAT } diff --git a/vm/crossvm_codec/vmcall_codec.go b/vm/crossvm_codec/vmcall_codec.go index 340c73c510..7727b71eec 100644 --- a/vm/crossvm_codec/vmcall_codec.go +++ b/vm/crossvm_codec/vmcall_codec.go @@ -27,7 +27,7 @@ import ( //input byte array should be the following format // version(1byte) + type(1byte) + data... func DeserializeCallParam(input []byte) (interface{}, error) { - if bytes.HasPrefix(input, []byte{0}) == false { + if !bytes.HasPrefix(input, []byte{0}) { return nil, ERROR_PARAM_FORMAT } diff --git a/vm/neovm/executor.go b/vm/neovm/executor.go index 91ac078bae..41eb78356c 100644 --- a/vm/neovm/executor.go +++ b/vm/neovm/executor.go @@ -877,7 +877,7 @@ func (self *Executor) ExecuteOp(opcode OpCode, context *ExecutionContext) (VMSta value, ok, err := mapVal.Get(index) if err != nil { return FAULT, err - } else if ok == false { + } else if !ok { // todo: suply a nil value in vm? return FAULT, errors.ERR_MAP_NOT_EXIST } diff --git a/vm/neovm/types/int_value.go b/vm/neovm/types/int_value.go index 3013fc046b..45e2126c55 100644 --- a/vm/neovm/types/int_value.go +++ b/vm/neovm/types/int_value.go @@ -36,14 +36,14 @@ type IntValue struct { func (self IntValue) Rsh(other IntValue) (result IntValue, err error) { var val uint64 - if other.isbig == false { + if !other.isbig { if other.integer < 0 { err = errors.ERR_SHIFT_BY_NEG return } val = uint64(other.integer) } else { - if other.bigint.IsUint64() == false { + if !other.bigint.IsUint64() { return IntValue{}, errors.ERR_SHIFT_BY_NEG } val = other.bigint.Uint64() @@ -71,14 +71,14 @@ func (self IntValue) Rsh(other IntValue) (result IntValue, err error) { func (self IntValue) Lsh(other IntValue) (result IntValue, err error) { var val uint64 - if other.isbig == false { + if !other.isbig { if other.integer < 0 { err = errors.ERR_SHIFT_BY_NEG return } val = uint64(other.integer) } else { - if other.bigint.IsUint64() == false { + if !other.bigint.IsUint64() { return IntValue{}, errors.ERR_SHIFT_BY_NEG } val = other.bigint.Uint64() @@ -127,7 +127,7 @@ func IntValFromNeoBytes(val []byte) (IntValue, error) { func (self *IntValue) ToNeoBytes() []byte { val := self.bigint - if self.isbig == false { + if !self.isbig { val = big.NewInt(self.integer) } value := common.BigIntToNeoBytes(val) @@ -221,7 +221,7 @@ func (self IntValue) Or(other IntValue) (IntValue, error) { } func (self IntValue) Cmp(other IntValue) int { - if self.isbig == false && other.isbig == false { + if !self.isbig && !other.isbig { if self.integer < other.integer { return -1 } else if self.integer == other.integer { @@ -231,12 +231,12 @@ func (self IntValue) Cmp(other IntValue) int { } } var left, right *big.Int - if self.isbig == false { + if !self.isbig { left = big.NewInt(self.integer) } else { left = self.bigint } - if other.isbig == false { + if !other.isbig { right = big.NewInt(other.integer) } else { right = other.bigint @@ -321,19 +321,19 @@ type overflowFn func(a, b int64) (result int64, ok bool) type bigintFn func(a, b *big.Int) (IntValue, error) func (self IntValue) intOp(other IntValue, littleintFunc overflowFn, bigintFunc bigintFn) (IntValue, error) { - if self.isbig == false && other.isbig == false { + if !self.isbig && !other.isbig { val, ok := littleintFunc(self.integer, other.integer) if ok { return IntValFromInt(val), nil } } var left, right *big.Int - if self.isbig == false { + if !self.isbig { left = big.NewInt(self.integer) } else { left = self.bigint } - if other.isbig == false { + if !other.isbig { right = big.NewInt(other.integer) } else { right = other.bigint diff --git a/vm/neovm/types/neovm_value.go b/vm/neovm/types/neovm_value.go index 3c61d8184d..f63e53defe 100644 --- a/vm/neovm/types/neovm_value.go +++ b/vm/neovm/types/neovm_value.go @@ -556,7 +556,7 @@ func (self *VmValue) AsInt64() (int64, error) { return 0, err } if val.isbig { - if val.bigint.IsInt64() == false { + if !val.bigint.IsInt64() { return 0, errors.ERR_INTEGER_UNDERFLOW } return val.bigint.Int64(), nil