diff --git a/.gitignore b/.gitignore index ac65035a24fb42330e2c00534018a93b42dfbf57..85712b3e38a94b6f02d668b97cfef6c960dbc4d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin *.log *.log.* -cover.out \ No newline at end of file +cover.out +test \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000000000000000000000000000000000..f4255d56efff964c6ffac682237836c0bbcbcca3 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,133 @@ + +run: + timeout: 10m + tests: true + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: true + # skip-files: + skip-dirs: + - p2p #from libp2p + - mock #from gomock + - protogo #from pb generate + - sqldbprovider #will remove + - eventsqldb + - evm-go + - gasm-go + - wasmer-go +linters: + disable-all: true + enable: + - deadcode + - goconst + - gocyclo + - gofmt + - ineffassign + - staticcheck + - structcheck # 当非导出结构嵌入另一个结构, 前一个结构被使用就不会监测到, 这个需要每个业务自己屏蔽 + - typecheck + - goimports + - revive + - gosimple + - govet + - lll + - rowserrcheck + - errcheck + - misspell + - unused + - varcheck + - sqlclosecheck + - gosec + + +linters-settings: + goconst: + min-len: 2 + min-occurrences: 2 + gocyclo: + min-complexity: 20 + goimports: + #local-prefixes: git.code.oa.com + golint: + #min-confidence: 0 + govet: + check-shadowing: true + gosimple: + go: "1.15" + lll: + line-length: 120 + errcheck: + check-type-assertions: true + gocritic: + enabled-checks: + - nestingReduce + settings: + nestingReduce: + bodyWidth: 5 + revive: + # see https://github.com/mgechev/revive#available-rules for details. + rules: + # - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + # - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + # - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unexported-naming + - name: unexported-return + - name: unreachable-code + - name: redefines-builtin-id + - name: function-length + arguments: [ 80,0 ] + +issues: + exclude-use-default: true + include: + - EXC0002 # golint (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form) + - EXC0003 # golint func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this + #- EXC0004 # govet (possible misuse of unsafe.Pointer|should have signature) + - EXC0005 # staticcheck ineffective break statement. Did you mean to break out of the outer loop + - EXC0011 # stylecheck (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form) + + exclude-rules: + - path: .*_test.go + linters: + - unused + - deadcode + - ineffassign + - staticcheck + - forbidigo + - dupl + - errcheck + - lll + - funlen + - linters: + - revive + text: "stutters" + - linters: + - errcheck + text: "json.Unmarshal" + - linters: + - gosec + text: "G108|G204|G501|G401" + max-same-issues: 0 + new: false + max-issues-per-linter: 0 + +output: + sort-results: true \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9c8f3ea0871e0bfe81da0fa6e7c1d7d156dc380e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4367bdcd59307e83e9596b161a023295f9eb849b --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +VERSION=v2.2.0_alpha_qc +VERSION_DEVELOP=develop + +gomod: + go get chainmaker.org/chainmaker/pb-go/v2@$(VERSION) + go get chainmaker.org/chainmaker/common/v2@$(VERSION_DEVELOP) + go get chainmaker.org/chainmaker/protocol/v2@$(VERSION) + go get chainmaker.org/chainmaker/logger/v2@$(VERSION_DEVELOP) + go get chainmaker.org/chainmaker/utils/v2@$(VERSION) + go get chainmaker.org/chainmaker/localconf/v2@$(VERSION) + go get chainmaker.org/chainmaker/chainconf/v2@$(VERSION) + go mod tidy + +lint: + golangci-lint run ./... + +ut: + mkdir -p ../ut-vm-native + go test -v -coverprofile=../ut-vm-native/cover.out ./... + go tool cover -html=../ut-vm-native/cover.out -o ../ut-vm-native/coverage.html \ No newline at end of file diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000000000000000000000000000000000000..82a4ba1845e7573f88f455a31eb37c4839cc941e --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +长安链·ChainMaker + +Copyright 2021 contributors to 长安链·ChainMaker \ No newline at end of file diff --git a/accountmgr/account_manager.go b/accountmgr/account_manager.go new file mode 100644 index 0000000000000000000000000000000000000000..081bcbea6bd339f1062327626fe7f165c8c1cfd8 --- /dev/null +++ b/accountmgr/account_manager.go @@ -0,0 +1,823 @@ +/* +Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package accountmgr + +import ( + "encoding/hex" + "errors" + "fmt" + "strconv" + "strings" + + "chainmaker.org/chainmaker/common/v2/crypto/asym" + "chainmaker.org/chainmaker/common/v2/evmutils" + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + configPb "chainmaker.org/chainmaker/pb-go/v2/config" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/chainconfigmgr" + "chainmaker.org/chainmaker/vm-native/v2/common" +) + +const ( + AccountPrefix = "__account_prefix__" + FrozenPrefix = "__frozen_account__" + AddressKey = "address_key" + BatchRecharge = "batch_recharge" + RechargeKey = "recharge_key" + RechargeAmountKey = "recharge_amount_key" + ChargePublicKey = "charge_public_key" + ChargeGasAmount = "charge_gas_amount" + Success = "success" + emptyString = "" + addressIllegal = "account address is illegal" + int64OverFlow = "int64 is overflow" + unlock = "0" + locked = "1" +) + +type AccountManager struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewAccountManager(log protocol.Logger) *AccountManager { + return &AccountManager{ + log: log, + methods: registerGasAccountContractMethods(log), + } +} + +func (g *AccountManager) GetMethod(methodName string) common.ContractFunc { + return g.methods[methodName] +} + +func registerGasAccountContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + gasAccountRuntime := &AccountManagerRuntime{log: log} + + methodMap[syscontract.GasAccountFunction_SET_ADMIN.String()] = common.WrapResultFunc( + gasAccountRuntime.SetAdmin) + methodMap[syscontract.GasAccountFunction_GET_ADMIN.String()] = common.WrapResultFunc( + gasAccountRuntime.GetAdmin) + methodMap[syscontract.GasAccountFunction_RECHARGE_GAS.String()] = common.WrapResultFunc( + gasAccountRuntime.RechargeGas) + methodMap[syscontract.GasAccountFunction_CHARGE_GAS.String()] = common.WrapResultFunc( + gasAccountRuntime.ChargeGasVm) + methodMap[syscontract.GasAccountFunction_GET_BALANCE.String()] = common.WrapResultFunc( + gasAccountRuntime.GetBalance) + methodMap[syscontract.GasAccountFunction_REFUND_GAS.String()] = common.WrapResultFunc( + gasAccountRuntime.RefundGas) + methodMap[syscontract.GasAccountFunction_REFUND_GAS_VM.String()] = common.WrapResultFunc( + gasAccountRuntime.RefundGasVm) + methodMap[syscontract.GasAccountFunction_FROZEN_ACCOUNT.String()] = common.WrapResultFunc( + gasAccountRuntime.FrozenAccount) + methodMap[syscontract.GasAccountFunction_UNFROZEN_ACCOUNT.String()] = common.WrapResultFunc( + gasAccountRuntime.UnFrozenAccount) + methodMap[syscontract.GasAccountFunction_ACCOUNT_STATUS.String()] = common.WrapResultFunc( + gasAccountRuntime.GetAccountStatus) + + return methodMap +} + +type AccountManagerRuntime struct { + log protocol.Logger +} + +func (g *AccountManagerRuntime) SetAdmin(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + addressBytes, ok := params[AddressKey] + if !ok { + err := fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(addressBytes) { + err := fmt.Errorf(" %s, param[public_key]=%s,", common.ErrParams.Error(), addressBytes) + g.log.Errorf(err.Error()) + return nil, err + } + + address := string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err := errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + return g.setAdmin(txSimContext, address) +} + +func (g *AccountManagerRuntime) setAdmin(txSimContext protocol.TxSimContext, address string) ([]byte, error) { + var err error + var chainConfig *configPb.ChainConfig + var result []byte + + chainConfig, err = chainconfigmgr.GetChainConfigEmptyParams(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if chainConfig.AccountConfig != nil { + chainConfig.AccountConfig.GasAdminAddress = address + } else { + chainConfig.AccountConfig = &configPb.GasAccountConfig{ + GasAdminAddress: address, + } + } + + result, err = chainconfigmgr.SetChainConfig(txSimContext, chainConfig) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + return result, nil +} + +func (g *AccountManagerRuntime) GetAdmin(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + adminPublicKey, err := g.getAdmin(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, errors.New(" not set gas admin account") + } + return adminPublicKey, nil +} + +func (g *AccountManagerRuntime) getAdmin(txSimContext protocol.TxSimContext) ([]byte, error) { + var err error + var chainConfig *configPb.ChainConfig + chainConfig, err = chainconfigmgr.GetChainConfigEmptyParams(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if chainConfig.AccountConfig == nil { + return nil, errors.New("chain config account config is empty ") + } + + if _, ok := g.verifyAddress(chainConfig.AccountConfig.GasAdminAddress); !ok { + return nil, errors.New(" gas admin address is illegal") + } + + return []byte(chainConfig.AccountConfig.GasAdminAddress), nil +} + +func (g *AccountManagerRuntime) RechargeGas(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var ( + gasBalance int64 + err error + publicKey []byte + ) + publicKey, err = g.getSenderPublicKey(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if !g.checkAdmin(txSimContext, publicKey) { + err = errors.New(" verify admin failed ") + g.log.Debug(err.Error()) + return nil, err + } + + batchRechargeBytes, ok := params[BatchRecharge] + if !ok { + err = fmt.Errorf(" params key %s not exist ", BatchRecharge) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(batchRechargeBytes) { + err = fmt.Errorf(" %s, param[%s]=%s", + common.ErrParams.Error(), + BatchRecharge, + batchRechargeBytes, + ) + g.log.Errorf(err.Error()) + return nil, err + } + + rechargeGasReq := &syscontract.RechargeGasReq{} + if err = rechargeGasReq.Unmarshal(batchRechargeBytes); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + for i, recharge := range rechargeGasReq.BatchRechargeGas { + address := recharge.Address + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + if err = g.checkAmount(recharge.GasAmount); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + accountKey := AccountPrefix + address + gasBalance, err = g.getAccountBalance(txSimContext, accountKey) + if err != nil { + err = fmt.Errorf(" batch index [%v] error is: %s", i, err.Error()) + g.log.Error(err.Error()) + return nil, err + } + + updateAmount := gasBalance + recharge.GasAmount + if err = g.checkOverFlow(updateAmount); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if err = txSimContext.Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(accountKey), []byte( + strconv.FormatInt(updateAmount, 10))); err != nil { + err = fmt.Errorf(" batch charge index [%v] error is: %s", i, err.Error()) + g.log.Error(err.Error()) + return nil, err + } + } + + return []byte(Success), nil +} + +func (g *AccountManagerRuntime) RefundGasVm(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var ( + gasBalance int64 + rechargeGasAmount int64 + err error + address string + ) + + rechargeKeyBytes, ok := params[RechargeKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", BatchRecharge) + g.log.Error(err.Error()) + return nil, err + } + + rechargeAmountKeyByte, ok := params[RechargeAmountKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", RechargeAmountKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(rechargeKeyBytes, rechargeAmountKeyByte) { + err = fmt.Errorf(" %s, param[%s]=%s,param[%s]=%s", + common.ErrParams.Error(), + RechargeKey, + rechargeKeyBytes, + RechargeAmountKey, + rechargeAmountKeyByte, + ) + g.log.Errorf(err.Error()) + return nil, err + } + + rechargeGasAmount, err = strconv.ParseInt(string(rechargeAmountKeyByte), 10, 0) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if err = g.checkAmount(rechargeGasAmount); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + address, err = publicKeyToAddress(rechargeKeyBytes) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + accountKey := AccountPrefix + address + gasBalance, err = g.getAccountBalance(txSimContext, accountKey) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + updateAmount := gasBalance + rechargeGasAmount + if err = g.checkOverFlow(updateAmount); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if err = txSimContext.Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(accountKey), []byte( + strconv.FormatInt(updateAmount, 10))); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + return []byte(Success), nil +} + +// charge gas for vm and must set config auth multi sign +func (g *AccountManagerRuntime) ChargeGasVm(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var err error + var address string + chargeGasPublicKey, ok := params[ChargePublicKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", ChargePublicKey) + g.log.Error(err.Error()) + return nil, err + } + + chargeGasAmountBytes, ok := params[ChargeGasAmount] + if !ok { + err = fmt.Errorf(" params key %s not exist ", ChargeGasAmount) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(chargeGasPublicKey, chargeGasAmountBytes) { + err = fmt.Errorf(" %s, param[%s]=%s,param[%s]=%s", + common.ErrParams.Error(), + ChargePublicKey, + chargeGasPublicKey, + ChargeGasAmount, + chargeGasAmountBytes, + ) + g.log.Errorf(err.Error()) + return nil, err + } + + address, err = publicKeyToAddress(chargeGasPublicKey) + if err != nil { + g.log.Error(err) + return nil, err + } + return g.chargeGas(txSimContext, address, chargeGasAmountBytes) +} + +func (g *AccountManagerRuntime) GetBalance(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var err error + var gasBalance []byte + addressBytes, ok := params[AddressKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(addressBytes) { + err = fmt.Errorf(" %s, param[%s]=%s", common.ErrParams.Error(), AddressKey, addressBytes) + g.log.Errorf(err.Error()) + return nil, err + } + + address := string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + gasBalance, err = txSimContext.Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), + []byte(AccountPrefix+address)) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if len(gasBalance) == 0 { + return []byte("0"), err + } + + return gasBalance, nil +} + +// refund gas for sdk +func (g *AccountManagerRuntime) RefundGas(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var publicKey []byte + var err error + addressBytes, ok := params[AddressKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + address := string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + chargeGasAmountBytes, ok := params[ChargeGasAmount] + if !ok { + err = fmt.Errorf(" params key %s not exist ", ChargeGasAmount) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(address, chargeGasAmountBytes) { + err = fmt.Errorf(" %s, param[%s]=%s,param[%s]=%s", + common.ErrParams.Error(), + AddressKey, + addressBytes, + ChargeGasAmount, + chargeGasAmountBytes, + ) + g.log.Errorf(err.Error()) + return nil, err + } + + publicKey, err = g.getSenderPublicKey(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if !g.checkAdmin(txSimContext, publicKey) { + err = errors.New(" verify admin failed ") + g.log.Error(err.Error()) + return nil, err + } + return g.chargeGas(txSimContext, address, chargeGasAmountBytes) + +} + +func (g *AccountManagerRuntime) chargeGas(txSimContext protocol.TxSimContext, address string, + chargeGasAmountBytes []byte) ([]byte, error) { + var ( + gasBalance int64 + err error + chargeGasAmount int64 + updateAmount int64 + ) + + if g.checkFrozen(txSimContext, address) { + err = fmt.Errorf(" %s accout is frozened", address) + g.log.Error(err.Error()) + return nil, err + } + + accountKey := AccountPrefix + address + gasBalance, err = g.getAccountBalance(txSimContext, accountKey) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + chargeGasAmount, err = strconv.ParseInt(string(chargeGasAmountBytes), 10, 64) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if err = g.checkAmount(chargeGasAmount); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if updateAmount = gasBalance - chargeGasAmount; updateAmount < 0 { + err = fmt.Errorf("please check [addr:%s] balance, gasBalance[%d] < chargeGasAmount[%d]", + address, gasBalance, chargeGasAmount) + g.log.Error(err.Error()) + return nil, err + } + + if err = txSimContext.Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(accountKey), []byte( + strconv.FormatInt(updateAmount, 10))); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + return []byte(Success), nil +} + +func (g *AccountManagerRuntime) FrozenAccount(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var err error + var publicKey []byte + var address string + publicKey, err = g.getSenderPublicKey(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if !g.checkAdmin(txSimContext, publicKey) { + err = errors.New(" verify admin failed ") + g.log.Error(err.Error()) + return nil, err + } + + addressBytes, ok := params[AddressKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(addressBytes) { + err = fmt.Errorf(" %s, param[%s]=%s", common.ErrParams.Error(), AddressKey, addressBytes) + g.log.Errorf(err.Error()) + return nil, err + } + + address = string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + frozenPublicKey := FrozenPrefix + address + if err = txSimContext.Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(frozenPublicKey), + []byte(locked)); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + return []byte(Success), nil + +} + +func (g *AccountManagerRuntime) UnFrozenAccount(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var err error + var publicKey []byte + var address string + publicKey, err = g.getSenderPublicKey(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + + if !g.checkAdmin(txSimContext, publicKey) { + err = errors.New(" verify admin failed ") + g.log.Error(err.Error()) + return nil, err + } + + addressBytes, ok := params[AddressKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(addressBytes) { + err = fmt.Errorf(" %s, param[%s]=%s", common.ErrParams.Error(), AddressKey, addressBytes) + g.log.Errorf(err.Error()) + return nil, err + } + + address = string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + if frozen := g.checkFrozen(txSimContext, address); !frozen { + err = fmt.Errorf("account %v not frozen", address) + g.log.Errorf(err.Error()) + return nil, err + } + + frozenPublicKey := FrozenPrefix + address + if err = txSimContext.Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(frozenPublicKey), + []byte(unlock)); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + return []byte(Success), nil + +} + +func (g *AccountManagerRuntime) GetAccountStatus(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var err error + var address string + addressBytes, ok := params[AddressKey] + if !ok { + err = fmt.Errorf(" params key %s not exist ", AddressKey) + g.log.Error(err.Error()) + return nil, err + } + + if utils.IsAnyBlank(addressBytes) { + err = fmt.Errorf(" %s, param[%s]=%s", common.ErrParams.Error(), AddressKey, addressBytes) + g.log.Errorf(err.Error()) + return nil, err + } + + address = string(addressBytes) + if address, ok = g.verifyAddress(address); !ok { + err = errors.New(addressIllegal) + g.log.Error(err.Error()) + return nil, err + } + + if g.checkFrozen(txSimContext, address) { + return []byte(locked), nil + } + + return []byte(unlock), nil + +} + +func (g *AccountManagerRuntime) checkFrozen(txSimContext protocol.TxSimContext, address string) bool { + var ( + err error + frozenBytes []byte + ) + + frozenBytes, err = txSimContext.Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)) + if err != nil { + g.log.Error(err.Error()) + return false + } + + if string(frozenBytes) != locked { + return false + } + return true +} + +func (g *AccountManagerRuntime) checkAdmin(txSimContext protocol.TxSimContext, userPublicKey []byte) bool { + adminPublicKeyBytes, err := g.getAdmin(txSimContext) + if err != nil { + g.log.Error(err.Error()) + return false + } + + publicKeyString, err := publicKeyToAddress(userPublicKey) + if err != nil { + g.log.Error(err.Error()) + return false + } + + if string(adminPublicKeyBytes) != publicKeyString { + return false + } + + return true +} + +func (g *AccountManagerRuntime) getSenderPublicKey(txSimContext protocol.TxSimContext) ([]byte, error) { + var err error + var pk []byte + sender := txSimContext.GetSender() + if sender == nil { + err = errors.New(" can not find sender from tx ") + g.log.Error(err.Error()) + return nil, err + } + + switch sender.MemberType { + case accesscontrol.MemberType_CERT: + pk, err = publicKeyFromCert(sender.MemberInfo) + if err != nil { + g.log.Error(err.Error()) + return nil, err + } + case accesscontrol.MemberType_CERT_HASH: + var certInfo *commonPb.CertInfo + infoHex := hex.EncodeToString(sender.MemberInfo) + if certInfo, err = wholeCertInfo(txSimContext, infoHex); err != nil { + g.log.Error(err.Error()) + return nil, fmt.Errorf(" can not load the whole cert info,member[%s],reason: %s", infoHex, err) + } + + if pk, err = publicKeyFromCert(certInfo.Cert); err != nil { + g.log.Error(err.Error()) + return nil, err + } + + case accesscontrol.MemberType_PUBLIC_KEY: + pk = sender.MemberInfo + default: + err = fmt.Errorf("invalid member type: %s", sender.MemberType) + g.log.Error(err.Error()) + return nil, err + } + + return pk, nil +} + +func (g *AccountManagerRuntime) getAccountBalance(txSimContext protocol.TxSimContext, + accountKey string) (int64, error) { + + var gasBalance int64 + gas, err := txSimContext.Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(accountKey)) + if err != nil { + g.log.Error(err.Error()) + return 0, nil + } + + if len(gas) == 0 { + return 0, nil + } + + gasBalance, err = strconv.ParseInt(string(gas), 10, 64) + if err != nil { + g.log.Error(err.Error()) + return 0, err + } + + if gasBalance < 0 { + err = errors.New(" gas balance less than zero ") + g.log.Error(err.Error()) + return 0, err + } + return gasBalance, nil +} + +func (g *AccountManagerRuntime) verifyAddress(address string) (string, bool) { + g.log.Infof("verify account address is:%v", address) + if len(address) != 42 { + return emptyString, false + } + + if address[:2] != "ZX" { + return emptyString, false + } + + return address[:2] + strings.ToLower(address[2:]), true +} + +func (g *AccountManagerRuntime) checkAmount(amount int64) error { + if amount < 0 { + g.log.Errorf("amount is %v", amount) + return errors.New("amount must >= 0") + } + return nil +} + +func (g *AccountManagerRuntime) checkOverFlow(amount int64) error { + if amount < 0 { + g.log.Error(int64OverFlow) + return errors.New(int64OverFlow) + } + return nil +} + +func publicKeyToAddress(publicKey []byte) (string, error) { + pk, err := asym.PublicKeyFromPEM(publicKey) + if err != nil { + return "", err + } + + publicKeyString, err := evmutils.ZXAddressFromPublicKey(pk) + if err != nil { + return emptyString, err + } + return publicKeyString, nil +} + +func publicKeyFromCert(member []byte) ([]byte, error) { + certificate, err := utils.ParseCert(member) + if err != nil { + return nil, err + } + pubKeyBytes, err := certificate.PublicKey.Bytes() + if err != nil { + return nil, err + } + return pubKeyBytes, nil +} + +func wholeCertInfo(txSimContext protocol.TxSimContext, certHash string) (*commonPb.CertInfo, error) { + certBytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)) + if err != nil { + return nil, err + } + + return &commonPb.CertInfo{ + Hash: certHash, + Cert: certBytes, + }, nil +} diff --git a/accountmgr/account_manager_test.go b/accountmgr/account_manager_test.go new file mode 100644 index 0000000000000000000000000000000000000000..e0cbb5a170d81445a0840e39219db32c819e143c --- /dev/null +++ b/accountmgr/account_manager_test.go @@ -0,0 +1,1302 @@ +/* +Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package accountmgr + +import ( + "encoding/hex" + "errors" + "fmt" + "reflect" + "testing" + + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + configPb "chainmaker.org/chainmaker/pb-go/v2/config" + "chainmaker.org/chainmaker/pb-go/v2/consensus" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/protocol/v2/mock" + "github.com/gogo/protobuf/proto" + "github.com/golang/mock/gomock" +) + +var ( + address = "ZX958f7550fe53d96e708b0fc95212812bec3141ed" + pk = `-----BEGIN PUBLIC KEY----- +MIGJAoGBALC7ewHv7ksky2qw/Zjeyfl5bxuv92/V31ZdrqnRQSxShVjhuANnjvVf +17SG2dlRZy68jkHTAeShomIqFTFKTkAnw5jki8UjQ6pBLTsgyoiPf+7eIRFWW65r +ADkhSM8WYKK5sn89v8lkKkUNBtlvbT2HtWw6QPW/3haU0k3yybupAgMBAAE= +-----END PUBLIC KEY-----` + cert = `-----BEGIN CERTIFICATE----- +MIICrzCCAlWgAwIBAgIDDsPeMAoGCCqGSM49BAMCMIGKMQswCQYDVQQGEwJDTjEQ +MA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzEfMB0GA1UEChMWd3gt +b3JnMS5jaGFpbm1ha2VyLm9yZzESMBAGA1UECxMJcm9vdC1jZXJ0MSIwIAYDVQQD +ExljYS53eC1vcmcxLmNoYWlubWFrZXIub3JnMB4XDTIwMTIwODA2NTM0M1oXDTMw +MTIwNjA2NTM0M1owgYoxCzAJBgNVBAYTAkNOMRAwDgYDVQQIEwdCZWlqaW5nMRAw +DgYDVQQHEwdCZWlqaW5nMR8wHQYDVQQKExZ3eC1vcmcxLmNoYWlubWFrZXIub3Jn +MRIwEAYDVQQLEwlyb290LWNlcnQxIjAgBgNVBAMTGWNhLnd4LW9yZzEuY2hhaW5t +YWtlci5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT7NyTIKcjtUVeMn29b +GKeEmwbefZ7g9Uk5GROl+o4k7fiIKNuty1rQHLQUvAvkpxqtlmOpPOZ0Qziu6Hw6 +hi19o4GnMIGkMA4GA1UdDwEB/wQEAwIBpjAPBgNVHSUECDAGBgRVHSUAMA8GA1Ud +EwEB/wQFMAMBAf8wKQYDVR0OBCIEIDUkP3EcubfENS6TH3DFczH5dAnC2eD73+wc +UF/bEIlnMEUGA1UdEQQ+MDyCDmNoYWlubWFrZXIub3Jngglsb2NhbGhvc3SCGWNh +Lnd4LW9yZzEuY2hhaW5tYWtlci5vcmeHBH8AAAEwCgYIKoZIzj0EAwIDSAAwRQIg +ar8CSuLl7pA4Iy6ytAMhR0kzy0WWVSElc+koVY6pF5sCIQCDs+vTD/9V1azmbDXX +bjoWeEfXbFJp2X/or9f4UIvMgg== +-----END CERTIFICATE----- +` +) + +func TestAccountManagerRuntime_ChargeGasVm(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + logger := mock.NewMockLogger(c) + gomock.InOrder( + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("0"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("10"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address), []byte("5")).Return(nil).AnyTimes(), + ) + + type fields struct { + log protocol.Logger + } + + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + ChargePublicKey: []byte(pk), + ChargeGasAmount: []byte("5"), + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.ChargeGasVm(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("ChargeGasVm() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ChargeGasVm() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_FrozenAccount(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + member := &accesscontrol.Member{ + MemberType: accesscontrol.MemberType_PUBLIC_KEY, + MemberInfo: []byte(pk), + } + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + + gomock.InOrder( + mockTxSimContext.EXPECT().GetSender().Return(member).AnyTimes(), + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address), []byte("1")).Return(nil).AnyTimes(), + ) + + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + AddressKey: []byte(address), + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.FrozenAccount(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("FrozenAccount() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("FrozenAccount() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_GetAccountStatus(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("0"), nil).AnyTimes() + + mockTxSimContextLock := mock.NewMockTxSimContext(c) + mockTxSimContextLock.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("1"), nil).AnyTimes() + + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "unlock", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + AddressKey: []byte(address), + }, + }, + want: []byte(unlock), + wantErr: false, + }, + { + name: "lock", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContextLock, + params: map[string][]byte{ + AddressKey: []byte(address), + }, + }, + want: []byte(locked), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.GetAccountStatus(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("GetAccountStatus() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetAccountStatus() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_GetAdmin(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes() + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + params: nil, + }, + want: []byte(address), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.GetAdmin(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("GetAdmin() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetAdmin() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_GetBalance(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), + []byte(AccountPrefix+address)).Return([]byte("10"), nil).AnyTimes() + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + AddressKey: []byte(address), + }, + }, + want: []byte("10"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.GetBalance(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("GetBalance() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetBalance() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_RechargeGas(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + member := &accesscontrol.Member{ + MemberType: accesscontrol.MemberType_PUBLIC_KEY, + MemberInfo: []byte(pk), + } + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + + mockTxSimContext := mock.NewMockTxSimContext(c) + gomock.InOrder( + mockTxSimContext.EXPECT().GetSender().Return(member).AnyTimes(), + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("100"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address), []byte("200")).Return(nil).AnyTimes(), + ) + + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error().Return().AnyTimes() + + rechargeGasReq := &syscontract.RechargeGasReq{ + BatchRechargeGas: []*syscontract.RechargeGas{ + { + Address: address, + GasAmount: 100, + }, + }, + } + rechargeGasReqBytes, err := rechargeGasReq.Marshal() + if err != nil { + t.Error(err.Error()) + return + } + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + BatchRecharge: rechargeGasReqBytes, + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.RechargeGas(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("RechargeGas() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("RechargeGas() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_RefundGas(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + member := &accesscontrol.Member{ + MemberType: accesscontrol.MemberType_PUBLIC_KEY, + MemberInfo: []byte(pk), + } + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + + gomock.InOrder( + mockTxSimContext.EXPECT().GetSender().Return(member).AnyTimes(), + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("0"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("100"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address), []byte("90")).Return(nil).AnyTimes(), + ) + + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error(fmt.Errorf(" %s accout is frozened", address).Error()).Return().AnyTimes() + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + AddressKey: []byte(address), + ChargeGasAmount: []byte("10"), + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.RefundGas(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("RefundGas() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("RefundGas() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_RefundGasVm(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + gomock.InOrder( + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("100"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address), []byte("110")).Return(nil).AnyTimes(), + ) + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error(errors.New("error")).Return().AnyTimes() + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + RechargeKey: []byte(pk), + RechargeAmountKey: []byte("10"), + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.RefundGasVm(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("RefundGasVm() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("RefundGasVm() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_SetAdmin(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + TrustRoots: []*configPb.TrustRootConfig{ + { + OrgId: address, + }, + }, + + Consensus: &configPb.ConsensusConfig{ + Type: consensus.ConsensusType_SOLO, + Nodes: []*configPb.OrgConfig{ + { + Address: []string{address}, + OrgId: "chainmaker.org1", + NodeId: []string{"node1"}, + }, + }, + }, + Block: &configPb.BlockConfig{ + TxTimestampVerify: false, + }, + ChainId: "chain1", + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + mockTxSimContext := mock.NewMockTxSimContext(c) + gomock.InOrder( + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes(), + ) + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error("org id(chainmaker.org1) not in trust roots config").Return().AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + //{ + // name: "bad", + // fields: fields{ + // log: logger, + // }, + // args: args{ + // txSimContext: mockTxSimContext, + // params: map[string][]byte{ + // AddressKey: []byte(address), + // }, + // }, + // want: []byte("org id(chainmaker.org1) not in trust roots config"), + // wantErr: true, + //}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.SetAdmin(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("SetAdmin() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("SetAdmin() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_UnFrozenAccount(t *testing.T) { + + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + member := &accesscontrol.Member{ + MemberType: accesscontrol.MemberType_PUBLIC_KEY, + MemberInfo: []byte(pk), + } + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + + gomock.InOrder( + mockTxSimContext.EXPECT().GetSender().Return(member).AnyTimes(), + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)). + Return(chainConfigBytes, nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), + []byte(FrozenPrefix+address)).Return([]byte("1"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), + []byte(FrozenPrefix+address), []byte(unlock)).Return(nil).AnyTimes(), + ) + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error(errors.New("error")).Return().AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + params map[string][]byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + params: map[string][]byte{ + AddressKey: []byte(address), + }, + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.UnFrozenAccount(tt.args.txSimContext, tt.args.params) + if (err != nil) != tt.wantErr { + t.Errorf("UnFrozenAccount() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("UnFrozenAccount() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_chargeGas(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + logger := mock.NewMockLogger(c) + gomock.InOrder( + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("0"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("200"), nil).AnyTimes(), + mockTxSimContext.EXPECT().Put(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address), []byte("100")).Return(nil).AnyTimes(), + ) + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + address string + chargeGasAmountBytes []byte + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + address: address, + chargeGasAmountBytes: []byte("100"), + }, + want: []byte(Success), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.chargeGas(tt.args.txSimContext, tt.args.address, tt.args.chargeGasAmountBytes) + if (err != nil) != tt.wantErr { + t.Errorf("chargeGas() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("chargeGas() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_checkAdmin(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address) + + loggerNotAdmin := mock.NewMockLogger(c) + gomock.InOrder( + loggerNotAdmin.EXPECT().Infof("verify account address is:%v", "Zx958f7550fe53d96e708b0fc95212812bec3141ea"), + loggerNotAdmin.EXPECT().Error(" gas admin address is illegal"), + ) + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + + chainConfigNotAdmin := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: "Zx958f7550fe53d96e708b0fc95212812bec3141ea", + }, + } + + chainConfigNotAdminBytes, err := proto.Marshal(chainConfigNotAdmin) + if err != nil { + t.Error(err.Error()) + return + } + + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes() + mockTxSimContextNotAdmin := mock.NewMockTxSimContext(c) + mockTxSimContextNotAdmin.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigNotAdminBytes, nil).AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + userPublicKey []byte + } + tests := []struct { + name string + fields fields + args args + want bool + }{ + { + name: "admin", + fields: fields{ + log: logger, + }, + args: args{ + txSimContext: mockTxSimContext, + userPublicKey: []byte(pk), + }, + want: true, + }, + { + name: "notAdmin", + fields: fields{ + log: loggerNotAdmin, + }, + args: args{ + txSimContext: mockTxSimContextNotAdmin, + userPublicKey: []byte(pk), + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + if got := g.checkAdmin(tt.args.txSimContext, tt.args.userPublicKey); got != tt.want { + t.Errorf("checkAdmin() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_checkFrozen(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + logger := mock.NewMockLogger(c) + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContextUnfrozen := mock.NewMockTxSimContext(c) + gomock.InOrder( + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("1"), nil), + mockTxSimContextUnfrozen.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(FrozenPrefix+address)).Return([]byte("0"), nil), + ) + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + address string + } + tests := []struct { + name string + fields fields + args args + want bool + }{ + { + name: "frozen", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + address: address, + }, + want: true, + }, + { + name: "unfrozen", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContextUnfrozen, + address: address, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + if got := g.checkFrozen(tt.args.txSimContext, tt.args.address); got != tt.want { + t.Errorf("checkFrozen() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_getAccountBalance(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + logger := mock.NewMockLogger(c) + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_ACCOUNT_MANAGER.String(), []byte(AccountPrefix+address)).Return([]byte("100"), nil) + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + accountKey string + } + tests := []struct { + name string + fields fields + args args + want int64 + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + accountKey: AccountPrefix + address, + }, + want: 100, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.getAccountBalance(tt.args.txSimContext, tt.args.accountKey) + if (err != nil) != tt.wantErr { + t.Errorf("getAccountBalance() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("getAccountBalance() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_getAdmin(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address) + + chainConfigContractName := syscontract.SystemContract_CHAIN_CONFIG.String() + chainConfig := &configPb.ChainConfig{ + AccountConfig: &configPb.GasAccountConfig{ + GasAdminAddress: address, + }, + } + + chainConfigBytes, err := proto.Marshal(chainConfig) + if err != nil { + t.Error(err.Error()) + return + } + mockTxSimContext := mock.NewMockTxSimContext(c) + mockTxSimContext.EXPECT().Get(chainConfigContractName, []byte(chainConfigContractName)).Return(chainConfigBytes, nil).AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + } + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{txSimContext: mockTxSimContext}, + want: []byte(address), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.getAdmin(tt.args.txSimContext) + if (err != nil) != tt.wantErr { + t.Errorf("getAdmin() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("getAdmin() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_getSenderPublicKey(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + logger := mock.NewMockLogger(c) + mockTxSimContext := mock.NewMockTxSimContext(c) + + member := &accesscontrol.Member{ + MemberType: accesscontrol.MemberType_PUBLIC_KEY, + MemberInfo: []byte(pk), + } + + mockTxSimContext.EXPECT().GetSender().Return(member).AnyTimes() + + type fields struct { + log protocol.Logger + } + type args struct { + txSimContext protocol.TxSimContext + } + + tests := []struct { + name string + fields fields + args args + want []byte + wantErr bool + }{ + { + name: "good", + fields: fields{log: logger}, + args: args{ + txSimContext: mockTxSimContext, + }, + want: []byte(pk), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, err := g.getSenderPublicKey(tt.args.txSimContext) + if (err != nil) != tt.wantErr { + t.Errorf("getSenderPublicKey() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("getSenderPublicKey() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAccountManagerRuntime_verifyAddress(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + loggerGood := mock.NewMockLogger(c) + logger := mock.NewMockLogger(c) + gomock.InOrder( + loggerGood.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes(), + logger.EXPECT().Infof("verify account address is:%v", "zX958f7550fe53d96e708b0fc95212812bec3141ed").Return().AnyTimes(), + ) + + type fields struct { + log protocol.Logger + } + type args struct { + address string + } + tests := []struct { + name string + fields fields + args args + want string + want1 bool + }{ + { + name: "good", + fields: fields{ + log: loggerGood, + }, + args: args{ + address: address, + }, + want: address, + want1: true, + }, + + { + name: "bad", + fields: fields{ + log: logger, + }, + args: args{ + address: "zX958f7550fe53d96e708b0fc95212812bec3141ed", + }, + want: emptyString, + want1: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := &AccountManagerRuntime{ + log: tt.fields.log, + } + got, got1 := g.verifyAddress(tt.args.address) + if got != tt.want { + t.Errorf("verifyAddress() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("verifyAddress() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func Test_publicKeyFromCert(t *testing.T) { + type args struct { + member []byte + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "good", + args: args{member: []byte(cert)}, + want: "3059301306072a8648ce3d020106082a8648ce3d03010703420004fb3724c829c8ed51578c9f6f5b18a7849b06de7d9ee0f549391913a5fa8e24edf88828dbadcb5ad01cb414bc0be4a71aad9663a93ce6744338aee87c3a862d7d", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := publicKeyFromCert(tt.args.member) + if (err != nil) != tt.wantErr { + t.Errorf("publicKeyFromCert() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(hex.EncodeToString(got), tt.want) { + t.Errorf("publicKeyFromCert() got = %v, want %v", hex.EncodeToString(got), tt.want) + } + }) + } +} + +func Test_publicKeyToAddress(t *testing.T) { + type args struct { + publicKey []byte + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "good", + args: args{publicKey: []byte(pk)}, + want: address, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := publicKeyToAddress(tt.args.publicKey) + if (err != nil) != tt.wantErr { + t.Errorf("publicKeyToAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("publicKeyToAddress() got = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_wholeCertInfo(t *testing.T) { + c := gomock.NewController(t) + defer c.Finish() + mockTxSimContext := mock.NewMockTxSimContext(c) + certHash := hex.EncodeToString([]byte(pk)) + mockTxSimContext.EXPECT().Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)).Return([]byte(pk), nil).AnyTimes() + + logger := mock.NewMockLogger(c) + logger.EXPECT().Infof("verify account address is:%v", address).Return().AnyTimes() + logger.EXPECT().Error(errors.New("error")).Return().AnyTimes() + + type args struct { + txSimContext protocol.TxSimContext + certHash string + } + tests := []struct { + name string + args args + want *commonPb.CertInfo + wantErr bool + }{ + { + name: "good", + args: args{ + txSimContext: mockTxSimContext, + certHash: certHash, + }, + wantErr: false, + want: &commonPb.CertInfo{ + Hash: certHash, + Cert: []byte(pk), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := wholeCertInfo(tt.args.txSimContext, tt.args.certHash) + if (err != nil) != tt.wantErr { + t.Errorf("wholeCertInfo() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("wholeCertInfo() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/accountmgr/gasManager.go b/accountmgr/gasManager.go new file mode 100644 index 0000000000000000000000000000000000000000..226926ba95522464d0f42dd4bb9967f17ede8410 --- /dev/null +++ b/accountmgr/gasManager.go @@ -0,0 +1,90 @@ +package accountmgr + +import "chainmaker.org/chainmaker/protocol/v2" + +type AccountMgr interface { + /** + * @Description: 设置gas管理员 + * @param publicKey + * @return bool + * @return error + */ + SetAdmin(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 查询gas管理员 + * @param publicKey + * @return []byte + * @return error + */ + GetAdmin(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 充值gas + * @param publicKey + * @param gas + * @return bool + * @return error + */ + RechargeGas(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 扣款for vm + * @param publicKey + * @param gas + * @return bool + * @return error + */ + ChargeGasVm(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 退还多扣的gas for vm + * @param: publicKey 发起交易的账户公钥 + * @param: gas 退还gas数量 + * @return bool 是否退还成功 + * @return error + */ + RefundGasVm(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 查询gas余额 + * @param publicKey + * @return uint64 + * @return error + */ + GetBalance(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 退款for sdk + * @param publicKey + * @param gasUsed + * @return bool + * @return error + */ + RefundGas(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 冻结指定账户 + * @param publicKey + * @return bool + * @return error + */ + FrozenAccount(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 解冻指定账号 + * @param txSimContext + * @param params + * @return []byte + * @return error + */ + UnFrozenAccount(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) + + /** + * @Description: 获取账户冻结状态 + * @param publicKey + * @return bool + * @return error + */ + GetAccountStatus(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) +} diff --git a/blockcontract/block_contract.go b/blockcontract/block_contract.go index 461312619392593c6f7f3c9d6ae2cb809f683817..afc950b3d9d9814da514460a92e74fa36f992130 100644 --- a/blockcontract/block_contract.go +++ b/blockcontract/block_contract.go @@ -17,7 +17,9 @@ import ( "strconv" "strings" - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/utils/v2" + + "chainmaker.org/chainmaker/vm-native/v2/common" "chainmaker.org/chainmaker/common/v2/crypto/hash" "chainmaker.org/chainmaker/localconf/v2" @@ -26,7 +28,6 @@ import ( storage "chainmaker.org/chainmaker/pb-go/v2/store" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" - "chainmaker.org/chainmaker/utils/v2" "github.com/gogo/protobuf/proto" ) @@ -35,14 +36,17 @@ const ( paramNameWithRWSet = "withRWSet" paramNameBlockHash = "blockHash" paramNameTxId = "txId" - TRUE = "true" + // TRUE string const + TRUE = "true" ) var ( logTemplateMarshalBlockInfoFailed = "marshal block info failed, %s" errStoreIsNil = fmt.Errorf("store is nil") + //errDataNotFound = fmt.Errorf("data not found") ) +type BlockHeight int64 type BlockContract struct { methods map[string]common.ContractFunc log protocol.Logger @@ -63,22 +67,26 @@ func registerBlockContractMethods(log protocol.Logger) map[string]common.Contrac q := make(map[string]common.ContractFunc, 64) b := &BlockRuntime{log: log} - q[syscontract.ChainQueryFunction_GET_BLOCK_BY_HEIGHT.String()] = b.GetBlockByHeight - q[syscontract.ChainQueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HEIGHT.String()] = b.GetBlockWithTxRWSetsByHeight - q[syscontract.ChainQueryFunction_GET_BLOCK_BY_HASH.String()] = b.GetBlockByHash - q[syscontract.ChainQueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HASH.String()] = b.GetBlockWithTxRWSetsByHash - q[syscontract.ChainQueryFunction_GET_BLOCK_BY_TX_ID.String()] = b.GetBlockByTxId - q[syscontract.ChainQueryFunction_GET_TX_BY_TX_ID.String()] = b.GetTxByTxId - q[syscontract.ChainQueryFunction_GET_LAST_CONFIG_BLOCK.String()] = b.GetLastConfigBlock - q[syscontract.ChainQueryFunction_GET_LAST_BLOCK.String()] = b.GetLastBlock - q[syscontract.ChainQueryFunction_GET_CHAIN_INFO.String()] = b.GetChainInfo - q[syscontract.ChainQueryFunction_GET_NODE_CHAIN_LIST.String()] = b.GetNodeChainList - q[syscontract.ChainQueryFunction_GET_FULL_BLOCK_BY_HEIGHT.String()] = b.GetFullBlockByHeight - q[syscontract.ChainQueryFunction_GET_BLOCK_HEIGHT_BY_TX_ID.String()] = b.GetBlockHeightByTxId - q[syscontract.ChainQueryFunction_GET_BLOCK_HEIGHT_BY_HASH.String()] = b.GetBlockHeightByHash - q[syscontract.ChainQueryFunction_GET_BLOCK_HEADER_BY_HEIGHT.String()] = b.GetBlockHeaderByHeight - q[syscontract.ChainQueryFunction_GET_ARCHIVED_BLOCK_HEIGHT.String()] = b.GetArchiveBlockHeight - q[syscontract.ChainQueryFunction_GET_MERKLE_PATH_BY_TX_ID.String()] = b.GetMerklePathByTxId + q[syscontract.ChainQueryFunction_GET_BLOCK_BY_HEIGHT.String()] = common.WrapResultFunc(b.GetBlockByHeight) + q[syscontract.ChainQueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HEIGHT.String()] = common.WrapResultFunc( + b.GetBlockWithTxRWSetsByHeight) + q[syscontract.ChainQueryFunction_GET_BLOCK_BY_HASH.String()] = common.WrapResultFunc(b.GetBlockByHash) + q[syscontract.ChainQueryFunction_GET_BLOCK_WITH_TXRWSETS_BY_HASH.String()] = common.WrapResultFunc( + b.GetBlockWithTxRWSetsByHash) + q[syscontract.ChainQueryFunction_GET_BLOCK_BY_TX_ID.String()] = common.WrapResultFunc(b.GetBlockByTxId) + q[syscontract.ChainQueryFunction_GET_TX_BY_TX_ID.String()] = common.WrapResultFunc(b.GetTxByTxId) + q[syscontract.ChainQueryFunction_GET_LAST_CONFIG_BLOCK.String()] = common.WrapResultFunc(b.GetLastConfigBlock) + q[syscontract.ChainQueryFunction_GET_LAST_BLOCK.String()] = common.WrapResultFunc(b.GetLastBlock) + q[syscontract.ChainQueryFunction_GET_CHAIN_INFO.String()] = common.WrapResultFunc(b.GetChainInfo) + q[syscontract.ChainQueryFunction_GET_NODE_CHAIN_LIST.String()] = common.WrapResultFunc(b.GetNodeChainList) + q[syscontract.ChainQueryFunction_GET_FULL_BLOCK_BY_HEIGHT.String()] = common.WrapResultFunc(b.GetFullBlockByHeight) + q[syscontract.ChainQueryFunction_GET_BLOCK_HEIGHT_BY_TX_ID.String()] = common.WrapResultFunc(b.GetBlockHeightByTxId) + q[syscontract.ChainQueryFunction_GET_BLOCK_HEIGHT_BY_HASH.String()] = common.WrapResultFunc(b.GetBlockHeightByHash) + q[syscontract.ChainQueryFunction_GET_BLOCK_HEADER_BY_HEIGHT.String()] = common.WrapResultFunc( + b.GetBlockHeaderByHeight) + q[syscontract.ChainQueryFunction_GET_ARCHIVED_BLOCK_HEIGHT.String()] = common.WrapResultFunc( + b.GetArchiveBlockHeight) + q[syscontract.ChainQueryFunction_GET_MERKLE_PATH_BY_TX_ID.String()] = common.WrapResultFunc(b.GetMerklePathByTxId) return q } @@ -139,11 +147,6 @@ func (r *BlockRuntime) GetChainInfo(txSimContext protocol.TxSimContext, paramete return nil, errStoreIsNil } - provider, err := txSimContext.GetChainNodesInfoProvider() - if err != nil { - return nil, fmt.Errorf("get ChainNodesInfoProvider error: %s", err) - } - var block *commonPb.Block var nodes []*discoveryPb.Node @@ -151,8 +154,13 @@ func (r *BlockRuntime) GetChainInfo(txSimContext protocol.TxSimContext, paramete return nil, err } - if nodes, err = r.getChainNodeInfo(provider, chainId); err != nil { - return nil, err + var provider protocol.ChainNodesInfoProvider + if provider, err = txSimContext.GetChainNodesInfoProvider(); err != nil { + r.log.Warn(err) + } else { + if nodes, err = r.getChainNodeInfo(provider, chainId); err != nil { + return nil, err + } } chainInfo := &discoveryPb.ChainInfo{ @@ -571,16 +579,18 @@ func (r *BlockRuntime) GetLastBlock(txSimContext protocol.TxSimContext, paramete } func (r *BlockRuntime) GetTxByTxId(txSimContext protocol.TxSimContext, parameters map[string][]byte) ([]byte, error) { - var errMsg string + //var errMsg string var err error - var transactionInfoBytes []byte + //var transactionInfoBytes []byte // check params var param *BlockRuntimeParam - if param, err = r.validateParams(parameters, paramNameTxId); err != nil { + if param, err = r.validateParamsAndLen(parameters, false, paramNameTxId); err != nil { return nil, err } - + if withRWSet, ok := parameters[paramNameWithRWSet]; ok { + param.withRWSet = string(withRWSet) + } chainId := txSimContext.GetTx().Payload.ChainId store := txSimContext.GetBlockchainStore() @@ -588,33 +598,47 @@ func (r *BlockRuntime) GetTxByTxId(txSimContext protocol.TxSimContext, parameter return nil, errStoreIsNil } - var tx *commonPb.Transaction - var block *commonPb.Block - - if tx, err = r.getTxByTxId(store, chainId, param.txId); err != nil { - return nil, err - } - - if block, err = r.getBlockByTxId(store, chainId, param.txId); err != nil { - return nil, err - } - - transactionInfo := &commonPb.TransactionInfo{ - Transaction: tx, - BlockHeight: uint64(block.Header.BlockHeight), - } - - if transactionInfo, err = checkRoleAndGenerateTransactionInfo(txSimContext, transactionInfo); err != nil { - return nil, err + if strings.ToLower(param.withRWSet) == "true" { + txInfoWithRWSet, err1 := r.getTxInfoWithRWSetByTxId(store, chainId, param.txId) + if err1 != nil { + return nil, err1 + } + return txInfoWithRWSet.Marshal() } - - transactionInfoBytes, err = proto.Marshal(transactionInfo) + txInfo, err := r.getTxWithInfoByTxId(store, chainId, param.txId) if err != nil { - errMsg = fmt.Sprintf("marshal tx failed, %s", err.Error()) - r.log.Errorf(errMsg) - return nil, fmt.Errorf(errMsg) + return nil, err } - return transactionInfoBytes, nil + return txInfo.Marshal() + + //var tx *commonPb.Transaction + //var block *commonPb.Block + // + //if tx, err = r.getTxByTxId(store, chainId, param.txId); err != nil { + // return nil, err + //} + // + //if block, err = r.getBlockByTxId(store, chainId, param.txId); err != nil { + // return nil, err + //} + // + //transactionInfo := &commonPb.TransactionInfo{ + // Transaction: tx, + // BlockHeight: uint64(block.Header.BlockHeight), + //} + // + //TODO:Devin 什么情况下要检查权限,从而决定只返回区块高度还是包含其他信息呢? + //if transactionInfo, err = checkRoleAndGenerateTransactionInfo(txSimContext, transactionInfo); err != nil { + // return nil, err + //} + // + //transactionInfoBytes, err = proto.Marshal(transactionInfo) + //if err != nil { + // errMsg = fmt.Sprintf("marshal tx failed, %s", err.Error()) + // r.log.Errorf(errMsg) + // return nil, fmt.Errorf(errMsg) + //} + //return transactionInfoBytes, nil } @@ -831,11 +855,10 @@ func (r *BlockRuntime) getBlockHeaderByHeight(store protocol.BlockchainStore, ch err = r.handleError(blockHeader, err, chainId) return blockHeader, err } - func (r *BlockRuntime) getBlockHeightByTxId(store protocol.BlockchainStore, chainId string, txId string) ( uint64, error) { height, err := store.GetTxHeight(txId) - err = r.handleError(height, err, chainId) + err = r.handleError(BlockHeight(height), err, chainId) return height, err } @@ -847,7 +870,7 @@ func (r *BlockRuntime) getBlockHeightByHash(store protocol.BlockchainStore, chai return 0, fmt.Errorf("decode hash failed, %s", err) } height, err := store.GetHeightByHash(hashBytes) - err = r.handleError(height, err, chainId) + err = r.handleError(BlockHeight(height), err, chainId) return height, err } @@ -877,13 +900,18 @@ func (r *BlockRuntime) getLastConfigBlock(store protocol.BlockchainStore, chainI return block, err } -func (r *BlockRuntime) getTxByTxId(store protocol.BlockchainStore, chainId string, txId string) ( - *commonPb.Transaction, error) { - tx, err := store.GetTx(txId) - err = r.handleError(tx, err, chainId) +func (r *BlockRuntime) getTxWithInfoByTxId(store protocol.BlockchainStore, chainId string, txId string) ( + *commonPb.TransactionInfo, error) { + tx, err := store.GetTxWithInfo(txId) + err = r.handleErrorSpecTypeName(tx, err, "transaction", chainId) + return tx, err +} +func (r *BlockRuntime) getTxInfoWithRWSetByTxId(store protocol.BlockchainStore, chainId string, txId string) ( + *commonPb.TransactionInfoWithRWSet, error) { + tx, err := store.GetTxInfoWithRWSet(txId) + err = r.handleErrorSpecTypeName(tx, err, "transaction", chainId) return tx, err } - func (r *BlockRuntime) getTxRWSetsByBlock(store protocol.BlockchainStore, chainId string, block *commonPb.Block) ( []*commonPb.TxRWSet, error) { var txRWSets []*commonPb.TxRWSet @@ -911,7 +939,12 @@ func (r *BlockRuntime) GetArchiveBlockHeight(context protocol.TxSimContext, para } func (r *BlockRuntime) handleError(value interface{}, err error, chainId string) error { - typeName := strings.ToLower(strings.Split(fmt.Sprintf("%T", value), ".")[1]) + tn := strings.Split(fmt.Sprintf("%T", value), ".") + typeName := strings.ToLower(tn[len(tn)-1]) + return r.handleErrorSpecTypeName(value, err, typeName, chainId) +} + +func (r *BlockRuntime) handleErrorSpecTypeName(value interface{}, err error, typeName, chainId string) error { if err != nil { r.log.Errorf("get %s from store failed, [chainId:%s], %s", typeName, chainId, err.Error()) return fmt.Errorf("get %s failed, %s", typeName, err) @@ -926,11 +959,15 @@ func (r *BlockRuntime) handleError(value interface{}, err error, chainId string) } func (r *BlockRuntime) validateParams(parameters map[string][]byte, keyNames ...string) (*BlockRuntimeParam, error) { + return r.validateParamsAndLen(parameters, true, keyNames...) +} +func (r *BlockRuntime) validateParamsAndLen(parameters map[string][]byte, checkParamLen bool, keyNames ...string) ( + *BlockRuntimeParam, error) { var ( errMsg string err error ) - if len(parameters) != len(keyNames) { + if checkParamLen && len(parameters) != len(keyNames) { errMsg = fmt.Sprintf("invalid params len, need [%s]", strings.Join(keyNames, "|")) r.log.Error(errMsg) return nil, errors.New(errMsg) @@ -995,33 +1032,33 @@ func checkRoleAndFilterBlockTxs(block *commonPb.Block, txSimContext protocol.TxS return block, nil } -func checkRoleAndGenerateTransactionInfo(txSimContext protocol.TxSimContext, - transactionInfo *commonPb.TransactionInfo) (*commonPb.TransactionInfo, error) { - var ( - reqSender protocol.Role - err error - ac protocol.AccessControlProvider - ) - tx := transactionInfo.Transaction - - if ac, err = txSimContext.GetAccessControl(); err != nil { - return nil, err - } - - if reqSender, err = utils.GetRoleFromTx(txSimContext.GetTx(), ac); err != nil { - return nil, err - } - - if reqSender == protocol.RoleLight { - if tx.Sender.Signer.OrgId != txSimContext.GetTx().Sender.Signer.OrgId { - newTransactionInfo := &commonPb.TransactionInfo{ - Transaction: nil, - BlockHeight: transactionInfo.BlockHeight, - BlockHash: transactionInfo.BlockHash, - TxIndex: transactionInfo.TxIndex, - } - return newTransactionInfo, nil - } - } - return transactionInfo, nil -} +//func checkRoleAndGenerateTransactionInfo(txSimContext protocol.TxSimContext, +// transactionInfo *commonPb.TransactionInfo) (*commonPb.TransactionInfo, error) { +// var ( +// reqSender protocol.Role +// err error +// ac protocol.AccessControlProvider +// ) +// tx := transactionInfo.Transaction +// +// if ac, err = txSimContext.GetAccessControl(); err != nil { +// return nil, err +// } +// +// if reqSender, err = utils.GetRoleFromTx(txSimContext.GetTx(), ac); err != nil { +// return nil, err +// } +// +// if reqSender == protocol.RoleLight { +// if tx.Sender.Signer.OrgId != txSimContext.GetTx().Sender.Signer.OrgId { +// newTransactionInfo := &commonPb.TransactionInfo{ +// Transaction: nil, +// BlockHeight: transactionInfo.BlockHeight, +// BlockHash: transactionInfo.BlockHash, +// TxIndex: transactionInfo.TxIndex, +// } +// return newTransactionInfo, nil +// } +// } +// return transactionInfo, nil +//} diff --git a/blockcontract/block_contract_test.go b/blockcontract/block_contract_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0af3e37bc2e4d711f6c17493bbcc3c74e8f0b3a1 --- /dev/null +++ b/blockcontract/block_contract_test.go @@ -0,0 +1,24 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package blockcontract + +import ( + "fmt" + "testing" + + "chainmaker.org/chainmaker/protocol/v2/test" + "github.com/stretchr/testify/require" +) + +func Test_handleError(t *testing.T) { + br := BlockRuntime{ + log: &test.GoLogger{}, + } + err := br.handleError(BlockHeight(0), fmt.Errorf("not found"), "chain1") + require.NotNil(t, err) + err = br.handleError(BlockHeight(0), nil, "chain1") + require.Nil(t, err) +} diff --git a/certmgr/cert_manage_contract.go b/certmgr/cert_manage_contract.go index b917df577ac493c5e8c40f7121a9ef0446c53a7f..981c887aa5dada4878a1670dffa3c5156130c323 100644 --- a/certmgr/cert_manage_contract.go +++ b/certmgr/cert_manage_contract.go @@ -18,10 +18,6 @@ import ( "errors" "fmt" "strings" - "time" - - "chainmaker.org/chainmaker/vm-native/chainconfigmgr" - "chainmaker.org/chainmaker/vm-native/common" bcx509 "chainmaker.org/chainmaker/common/v2/crypto/x509" pbac "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" @@ -30,6 +26,8 @@ import ( "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/chainconfigmgr" + "chainmaker.org/chainmaker/vm-native/v2/common" "github.com/gogo/protobuf/proto" ) @@ -60,13 +58,13 @@ func registerCertManageContractMethods(log protocol.Logger) map[string]common.Co // cert manager certManageRuntime := &CertManageRuntime{log: log} - methodMap[syscontract.CertManageFunction_CERT_ADD.String()] = certManageRuntime.Add - methodMap[syscontract.CertManageFunction_CERTS_DELETE.String()] = certManageRuntime.Delete - methodMap[syscontract.CertManageFunction_CERTS_FREEZE.String()] = certManageRuntime.Freeze - methodMap[syscontract.CertManageFunction_CERTS_UNFREEZE.String()] = certManageRuntime.Unfreeze - methodMap[syscontract.CertManageFunction_CERTS_REVOKE.String()] = certManageRuntime.Revoke + methodMap[syscontract.CertManageFunction_CERT_ADD.String()] = common.WrapResultFunc(certManageRuntime.Add) + methodMap[syscontract.CertManageFunction_CERTS_DELETE.String()] = common.WrapResultFunc(certManageRuntime.Delete) + methodMap[syscontract.CertManageFunction_CERTS_FREEZE.String()] = common.WrapResultFunc(certManageRuntime.Freeze) + methodMap[syscontract.CertManageFunction_CERTS_UNFREEZE.String()] = common.WrapResultFunc(certManageRuntime.Unfreeze) + methodMap[syscontract.CertManageFunction_CERTS_REVOKE.String()] = common.WrapResultFunc(certManageRuntime.Revoke) // query - methodMap[syscontract.CertManageFunction_CERTS_QUERY.String()] = certManageRuntime.Query + methodMap[syscontract.CertManageFunction_CERTS_QUERY.String()] = common.WrapResultFunc(certManageRuntime.Query) return methodMap } @@ -78,30 +76,29 @@ type CertManageRuntime struct { func (r *CertManageRuntime) Add(txSimContext protocol.TxSimContext, _ map[string][]byte) ( result []byte, err error) { - tx := txSimContext.GetTx() - sender := tx.Sender - memberInfo := sender.Signer.GetMemberInfo() + memberInfo := txSimContext.GetTx().Sender.Signer.GetMemberInfo() ac, err := txSimContext.GetAccessControl() if err != nil { - r.log.Errorf("txSimContext.GetAccessControl failed, err: %s", err.Error()) + r.log.Warnf("txSimContext.GetAccessControl failed, err: %s", err.Error()) return nil, err } hashType := ac.GetHashAlg() certHash, err := utils.GetCertificateIdHex(memberInfo, hashType) if err != nil { - r.log.Errorf("get certHash failed, err: %s", err.Error()) + r.log.Warnf("get certHash failed, err: %s", err.Error()) return nil, err } err = txSimContext.Put(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash), memberInfo) if err != nil { - r.log.Errorf("certManage add cert failed, err: %s", err.Error()) + r.log.Warnf("certManage add cert failed, err: %s", err.Error()) return nil, err } - r.log.Infof("certManage add cert success certHash[%s] memberInfo[%s]", certHash, string(memberInfo)) + r.log.Infof("certManage add cert success."+ + " certHash[%s] memberInfo[%s] hashType[%s]", certHash, string(memberInfo), hashType) return []byte(certHash), nil } @@ -114,7 +111,7 @@ func (r *CertManageRuntime) Delete(txSimContext protocol.TxSimContext, params ma if utils.IsAnyBlank(certHashesStr) { err = fmt.Errorf("%s, delete cert require param [%s] not found", common.ErrParams.Error(), paramNameCertHashes) - r.log.Error(err) + r.log.Warn(err) return nil, err } @@ -122,20 +119,20 @@ func (r *CertManageRuntime) Delete(txSimContext protocol.TxSimContext, params ma for _, certHash := range certHashes { bytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)) if err != nil { - r.log.Errorf("certManage delete the certHash failed, certHash[%s], err: %s", certHash, err.Error()) + r.log.Warnf("certManage delete the certHash failed, certHash[%s], err: %s", certHash, err.Error()) return nil, err } if len(bytes) == 0 { msg := fmt.Sprintf( "certManage delete the certHash failed, certHash[%s], err: certHash is not exist", certHash) - r.log.Error(msg) + r.log.Warnf(msg) return nil, errors.New(msg) } err = txSimContext.Del(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)) if err != nil { - r.log.Errorf("certManage txSimContext.Del failed, certHash[%s] err: %s", certHash, err.Error()) + r.log.Warnf("certManage txSimContext.Del failed, certHash[%s] err: %s", certHash, err.Error()) return nil, err } } @@ -152,7 +149,7 @@ func (r *CertManageRuntime) Query(txSimContext protocol.TxSimContext, params map if utils.IsAnyBlank(certHashesStr) { err := fmt.Errorf("%s, query cert require param [%s] not found", common.ErrParams.Error(), paramNameCertHashes) - r.log.Error(err) + r.log.Warn(err) return nil, err } @@ -161,7 +158,7 @@ func (r *CertManageRuntime) Query(txSimContext protocol.TxSimContext, params map for i, certHash := range certHashes { certBytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)) if err != nil { - r.log.Errorf("certManage delete the certHash failed, certHash[%s] err: %s", certHash, err.Error()) + r.log.Warnf("certManage delete the certHash failed, certHash[%s] err: %s", certHash, err.Error()) return nil, err } @@ -175,7 +172,7 @@ func (r *CertManageRuntime) Query(txSimContext protocol.TxSimContext, params map c.CertInfos = certInfos certBytes, err := proto.Marshal(c) if err != nil { - r.log.Errorf("certManage query proto.Marshal(c) err certHash[%s] err", certHashesStr, err) + r.log.Warnf("certManage query proto.Marshal(c) err certHash[%s] err", certHashesStr, err) return nil, err } @@ -199,7 +196,7 @@ func (r *CertManageRuntime) Freeze(txSimContext protocol.TxSimContext, params ma if utils.IsAnyBlank(certsStr) { err = fmt.Errorf("%s, freeze cert require param [%s] not found", common.ErrParams.Error(), paramNameCerts) - r.log.Error(err) + r.log.Warn(err) return nil, err } @@ -245,18 +242,18 @@ func (r *CertManageRuntime) Freeze(txSimContext protocol.TxSimContext, params ma } if !changed { - r.log.Error(common.ErrParams) + r.log.Warn(common.ErrParams) return nil, common.ErrParams } marshal, err := json.Marshal(freezeKeyArray) if err != nil { - r.log.Errorf("freezeKeyArray err: ", err.Error()) + r.log.Warnf("freezeKeyArray err: ", err.Error()) return nil, err } err = txSimContext.Put(syscontract.SystemContract_CERT_MANAGE.String(), []byte(protocol.CertFreezeKey), marshal) if err != nil { - r.log.Errorf("txSimContext put CERT_FREEZE_KEY err ", err.Error()) + r.log.Warnf("txSimContext put CERT_FREEZE_KEY err ", err.Error()) return nil, err } @@ -278,7 +275,7 @@ func (r *CertManageRuntime) Unfreeze(txSimContext protocol.TxSimContext, params } if len(freezeKeyArray) == 0 { - r.log.Errorf("no cert need to unfreeze") + r.log.Warnf("no cert need to unfreeze") return nil, errors.New("no cert need to unfreeze") } @@ -290,7 +287,7 @@ func (r *CertManageRuntime) Unfreeze(txSimContext protocol.TxSimContext, params if utils.IsAllBlank(certsStr, certHashesStr) { err = fmt.Errorf("%s, unfreeze cert require param [%s or %s] not found", common.ErrParams.Error(), paramNameCerts, paramNameCertHashes) - r.log.Error(err) + r.log.Warn(err) return nil, err } @@ -305,7 +302,7 @@ func (r *CertManageRuntime) Unfreeze(txSimContext protocol.TxSimContext, params } certHash, err1 := utils.GetCertificateIdHex([]byte(cert), hashType) if err1 != nil { - r.log.Errorf("GetCertificateIdHex failed, err: ", err1.Error()) + r.log.Warnf("GetCertificateIdHex failed, err: ", err1.Error()) continue } freezeKeyArray, changed = r.recoverFrozenCert(txSimContext, certHash, freezeKeyArray, certFullHashes, changed) @@ -320,18 +317,18 @@ func (r *CertManageRuntime) Unfreeze(txSimContext protocol.TxSimContext, params } if !changed { - r.log.Error(common.ErrParams) + r.log.Warn(common.ErrParams) return nil, common.ErrParams } marshal, err := json.Marshal(freezeKeyArray) if err != nil { - r.log.Errorf("freezeKeyArray err: ", err.Error()) + r.log.Warnf("freezeKeyArray err: ", err.Error()) return nil, err } err = txSimContext.Put(syscontract.SystemContract_CERT_MANAGE.String(), []byte(protocol.CertFreezeKey), marshal) if err != nil { - r.log.Errorf("txSimContext put CERT_FREEZE_KEY err: ", err.Error()) + r.log.Warnf("txSimContext put CERT_FREEZE_KEY err: ", err.Error()) return nil, err } @@ -350,17 +347,17 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma crlStr, ok := params[paramNameCertCrl] if !ok { err := fmt.Errorf("certManage cert revocation params err,cert_cerl is empty") - r.log.Error(err.Error()) + r.log.Warn(err.Error()) return nil, err } ac, err := txSimContext.GetAccessControl() if err != nil { - r.log.Errorf("certManage txSimContext.GetOrganization failed, err: ", err.Error()) + r.log.Warnf("certManage txSimContext.GetOrganization failed, err: ", err.Error()) return nil, err } _, err = ac.VerifyRelatedMaterial(pbac.VerifyType_CRL, crlStr) if err != nil { - r.log.Errorf("certManage validate crl failed err: ", err.Error()) + r.log.Warnf("certManage validate crl failed err: ", err.Error()) return nil, err } @@ -370,16 +367,17 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma for crlPEM != nil { crl, err1 := x509.ParseCRL(crlPEM.Bytes) if err1 != nil { - r.log.Errorf("certManage parse crl failed err: ", err1.Error()) + r.log.Warnf("certManage parse crl failed err: ", err1.Error()) return nil, err1 } + crlPEM, rest = pem.Decode(rest) crls = append(crls, crl) } crlBytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(protocol.CertRevokeKey)) if err != nil { - r.log.Errorf("get certManage crlList fail err: ", err.Error()) + r.log.Warnf("get certManage crlList fail err: ", err.Error()) return nil, fmt.Errorf("get certManage crlList failed, err: %s", err) } @@ -387,7 +385,7 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma if len(crlBytes) > 0 { err = json.Unmarshal(crlBytes, &crlKeyList) if err != nil { - r.log.Errorf("certManage unmarshal crl list err: ", err.Error()) + r.log.Warnf("certManage unmarshal crl list err: ", err.Error()) return nil, errors.New("unmarshal crl list err") } } @@ -396,14 +394,14 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma for _, crtList := range crls { aki, err1 := getAKI(crtList) if err1 != nil { - r.log.Errorf("certManage getAKI err: ", err1.Error()) + r.log.Warnf("certManage getAKI err: ", err1.Error()) continue } key := fmt.Sprintf("%s%s", protocol.CertRevokeKeyPrefix, hex.EncodeToString(aki)) crtListBytes, err1 := asn1.Marshal(*crtList) if err1 != nil { - r.log.Errorf("certManage marshal crt list err: ", err1.Error()) + r.log.Warnf("certManage marshal crt list err: ", err1.Error()) continue } @@ -427,7 +425,7 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma err = txSimContext.Put(syscontract.SystemContract_CERT_MANAGE.String(), []byte(key), toMemory) if err != nil { - r.log.Errorf("certManage save crl certs err: ", err.Error()) + r.log.Warnf("certManage save crl certs err: ", err.Error()) return nil, err } @@ -441,18 +439,18 @@ func (r *CertManageRuntime) Revoke(txSimContext protocol.TxSimContext, params ma } if !changed { - r.log.Error(common.ErrParams) + r.log.Warn(common.ErrParams) return nil, common.ErrParams } crlBytesResult, err := json.Marshal(crlKeyList) if err != nil { - r.log.Errorf("certManage marshal crlKeyList err: ", err.Error()) + r.log.Warnf("certManage marshal crlKeyList err: ", err.Error()) return nil, err } err = txSimContext.Put(syscontract.SystemContract_CERT_MANAGE.String(), []byte(protocol.CertRevokeKey), crlBytesResult) if err != nil { - r.log.Errorf("certManage txSimContext put CertRevokeKey err: ", err.Error()) + r.log.Warnf("certManage txSimContext put CertRevokeKey err: ", err.Error()) return nil, err } crlResultStr := strings.TrimRight(crlResult.String(), ",") @@ -471,7 +469,7 @@ func getAKI(crl *pkix.CertificateList) (aki []byte, err error) { func (r *CertManageRuntime) getFreezeKeyArray(txSimContext protocol.TxSimContext) (string, []string, error) { ac, err := txSimContext.GetAccessControl() if err != nil { - r.log.Errorf("txSimContext.GetAccessControl failed, err: ", err.Error()) + r.log.Warnf("txSimContext.GetAccessControl failed, err: ", err.Error()) return "", nil, err } hashType := ac.GetHashAlg() @@ -481,14 +479,14 @@ func (r *CertManageRuntime) getFreezeKeyArray(txSimContext protocol.TxSimContext freezeKeyArrayBytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(protocol.CertFreezeKey)) if err != nil { - r.log.Errorf("txSimContext get CERT_FREEZE_KEY err: ", err.Error()) + r.log.Warnf("txSimContext get CERT_FREEZE_KEY err: ", err.Error()) return "", nil, err } if len(freezeKeyArrayBytes) > 0 { err := json.Unmarshal(freezeKeyArrayBytes, &freezeKeyArray) if err != nil { - r.log.Errorf("unmarshal freeze key array err: ", err.Error()) + r.log.Warnf("unmarshal freeze key array err: ", err.Error()) return "", nil, err } } @@ -537,31 +535,11 @@ func (r *CertManageRuntime) checkCert(cert string, trustRoots []*configPb.TrustR return errors.New("can not freeze/unfreeze root certificate") } - // 判断是否是该ca签发的证书 - caPool := bcx509.NewCertPool() + caCerts := make([][]byte, 0) for _, root := range trustRoots { - for _, s := range root.Root { - pemBlock, rest := pem.Decode([]byte(s)) - for pemBlock != nil { - cert, _ := bcx509.ParseCertificate(pemBlock.Bytes) - caPool.AddCert(cert) - pemBlock, rest = pem.Decode(rest) - } + for _, certTmp := range root.Root { + caCerts = append(caCerts, []byte(certTmp)) } } - certChain, err := c.Verify(bcx509.VerifyOptions{ - Intermediates: caPool, - Roots: caPool, - CurrentTime: time.Time{}, - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, - MaxConstraintComparisions: 0, - }) - if err != nil { - r.log.Warn(err) - return err - } - if len(certChain) > 0 && len(certChain[0]) > 0 { - return nil - } - return errors.New("the cert is not in trust root") + return utils.VerifyCertIssue(caCerts, nil, []byte(cert)) } diff --git a/certmgr/cert_manage_contract_test.go b/certmgr/cert_manage_contract_test.go new file mode 100644 index 0000000000000000000000000000000000000000..69460c563c43f07c19506f3581aacd6dd101e624 --- /dev/null +++ b/certmgr/cert_manage_contract_test.go @@ -0,0 +1,152 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package certmgr + +import ( + "fmt" + "testing" + + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2/test" + "github.com/stretchr/testify/assert" + + "chainmaker.org/chainmaker/protocol/v2/mock" + "github.com/golang/mock/gomock" + + "chainmaker.org/chainmaker/protocol/v2" +) + +var ( + errCert = false +) + +func Test_AddCert(t *testing.T) { + mgrRuntime, txSimContext, fn := initEnv(t) + defer fn() + result, err := mgrRuntime.Add(txSimContext, nil) + assert.Nil(t, err) + assert.Equal(t, "e77c9238c51e3446d942f94bd8803cc4f351254f8771f972146d7bfc6e0be7f4", string(result)) + fmt.Printf("add cert success. cert hash: %s \n", result) + + errCert = true + _, err = mgrRuntime.Add(txSimContext, nil) + assert.NotNil(t, err) + errCert = false +} + +func Test_DeleteCert(t *testing.T) { + mgrRuntime, txSimContext, fn := initEnv(t) + defer fn() + + result, err := mgrRuntime.Add(txSimContext, nil) + assert.Equal(t, "e77c9238c51e3446d942f94bd8803cc4f351254f8771f972146d7bfc6e0be7f4", string(result)) + + params := make(map[string][]byte) + params[paramNameCertHashes] = []byte("e77c9238c51e3446d942f94bd8803cc4f351254f8771f972146d7bfc6e0be7f4") + result, err = mgrRuntime.Delete(txSimContext, params) + assert.Nil(t, err) + result, err = mgrRuntime.Delete(txSimContext, params) + assert.NotNil(t, err) + + _, err = mgrRuntime.Delete(txSimContext, nil) + assert.NotNil(t, err) +} + +var _ protocol.TxSimContext = (*mock.MockTxSimContext)(nil) + +func initEnv(t *testing.T) (*CertManageRuntime, *mock.MockTxSimContext, func()) { + certMgrRuntime := &CertManageRuntime{NewLogger()} + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + + acTest := mock.NewMockAccessControlProvider(ctrl) + acTest.EXPECT().GetHashAlg().Return("SHA256").AnyTimes() + txSimContext.EXPECT().GetAccessControl().Return(acTest, nil).AnyTimes() + + cache := NewCacheMock() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte, value []byte) error { + cache.Put(name, string(key), value) + return nil + }).AnyTimes() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte) ([]byte, error) { + return cache.Get(name, string(key)), nil + }).AnyTimes() + txSimContext.EXPECT().Del(gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte) error { + return cache.Del(name, string(key)) + }).AnyTimes() + txSimContext.EXPECT().GetTx().DoAndReturn( + func() *commonPb.Transaction { + return &commonPb.Transaction{ + Sender: &commonPb.EndorsementEntry{ + Signer: getOrg1Client1Signer(), + }, + } + }).AnyTimes() + return certMgrRuntime, txSimContext, func() { ctrl.Finish() } +} + +func getOrg1Client1Signer() *accesscontrol.Member { + certStr := "-----BEGIN CERTIFICATE-----\nMIICijCCAi+gAwIBAgIDBS9vMAoGCCqGSM49BAMCMIGKMQswCQYDVQQGEwJDTjEQ\nMA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzEfMB0GA1UEChMWd3gt\nb3JnMS5jaGFpbm1ha2VyLm9yZzESMBAGA1UECxMJcm9vdC1jZXJ0MSIwIAYDVQQD\nExljYS53eC1vcmcxLmNoYWlubWFrZXIub3JnMB4XDTIwMTIwODA2NTM0M1oXDTI1\nMTIwNzA2NTM0M1owgZExCzAJBgNVBAYTAkNOMRAwDgYDVQQIEwdCZWlqaW5nMRAw\nDgYDVQQHEwdCZWlqaW5nMR8wHQYDVQQKExZ3eC1vcmcxLmNoYWlubWFrZXIub3Jn\nMQ8wDQYDVQQLEwZjbGllbnQxLDAqBgNVBAMTI2NsaWVudDEuc2lnbi53eC1vcmcx\nLmNoYWlubWFrZXIub3JnMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE56xayRx0\n/a8KEXPxRfiSzYgJ/sE4tVeI/ZbjpiUX9m0TCJX7W/VHdm6WeJLOdCDuLLNvjGTy\nt8LLyqyubJI5AKN7MHkwDgYDVR0PAQH/BAQDAgGmMA8GA1UdJQQIMAYGBFUdJQAw\nKQYDVR0OBCIEIMjAiM2eMzlQ9HzV9ePW69rfUiRZVT2pDBOMqM4WVJSAMCsGA1Ud\nIwQkMCKAIDUkP3EcubfENS6TH3DFczH5dAnC2eD73+wcUF/bEIlnMAoGCCqGSM49\nBAMCA0kAMEYCIQCWUHL0xisjQoW+o6VV12pBXIRJgdeUeAu2EIjptSg2GAIhAIxK\nLXpHIBFxIkmWlxUaanCojPSZhzEbd+8LRrmhEO8n\n-----END CERTIFICATE-----" + if errCert { + certStr = "-----BEGIN CERTIFICATE-----\nMIICijCCAi+gAwIBAgIDBS9vMAoCqGSM49BAMCMIGKMQswCQYDVQQGEwJDTjEQ\nMA4GA1UECBMHQmVpamluZzEQMA4GA1UEmVpamluZzEfMB0GA1UEChMWd3gt\nb3JnMS5jaGFpbm1ha2VyLm9yZzESMBAGA1UECxMJcm9vdC1jZXJ0MSIwIAYDVQQD\nExljYS53eC1vcmcxLmNoYWlubWFrZXIub3JnMB4XDTIwMTIwODA2NTM0M1oXDTI1\nMTIwNzA2NTM0M1owgZExCzAJBgNVBAYTAkNOMRAwDgYDVQQIEwdCZWlqaW5nMRAw\nDgYDVQQHEwdCZWlqaW5nMR8wHQYDVQQKExZ3eC1vcmcxLmNoYWlubWFrZXIub3Jn\nMQ8wDQYDVQQLEwZjbGllbnQxLDAqBgNVBAMTI2NsaWVudDEuc2lnbi53eC1vcmcx\nLmNoYWlubWFrZXIub3JnMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE56xayRx0/a8KEXPxRfiSzYgJ/sE4tVeI/ZbjpiUX9m0TCJX7W/VHdm6WeJLOdCDuLLNvjGTy\nt8LLyqyubJI5AKN7MHkwDgYDVR0PAQH/BAQDAgGmMA8GA1UdJQQIMAYGBFUdJQAw\nKQYDVR0OBCIEIMjAiM2eMzlQ9HzV9ePW69rfUiRZVT2pDBOMqM4WVJSAMCsGA1Ud\nIwQkMCKAIDUkP3EcubfENS6TH3DFczH5dAnC2eD73+wcUF/bEIlnMAoGCCqGSM49\nBAMCA0kAMEYCIQCWUHisjQoW+o6VV12pBXIRJgdeUeAu2EIjptSg2GAIhAIxK\nLXpHIBFxIkmWlxUaanCojPSEbd+8LRrmhEO8n\n-----END CERTIFICATE-----" + } + return &accesscontrol.Member{ + OrgId: "wx-org1.chainmaker.org", + MemberType: accesscontrol.MemberType_CERT, + MemberInfo: []byte(certStr), + } +} +func NewLogger() protocol.Logger { + cmLogger := &test.GoLogger{} + return cmLogger +} + +const KeyFormat = "%s/%s" + +func realKey(name, key string) string { + return fmt.Sprintf(KeyFormat, name, key) +} + +type CacheMock struct { + content map[string][]byte +} + +func NewCacheMock() *CacheMock { + return &CacheMock{ + content: make(map[string][]byte, 64), + } +} + +func (c *CacheMock) Put(name, key string, value []byte) { + c.content[realKey(name, key)] = value +} + +func (c *CacheMock) Get(name, key string) []byte { + return c.content[realKey(name, key)] +} + +func (c *CacheMock) Del(name, key string) error { + delete(c.content, realKey(name, key)) + return nil +} + +func (c *CacheMock) GetByKey(key string) []byte { + return c.content[key] +} + +func (c *CacheMock) Keys() []string { + sc := make([]string, 0) + for k := range c.content { + sc = append(sc, k) + } + return sc +} diff --git a/chainconfigmgr/chain_config_contract.go b/chainconfigmgr/chain_config_contract.go index 7d65b9c4305762ea02ddfacefd46915deae527c0..809efd22a05421e6bf3a135ca855060c839a9512 100644 --- a/chainconfigmgr/chain_config_contract.go +++ b/chainconfigmgr/chain_config_contract.go @@ -13,15 +13,16 @@ import ( "strconv" "strings" - "chainmaker.org/chainmaker/vm-native/common" - "chainmaker.org/chainmaker/chainconf/v2" "chainmaker.org/chainmaker/common/v2/sortedmap" acPb "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" configPb "chainmaker.org/chainmaker/pb-go/v2/config" + "chainmaker.org/chainmaker/pb-go/v2/consensus" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" "github.com/gogo/protobuf/proto" ) @@ -36,6 +37,8 @@ const ( paramNameTxSchedulerTimeout = "tx_scheduler_timeout" paramNameTxSchedulerValidateTimeout = "tx_scheduler_validate_timeout" + paramNameEnableSenderGroup = "enable_sender_group" + paramNameEnableConflictsBitWindow = "enable_conflicts_bit_window" paramNameTxTimestampVerify = "tx_timestamp_verify" paramNameTxTimeout = "tx_timeout" @@ -43,6 +46,7 @@ const ( paramNameChainBlockSize = "block_size" paramNameChainBlockInterval = "block_interval" paramNameChainBlockHeight = "block_height" + paramNameAddrType = "addr_type" defaultConfigMaxValidateTimeout = 60 defaultConfigMaxSchedulerTimeout = 60 @@ -74,49 +78,77 @@ func registerChainConfigContractMethods(log protocol.Logger) map[string]common.C // [core] coreRuntime := &ChainCoreRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_CORE_UPDATE.String()] = coreRuntime.CoreUpdate + methodMap[syscontract.ChainConfigFunction_CORE_UPDATE.String()] = common.WrapResultFunc(coreRuntime.CoreUpdate) // [block] blockRuntime := &ChainBlockRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_BLOCK_UPDATE.String()] = blockRuntime.BlockUpdate + methodMap[syscontract.ChainConfigFunction_BLOCK_UPDATE.String()] = common.WrapResultFunc(blockRuntime.BlockUpdate) // [trust_root] trustRootsRuntime := &ChainTrustRootsRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_ADD.String()] = trustRootsRuntime.TrustRootAdd - methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_UPDATE.String()] = trustRootsRuntime.TrustRootUpdate - methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_DELETE.String()] = trustRootsRuntime.TrustRootDelete + methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_ADD.String()] = common.WrapResultFunc( + trustRootsRuntime.TrustRootAdd) + methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_UPDATE.String()] = common.WrapResultFunc( + trustRootsRuntime.TrustRootUpdate) + methodMap[syscontract.ChainConfigFunction_TRUST_ROOT_DELETE.String()] = common.WrapResultFunc( + trustRootsRuntime.TrustRootDelete) // [trust_Member] trustMembersRuntime := &ChainTrustMembersRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_TRUST_MEMBER_ADD.String()] = trustMembersRuntime.TrustMemberAdd - methodMap[syscontract.ChainConfigFunction_TRUST_MEMBER_DELETE.String()] = trustMembersRuntime.TrustMemberDelete + methodMap[syscontract.ChainConfigFunction_TRUST_MEMBER_ADD.String()] = common.WrapResultFunc( + trustMembersRuntime.TrustMemberAdd) + methodMap[syscontract.ChainConfigFunction_TRUST_MEMBER_DELETE.String()] = common.WrapResultFunc( + trustMembersRuntime.TrustMemberDelete) // [consensus] consensusRuntime := &ChainConsensusRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_NODE_ID_ADD.String()] = consensusRuntime.NodeIdAdd - methodMap[syscontract.ChainConfigFunction_NODE_ID_UPDATE.String()] = consensusRuntime.NodeIdUpdate - methodMap[syscontract.ChainConfigFunction_NODE_ID_DELETE.String()] = consensusRuntime.NodeIdDelete - methodMap[syscontract.ChainConfigFunction_NODE_ORG_ADD.String()] = consensusRuntime.NodeOrgAdd - methodMap[syscontract.ChainConfigFunction_NODE_ORG_UPDATE.String()] = consensusRuntime.NodeOrgUpdate - methodMap[syscontract.ChainConfigFunction_NODE_ORG_DELETE.String()] = consensusRuntime.NodeOrgDelete - methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_ADD.String()] = consensusRuntime.ConsensusExtAdd - methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_UPDATE.String()] = consensusRuntime.ConsensusExtUpdate - methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_DELETE.String()] = consensusRuntime.ConsensusExtDelete + methodMap[syscontract.ChainConfigFunction_NODE_ID_ADD.String()] = common.WrapResultFunc( + consensusRuntime.NodeIdAdd) + methodMap[syscontract.ChainConfigFunction_NODE_ID_UPDATE.String()] = common.WrapResultFunc( + consensusRuntime.NodeIdUpdate) + methodMap[syscontract.ChainConfigFunction_NODE_ID_DELETE.String()] = common.WrapResultFunc( + consensusRuntime.NodeIdDelete) + methodMap[syscontract.ChainConfigFunction_NODE_ORG_ADD.String()] = common.WrapResultFunc( + consensusRuntime.NodeOrgAdd) + methodMap[syscontract.ChainConfigFunction_NODE_ORG_UPDATE.String()] = common.WrapResultFunc( + consensusRuntime.NodeOrgUpdate) + methodMap[syscontract.ChainConfigFunction_NODE_ORG_DELETE.String()] = common.WrapResultFunc( + consensusRuntime.NodeOrgDelete) + methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_ADD.String()] = common.WrapResultFunc( + consensusRuntime.ConsensusExtAdd) + methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_UPDATE.String()] = common.WrapResultFunc( + consensusRuntime.ConsensusExtUpdate) + methodMap[syscontract.ChainConfigFunction_CONSENSUS_EXT_DELETE.String()] = common.WrapResultFunc( + consensusRuntime.ConsensusExtDelete) // [permission] - methodMap[syscontract.ChainConfigFunction_PERMISSION_ADD.String()] = consensusRuntime.ResourcePolicyAdd - methodMap[syscontract.ChainConfigFunction_PERMISSION_UPDATE.String()] = consensusRuntime.ResourcePolicyUpdate - methodMap[syscontract.ChainConfigFunction_PERMISSION_DELETE.String()] = consensusRuntime.ResourcePolicyDelete + methodMap[syscontract.ChainConfigFunction_PERMISSION_ADD.String()] = common.WrapResultFunc( + consensusRuntime.ResourcePolicyAdd) + methodMap[syscontract.ChainConfigFunction_PERMISSION_UPDATE.String()] = common.WrapResultFunc( + consensusRuntime.ResourcePolicyUpdate) + methodMap[syscontract.ChainConfigFunction_PERMISSION_DELETE.String()] = common.WrapResultFunc( + consensusRuntime.ResourcePolicyDelete) // [chainConfig] ccRuntime := &ChainConfigRuntime{log: log} - methodMap[syscontract.ChainConfigFunction_GET_CHAIN_CONFIG.String()] = ccRuntime.GetChainConfig - methodMap[syscontract.ChainConfigFunction_GET_CHAIN_CONFIG_AT.String()] = ccRuntime.GetChainConfigFromBlockHeight + methodMap[syscontract.ChainConfigFunction_GET_CHAIN_CONFIG.String()] = common.WrapResultFunc( + ccRuntime.GetChainConfig) + methodMap[syscontract.ChainConfigFunction_GET_CHAIN_CONFIG_AT.String()] = common.WrapResultFunc( + ccRuntime.GetChainConfigFromBlockHeight) + + // [account config] + methodMap[syscontract.ChainConfigFunction_ENABLE_OR_DISABLE_GAS.String()] = common.WrapResultFunc( + ccRuntime.EnableOrDisableGas) + + methodMap[syscontract.ChainConfigFunction_ALTER_ADDR_TYPE.String()] = common.WrapResultFunc( + ccRuntime.AlterAddrType) //// [archive] //archiveStoreRuntime := &ArchiveStoreRuntime{log: log} - //methodMap[commonPb.ArchiveStoreContractFunction_ARCHIVE_BLOCK.String()] = archiveStoreRuntime.ArchiveBlock - //methodMap[commonPb.ArchiveStoreContractFunction_RESTORE_BLOCKS.String()] = archiveStoreRuntime.RestoreBlock + //methodMap[commonPb.ArchiveStoreContractFunction_ARCHIVE_BLOCK.String()] = common.WrapResultFunc( + //archiveStoreRuntime.ArchiveBlock + //methodMap[commonPb.ArchiveStoreContractFunction_RESTORE_BLOCKS.String()] = common.WrapResultFunc( + //archiveStoreRuntime.RestoreBlock return methodMap } @@ -127,6 +159,10 @@ func getChainConfig(txSimContext protocol.TxSimContext, params map[string][]byte if params == nil { return nil, common.ErrParamsEmpty } + return GetChainConfigEmptyParams(txSimContext) +} + +func GetChainConfigEmptyParams(txSimContext protocol.TxSimContext) (*configPb.ChainConfig, error) { bytes, err := txSimContext.Get(chainConfigContractName, []byte(keyChainConfig)) if err != nil { msg := fmt.Errorf("txSimContext get failed, name[%s] key[%s] err: %+v", @@ -140,11 +176,10 @@ func getChainConfig(txSimContext protocol.TxSimContext, params map[string][]byte msg := fmt.Errorf("unmarshal chainConfig failed, contractName %s err: %+v", chainConfigContractName, err) return nil, msg } - return &chainConfig, nil } -func setChainConfig(txSimContext protocol.TxSimContext, chainConfig *configPb.ChainConfig) ([]byte, error) { +func SetChainConfig(txSimContext protocol.TxSimContext, chainConfig *configPb.ChainConfig) ([]byte, error) { _, err := chainconf.VerifyChainConfig(chainConfig) if err != nil { return nil, err @@ -164,7 +199,7 @@ func setChainConfig(txSimContext protocol.TxSimContext, chainConfig *configPb.Ch return pbccPayload, nil } -// [core] +// ChainConfigRuntime get chain config info type ChainConfigRuntime struct { log protocol.Logger } @@ -183,7 +218,7 @@ func (r *ChainConfigRuntime) GetChainConfig(txSimContext protocol.TxSimContext, return bytes, nil } -// GetChainConfigAt get chain config from less than or equal to block height +// GetChainConfigFromBlockHeight get chain config from less than or equal to block height func (r *ChainConfigRuntime) GetChainConfigFromBlockHeight(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { if params == nil { @@ -196,8 +231,23 @@ func (r *ChainConfigRuntime) GetChainConfigFromBlockHeight(txSimContext protocol r.log.Error(err) return nil, err } - chainConfig, err := chainconf.GetChainConfigAt(r.log, nil, nil, txSimContext.GetBlockchainStore(), - blockHeight) + blockchainStore := txSimContext.GetBlockchainStore() + header, err := blockchainStore.GetBlockHeaderByHeight(blockHeight) + if err != nil { + r.log.Errorf("get block header(height: %d) from store failed, %s", blockHeight, err) + return nil, err + } + configHeight := blockHeight + if header.BlockType != commonPb.BlockType_CONFIG_BLOCK { + configHeight = header.PreConfHeight + } + configBlock, err := blockchainStore.GetBlock(configHeight) + if err != nil { + r.log.Errorf("get block(height: %d) from store failed, %s", configHeight, err) + return nil, err + } + + chainConfig, err := r.getConfigFromBlock(configBlock) if err != nil { r.log.Error("get chain config from block height failed, err: %s", err) return nil, err @@ -209,8 +259,85 @@ func (r *ChainConfigRuntime) GetChainConfigFromBlockHeight(txSimContext protocol } return bytes, nil } +func (c *ChainConfigRuntime) getConfigFromBlock(block *commonPb.Block) (*configPb.ChainConfig, error) { + txConfig := block.Txs[0] + if txConfig.Result == nil || txConfig.Result.ContractResult == nil || txConfig.Result.ContractResult.Result == nil { + c.log.Errorf("tx(id: %s) is not config tx", txConfig.Payload.TxId) + return nil, errors.New("tx is not config tx") + } + result := txConfig.Result.ContractResult.Result + chainConfig := &configPb.ChainConfig{} + err := proto.Unmarshal(result, chainConfig) + if err != nil { + return nil, err + } + + return chainConfig, nil +} + +// AlterAddrType upgrade the type of address +func (r *ChainConfigRuntime) AlterAddrType(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, + err error) { + var chainConfig *configPb.ChainConfig + chainConfig, err = getChainConfig(txSimContext, params) + if err != nil { + return nil, err + } + + addrTypeBytes, ok := params[paramNameAddrType] + if !ok { + err = fmt.Errorf("alter address type failed, require param [%s], but not found", paramNameAddrType) + r.log.Error(err) + return nil, err + } + + addrType, err := strconv.ParseUint(string(addrTypeBytes), 10, 0) + if err != nil { + err = fmt.Errorf("alter address type failed, failed to parse address type from param[%s]", paramNameAddrType) + r.log.Error(err) + return nil, err + } + + at := configPb.AddrType(int32(addrType)) + if at == chainConfig.Vm.AddrType { + return []byte{}, nil + } + + chainConfig.Vm.AddrType = at + result, err = SetChainConfig(txSimContext, chainConfig) + if err != nil { + r.log.Error(err) + return nil, err + } + return result, nil +} + +// EnableOrDisableGas enable or able gas +func (r *ChainConfigRuntime) EnableOrDisableGas(txSimContext protocol.TxSimContext, + params map[string][]byte) (result []byte, err error) { + + var chainConfig *configPb.ChainConfig + chainConfig, err = GetChainConfigEmptyParams(txSimContext) + if err != nil { + return nil, err + } + + if chainConfig.AccountConfig != nil { + chainConfig.AccountConfig.EnableGas = !chainConfig.AccountConfig.EnableGas + } else { + chainConfig.AccountConfig = &configPb.GasAccountConfig{ + EnableGas: true, + } + } + result, err = SetChainConfig(txSimContext, chainConfig) + if err != nil { + r.log.Error(err) + return nil, err + } + return result, nil +} -// [core] +// ChainCoreRuntime chain core config update type ChainCoreRuntime struct { log protocol.Logger } @@ -255,12 +382,24 @@ func (r *ChainCoreRuntime) CoreUpdate(txSimContext protocol.TxSimContext, params changed = true } + if enableSenderGroup, ok := params[paramNameEnableSenderGroup]; ok { + parseBool, _ := strconv.ParseBool(string(enableSenderGroup)) + chainConfig.Core.EnableSenderGroup = parseBool + changed = true + } + + if enableConflictsBitWindow, ok := params[paramNameEnableConflictsBitWindow]; ok { + parseBool, _ := strconv.ParseBool(string(enableConflictsBitWindow)) + chainConfig.Core.EnableConflictsBitWindow = parseBool + changed = true + } + if !changed { r.log.Error(common.ErrParams) return nil, common.ErrParams } // [end] - result, err := setChainConfig(txSimContext, chainConfig) + result, err := SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("core update update fail, %s, params %+v", err.Error(), params) } else { @@ -269,7 +408,7 @@ func (r *ChainCoreRuntime) CoreUpdate(txSimContext protocol.TxSimContext, params return result, err } -// [block] +// ChainBlockRuntime chain block config update type ChainBlockRuntime struct { log protocol.Logger } @@ -314,7 +453,7 @@ func (r *ChainBlockRuntime) BlockUpdate(txSimContext protocol.TxSimContext, para return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("block update fail, %s, params %+v", err.Error(), params) } else { @@ -323,7 +462,7 @@ func (r *ChainBlockRuntime) BlockUpdate(txSimContext protocol.TxSimContext, para return result, err } -// [trust_root] +// ChainTrustRootsRuntime chain trust root manager type ChainTrustRootsRuntime struct { log protocol.Logger } @@ -348,9 +487,20 @@ func (r *ChainTrustRootsRuntime) TrustRootAdd(txSimContext protocol.TxSimContext } root := strings.Split(rootCasStr, ",") - trustRoot := &configPb.TrustRootConfig{OrgId: orgId, Root: root} - chainConfig.TrustRoots = append(chainConfig.TrustRoots, trustRoot) - result, err = setChainConfig(txSimContext, chainConfig) + existOrgId := false + for i := 0; i < len(chainConfig.TrustRoots); i++ { + if chainConfig.TrustRoots[i].OrgId == orgId { + existOrgId = true + chainConfig.TrustRoots[i].Root = append(chainConfig.TrustRoots[i].Root, root...) + } + } + + if !existOrgId { + trustRoot := &configPb.TrustRootConfig{OrgId: orgId, Root: root} + chainConfig.TrustRoots = append(chainConfig.TrustRoots, trustRoot) + } + + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("trust root add fail, %s, orgId[%s] cert[%s]", err.Error(), orgId, rootCasStr) } else { @@ -379,13 +529,24 @@ func (r *ChainTrustRootsRuntime) TrustRootUpdate(txSimContext protocol.TxSimCont return nil, err } + // verify has consensus nodes + if useCert(chainConfig.AuthType) { + for _, node := range chainConfig.Consensus.Nodes { + if orgId == node.OrgId { + err = fmt.Errorf("update trust root cert failed, you must delete all consensus nodes under the organization first") + r.log.Error(err) + return nil, err + } + } + } + root := strings.Split(rootCasStr, ",") trustRoots := chainConfig.TrustRoots for i, trustRoot := range trustRoots { if orgId == trustRoot.OrgId { trustRoots[i] = &configPb.TrustRootConfig{OrgId: orgId, Root: root} - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("trust root update fail, %s, orgId[%s] cert[%s]", err.Error(), orgId, rootCasStr) } else { @@ -400,7 +561,9 @@ func (r *ChainTrustRootsRuntime) TrustRootUpdate(txSimContext protocol.TxSimCont return nil, err } -// TrustRootDelete delete trustRoot +// TrustRootDelete +// delete the org all trust root +// must not contain the consensus node cert issued by the cert func (r *ChainTrustRootsRuntime) TrustRootDelete(txSimContext protocol.TxSimContext, params map[string][]byte) ( result []byte, err error) { // [start] @@ -433,15 +596,20 @@ func (r *ChainTrustRootsRuntime) TrustRootDelete(txSimContext protocol.TxSimCont } trustRoots = append(trustRoots[:index], trustRoots[index+1:]...) - nodes := chainConfig.Consensus.Nodes - for i := len(nodes) - 1; i >= 0; i-- { - if orgId == nodes[i].OrgId { - nodes = append(nodes[:i], nodes[i+1:]...) + + // verify has consensus nodes + if useCert(chainConfig.AuthType) { + for _, node := range chainConfig.Consensus.Nodes { + if orgId == node.OrgId { + err = fmt.Errorf("update trust root cert failed, you must delete all consensus nodes under the organization first") + r.log.Error(err) + return nil, err + } } } - chainConfig.Consensus.Nodes = nodes + chainConfig.TrustRoots = trustRoots - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("trust root delete fail, %s, orgId[%s] ", err.Error(), orgId) } else { @@ -450,7 +618,7 @@ func (r *ChainTrustRootsRuntime) TrustRootDelete(txSimContext protocol.TxSimCont return result, err } -// [trust_root] +// ChainTrustMembersRuntime trust member(third cert) manager type ChainTrustMembersRuntime struct { log protocol.Logger } @@ -484,7 +652,7 @@ func (r *ChainTrustMembersRuntime) TrustMemberAdd(txSimContext protocol.TxSimCon } trustMember := &configPb.TrustMemberConfig{MemberInfo: memberInfo, OrgId: orgId, Role: role, NodeId: nodeId} chainConfig.TrustMembers = append(chainConfig.TrustMembers, trustMember) - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("trust member add fail, %s, orgId[%s] memberInfo[%s] role[%s] nodeId[%s]", err.Error(), orgId, memberInfo, role, nodeId) @@ -529,7 +697,7 @@ func (r *ChainTrustMembersRuntime) TrustMemberDelete(txSimContext protocol.TxSim trustMembers = append(trustMembers[:index], trustMembers[index+1:]...) chainConfig.TrustMembers = trustMembers - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("trust member delete fail, %s, nodeId[%s] ", err.Error(), memberInfo) } else { @@ -538,7 +706,7 @@ func (r *ChainTrustMembersRuntime) TrustMemberDelete(txSimContext protocol.TxSim return result, err } -// [consensus] +// ChainConsensusRuntime chain consensus config update type ChainConsensusRuntime struct { log protocol.Logger } @@ -598,7 +766,7 @@ func (r *ChainConsensusRuntime) NodeIdAdd(txSimContext protocol.TxSimContext, pa return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node id add fail, %s, orgId[%s] nodeIdsStr[%s]", err.Error(), orgId, nodeIdsStr) } else { @@ -617,6 +785,11 @@ func (r *ChainConsensusRuntime) NodeIdUpdate(txSimContext protocol.TxSimContext, return nil, err } + if isRaft(chainConfig) { + err = fmt.Errorf("raft consensus does not support update node id, please use delete and add operation") + r.log.Error(err) + return nil, err + } // verify params orgId := string(params[paramNameOrgId]) nodeId := string(params[paramNameNodeId]) // origin node id @@ -654,7 +827,7 @@ func (r *ChainConsensusRuntime) NodeIdUpdate(txSimContext protocol.TxSimContext, nodeConf.NodeId[j] = newNodeId nodes[index] = nodeConf chainConfig.Consensus.Nodes = nodes - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node id update fail, %s, orgId[%s] addr[%s] newAddr[%s]", err.Error(), orgId, nid, newNodeId) @@ -671,6 +844,7 @@ func (r *ChainConsensusRuntime) NodeIdUpdate(txSimContext protocol.TxSimContext, } // NodeIdDelete delete nodeId +// raft consensus in public key mode, when delete nodes, the remaining consensus nodes counts need >= 2 func (r *ChainConsensusRuntime) NodeIdDelete(txSimContext protocol.TxSimContext, params map[string][]byte) ( result []byte, err error) { // [start] @@ -689,6 +863,12 @@ func (r *ChainConsensusRuntime) NodeIdDelete(txSimContext protocol.TxSimContext, return nil, err } + err = verifyConsensusCount(chainConfig, nodeId, "") + if err != nil { + r.log.Error(err) + return nil, err + } + nodes := chainConfig.Consensus.Nodes index := -1 var nodeConf *configPb.OrgConfig @@ -712,7 +892,7 @@ func (r *ChainConsensusRuntime) NodeIdDelete(txSimContext protocol.TxSimContext, nodeConf.NodeId = append(nodeIds[:j], nodeIds[j+1:]...) nodes[index] = nodeConf chainConfig.Consensus.Nodes = nodes - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node id delete fail, %s, orgId[%s] addr[%s]", err.Error(), orgId, nid) } else { @@ -767,7 +947,7 @@ func (r *ChainConsensusRuntime) NodeOrgAdd(txSimContext protocol.TxSimContext, p if len(org.NodeId) > 0 { chainConfig.Consensus.Nodes = append(chainConfig.Consensus.Nodes, org) - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node org add fail, %s, orgId[%s] nodeIdsStr[%s]", err.Error(), orgId, nodeIdsStr) } else { @@ -789,6 +969,11 @@ func (r *ChainConsensusRuntime) NodeOrgUpdate(txSimContext protocol.TxSimContext r.log.Error(err) return nil, err } + if isRaft(chainConfig) { + err = fmt.Errorf("raft consensus does not support update node id, please use delete and add operation") + r.log.Error(err) + return nil, err + } // verify params changed := false @@ -835,8 +1020,15 @@ func (r *ChainConsensusRuntime) NodeOrgUpdate(txSimContext protocol.TxSimContext r.log.Error(common.ErrParams) return nil, common.ErrParams } + + err = verifyConsensusCount(chainConfig, "", "") + if err != nil { + r.log.Error(err) + return nil, err + } + // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node org update fail, %s, orgId[%s] nodeIdsStr[%s]", err.Error(), orgId, nodeIdsStr) } else { @@ -846,6 +1038,7 @@ func (r *ChainConsensusRuntime) NodeOrgUpdate(txSimContext protocol.TxSimContext } // NodeOrgDelete delete nodeOrg +// raft consensus in public key mode, when delete nodes, the remaining consensus nodes counts need >= 2 func (r *ChainConsensusRuntime) NodeOrgDelete(txSimContext protocol.TxSimContext, params map[string][]byte) ( result []byte, err error) { // [start] @@ -864,6 +1057,12 @@ func (r *ChainConsensusRuntime) NodeOrgDelete(txSimContext protocol.TxSimContext return nil, err } + err = verifyConsensusCount(chainConfig, "", orgId) + if err != nil { + r.log.Error(err) + return nil, err + } + nodes := chainConfig.Consensus.Nodes if len(nodes) == 1 { err1 := fmt.Errorf("there is at least one org") @@ -875,7 +1074,7 @@ func (r *ChainConsensusRuntime) NodeOrgDelete(txSimContext protocol.TxSimContext nodes = append(nodes[:i], nodes[i+1:]...) chainConfig.Consensus.Nodes = nodes - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("node org delete fail, %s, orgId[%s]", err.Error(), orgId) } else { @@ -942,7 +1141,7 @@ func (r *ChainConsensusRuntime) ConsensusExtAdd(txSimContext protocol.TxSimConte return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("consensus ext add fail, %s, params %+v", err.Error(), params) } else { @@ -995,7 +1194,7 @@ func (r *ChainConsensusRuntime) ConsensusExtUpdate(txSimContext protocol.TxSimCo return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("consensus ext update fail, %s, params %+v", err.Error(), params) } else { @@ -1044,7 +1243,7 @@ func (r *ChainConsensusRuntime) ConsensusExtDelete(txSimContext protocol.TxSimCo return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("consensus ext delete fail, %s, params %+v", err.Error(), params) } else { @@ -1137,7 +1336,7 @@ func (r *ChainConsensusRuntime) ResourcePolicyAdd(txSimContext protocol.TxSimCon return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("resource policy add fail, %s, params %+v", err.Error(), params) } else { @@ -1226,7 +1425,7 @@ func (r *ChainConsensusRuntime) ResourcePolicyUpdate(txSimContext protocol.TxSim return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("resource policy update fail, %s, params %+v", err.Error(), params) } else { @@ -1308,7 +1507,7 @@ func (r *ChainConsensusRuntime) ResourcePolicyDelete(txSimContext protocol.TxSim return nil, common.ErrParams } // [end] - result, err = setChainConfig(txSimContext, chainConfig) + result, err = SetChainConfig(txSimContext, chainConfig) if err != nil { r.log.Errorf("resource policy delete fail, %s, params %+v", err.Error(), params) } else { @@ -1316,3 +1515,37 @@ func (r *ChainConsensusRuntime) ResourcePolicyDelete(txSimContext protocol.TxSim } return result, err } + +func useCert(authType string) bool { + authType = strings.ToLower(authType) + return authType == protocol.PermissionedWithCert || authType == protocol.Identity || authType == "" +} + +func verifyConsensusCount(chainConfig *configPb.ChainConfig, nodeId, orgId string) error { + // raft && pubKey, verify nodeIds count + if isRaftPubKey(chainConfig) { + count := 0 + for _, node := range chainConfig.Consensus.Nodes { + if orgId == node.OrgId { + continue + } + for _, nodeIdTmp := range node.NodeId { + if nodeId == nodeIdTmp { + continue + } + count++ + } + } + if count < 2 { + return fmt.Errorf("raft use pubkey, when delete nodes, the remaining consensus nodes counts need >= 2") + } + } + return nil +} + +func isRaftPubKey(chainConfig *configPb.ChainConfig) bool { + return chainConfig.Consensus.Type == consensus.ConsensusType_RAFT && !useCert(chainConfig.AuthType) +} +func isRaft(chainConfig *configPb.ChainConfig) bool { + return chainConfig.Consensus.Type == consensus.ConsensusType_RAFT +} diff --git a/common/errors.go b/common/errors.go index edad5c7f628576518f4fa4ed95511d2d2479d8fb..22cfe0086a034d1c746600cfa5b2b1f40eade23e 100644 --- a/common/errors.go +++ b/common/errors.go @@ -10,14 +10,24 @@ package common import "errors" var ( - ErrContractIdIsNil = errors.New("the contractId is empty") + // ErrContractIdIsNil err msg + ErrContractIdIsNil = errors.New("the contractId is empty") + // ErrContractNotFound err msg ErrContractNotFound = errors.New("the contractName is not exist") + // ErrTxTypeNotSupport err msg ErrTxTypeNotSupport = errors.New("the txType does not support") - ErrMethodNotFound = errors.New("the method does not found") - ErrParamsEmpty = errors.New("the params is empty") - ErrContractName = errors.New("the contractName is error") - ErrOutOfRange = errors.New("out of range") - ErrParams = errors.New("params is error") - ErrSequence = errors.New("sequence is error") - ErrUnmarshalFailed = errors.New("unmarshal is error") + // ErrMethodNotFound err msg + ErrMethodNotFound = errors.New("the method does not found") + // ErrParamsEmpty err msg + ErrParamsEmpty = errors.New("the params is empty") + // ErrContractName err msg + ErrContractName = errors.New("the contractName is error") + // ErrOutOfRange err msg + ErrOutOfRange = errors.New("out of range") + // ErrParams err msg + ErrParams = errors.New("params is error") + // ErrSequence err msg + ErrSequence = errors.New("sequence is error") + // ErrUnmarshalFailed err msg + ErrUnmarshalFailed = errors.New("unmarshal is error") ) diff --git a/common/gas.go b/common/gas.go new file mode 100644 index 0000000000000000000000000000000000000000..1b41ac027bb99b0af6f4a92aa2493f0875e1a47a --- /dev/null +++ b/common/gas.go @@ -0,0 +1,31 @@ +package common + +import "chainmaker.org/chainmaker/pb-go/v2/syscontract" + +const DefaultGas = uint64(100000) + +// contractName: [functionName:gas] +var gasTable = map[string]map[string]uint64{ + syscontract.SystemContract_CHAIN_QUERY.String(): {"": DefaultGas}, //key: ""表示默认方法 + syscontract.SystemContract_CONTRACT_MANAGE.String(): { + syscontract.ContractManageFunction_INIT_CONTRACT.String(): 1000000, + syscontract.ContractManageFunction_UPGRADE_CONTRACT.String(): 1000000, + "": DefaultGas, + }, +} + +func GetGas(contractName, method string, defaultGas uint64) uint64 { + methodGasMap, ok := gasTable[contractName] + if !ok { //找不到合约的Gas设置 + return defaultGas + } + gas, ok2 := methodGasMap[method] + if !ok2 { //找不到匹配的,就找key为空的 + contractGas, ok3 := methodGasMap[""] + if !ok3 { + return defaultGas + } + return contractGas + } + return gas +} diff --git a/common/interface.go b/common/interface.go index dc0c146680ff1c95e1b68b81956bb0b51e05a7b4..136b67fefed617bba29f54b18363db1cc88d9f07 100644 --- a/common/interface.go +++ b/common/interface.go @@ -7,9 +7,12 @@ package common -import "chainmaker.org/chainmaker/protocol/v2" +import ( + "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2" +) -type ContractFunc func(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) +type ContractFunc func(context protocol.TxSimContext, params map[string][]byte) *common.ContractResult // Contract define native Contract interface type Contract interface { diff --git a/common/result.go b/common/result.go new file mode 100644 index 0000000000000000000000000000000000000000..af7b442215c791c23ba05422da4488c2b5f94989 --- /dev/null +++ b/common/result.go @@ -0,0 +1,81 @@ +package common + +import ( + "encoding/json" + + "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2" +) + +func ResultSuccess(result []byte, gas uint64) *common.ContractResult { + return &common.ContractResult{ + Code: 0, + Result: result, + Message: "OK", + GasUsed: gas, + ContractEvent: nil, + } +} +func ResultError(err error) *common.ContractResult { + return &common.ContractResult{ + Code: 1, + Result: nil, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } +} +func ResultBytesAndError(returnResult []byte, err error) *common.ContractResult { + if err != nil { + return &common.ContractResult{ + Code: 1, + Result: returnResult, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } + } + //if len(returnResult) == 0 { + // returnResult = []byte("ok") + //} + return &common.ContractResult{ + Code: 0, + Result: returnResult, + Message: "OK", + GasUsed: 0, + ContractEvent: nil, + } +} +func ResultErrorWithGasUsed(err error, gas uint64) *common.ContractResult { + return &common.ContractResult{ + Code: 1, + Result: nil, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } +} + +func ResultJson(obj interface{}) (*common.ContractResult, error) { + data, err := json.Marshal(obj) + if err != nil { + return nil, err + } + return &common.ContractResult{ + Code: 0, + Result: data, + Message: "OK", + GasUsed: 0, + ContractEvent: nil, + }, nil +} + +//WrapResultFunc 包装原有的返回[]byte的函数,改为返回ContractResult的函数 +func WrapResultFunc(f func(txSimContext protocol.TxSimContext, parameters map[string][]byte) ([]byte, error)) func( + txSimContext protocol.TxSimContext, parameters map[string][]byte) *common.ContractResult { + f2 := func(txSimContext protocol.TxSimContext, parameters map[string][]byte) *common.ContractResult { + result, err := f(txSimContext, parameters) + return ResultBytesAndError(result, err) + } + return f2 +} diff --git a/contractmgr/contract_manager.go b/contractmgr/contract_manager.go index d7c2e4ffb69ab97f4f85acd327dad3d78a64aedd..7ea6bc90b85d69131e774d304f8bd99e7bd56ca0 100644 --- a/contractmgr/contract_manager.go +++ b/contractmgr/contract_manager.go @@ -12,26 +12,18 @@ import ( "errors" "fmt" - "chainmaker.org/chainmaker/vm-native/chainconfigmgr" - "chainmaker.org/chainmaker/vm-native/common" - + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" commonPb "chainmaker.org/chainmaker/pb-go/v2/common" - configPb "chainmaker.org/chainmaker/pb-go/v2/config" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" ) var ( - ContractName = syscontract.SystemContract_CONTRACT_MANAGE.String() - keyContractName = "_Native_Contract_List" - contractsForMultiSignWhiteList = []string{ - syscontract.SystemContract_CERT_MANAGE.String(), - syscontract.SystemContract_PRIVATE_COMPUTE.String(), - syscontract.SystemContract_CONTRACT_MANAGE.String(), - } - TRUE = []byte("true") - FALSE = []byte("false") + ContractName = syscontract.SystemContract_CONTRACT_MANAGE.String() + TRUE = []byte("true") + FALSE = []byte("false") ) type ContractManager struct { @@ -55,15 +47,27 @@ func registerContractManagerMethods(log protocol.Logger) map[string]common.Contr runtime := &ContractManagerRuntime{log: log} methodMap[syscontract.ContractManageFunction_INIT_CONTRACT.String()] = runtime.installContract methodMap[syscontract.ContractManageFunction_UPGRADE_CONTRACT.String()] = runtime.upgradeContract - methodMap[syscontract.ContractManageFunction_FREEZE_CONTRACT.String()] = runtime.freezeContract - methodMap[syscontract.ContractManageFunction_UNFREEZE_CONTRACT.String()] = runtime.unfreezeContract - methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT.String()] = runtime.revokeContract - methodMap[syscontract.ContractQueryFunction_GET_CONTRACT_INFO.String()] = runtime.getContractInfo - - methodMap[syscontract.ContractManageFunction_GRANT_CONTRACT_ACCESS.String()] = runtime.grantContractAccess - methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT_ACCESS.String()] = runtime.revokeContractAccess - methodMap[syscontract.ContractManageFunction_VERIFY_CONTRACT_ACCESS.String()] = runtime.verifyContractAccess - methodMap[syscontract.ContractQueryFunction_GET_DISABLED_CONTRACT_LIST.String()] = runtime.getDisabledContractList + methodMap[syscontract.ContractManageFunction_FREEZE_CONTRACT.String()] = common.WrapResultFunc( + runtime.freezeContract) + methodMap[syscontract.ContractManageFunction_UNFREEZE_CONTRACT.String()] = common.WrapResultFunc( + runtime.unfreezeContract) + methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT.String()] = common.WrapResultFunc( + runtime.revokeContract) + methodMap[syscontract.ContractQueryFunction_GET_CONTRACT_INFO.String()] = common.WrapResultFunc( + runtime.getContractInfo) + methodMap[syscontract.ContractQueryFunction_GET_CONTRACT_LIST.String()] = common.WrapResultFunc( + runtime.getAllContracts) + + methodMap[syscontract.ContractManageFunction_GRANT_CONTRACT_ACCESS.String()] = common.WrapResultFunc( + runtime.grantContractAccess) + methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT_ACCESS.String()] = common.WrapResultFunc( + runtime.revokeContractAccess) + methodMap[syscontract.ContractManageFunction_VERIFY_CONTRACT_ACCESS.String()] = common.WrapResultFunc( + runtime.verifyContractAccess) + methodMap[syscontract.ContractQueryFunction_GET_DISABLED_CONTRACT_LIST.String()] = common.WrapResultFunc( + runtime.getDisabledContractList) + methodMap[syscontract.ContractManageFunction_INIT_NEW_NATIVE_CONTRACT.String()] = common.WrapResultFunc( + runtime.InitNewNativeContract) return methodMap @@ -71,88 +75,67 @@ func registerContractManagerMethods(log protocol.Logger) map[string]common.Contr // enable access to a native contract // this method will take off the contract name from the disabled contract list +// 传入合约列表,将合约状态改为Normal func (r *ContractManagerRuntime) grantContractAccess(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { var ( - err error - requestContractListBytes []byte - updatedContractListBytes []byte - disabledContractList []string - requestContractList []string - updatedContractList []string + err error + requestContractList []string ) - // 1. fetch the disabled contract list - disabledContractList, err = r.fetchDisabledContractList(txSimContext) - if err != nil { - return nil, err - } - - // 2. get the requested contracts to enable access from parameters - requestContractListBytes = params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] + // 1. get the requested contracts to enable access from parameters + requestContractListBytes := params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] err = json.Unmarshal(requestContractListBytes, &requestContractList) if err != nil { return nil, err } - - // 3. adjust the disabled native contract list per the requested contract names - updatedContractList = filterContracts(disabledContractList, requestContractList) - updatedContractListBytes, err = json.Marshal(updatedContractList) - if err != nil { - return nil, err + for _, cn := range requestContractList { + if cn == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return nil, errors.New("can't grant contract_manage") + } } - - // 4. store the adjusted native contract list back to the database - err = storeDisabledContractList(txSimContext, updatedContractListBytes) - if err != nil { - return nil, err + // 2. unfreeze contract status + for _, contractName := range requestContractList { + _, err := r.UnfreezeContract(txSimContext, contractName) + if err != nil { + return nil, err + } } - r.log.Infof("grant access to contract: %v succeed!", requestContractList) return nil, nil } // disable access to a native contract // this method will add the contract names to the disabled contract list +//传入合约列表,将合约状态改为冻结 func (r *ContractManagerRuntime) revokeContractAccess(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { var ( - err error - requestContractListBytes []byte - updatedContractListBytes []byte - disabledContractList []string - requestContractList []string - updatedContractList []string + err error + requestContractList []string ) - // 1. fetch the disabled contract list - disabledContractList, err = r.fetchDisabledContractList(txSimContext) - if err != nil { - return nil, err - } - - // 2. 2. get the requested contracts to disable access from parameters - requestContractListBytes = params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] + // 1. get the requested contracts to disable access from parameters + requestContractListBytes := params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] err = json.Unmarshal(requestContractListBytes, &requestContractList) if err != nil { return nil, err } - - // 3. adjust the disabled native contract list per the requested contract names - updatedContractList = append(disabledContractList, requestContractList...) - - updatedContractListBytes, err = json.Marshal(updatedContractList) - if err != nil { - return nil, err + for _, cn := range requestContractList { + if cn == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return nil, errors.New("can't revoke contract_manage") + } } - // 4. store the updated native contract list back to the database - err = storeDisabledContractList(txSimContext, updatedContractListBytes) - if err != nil { - return nil, err + // 2. freeze contract + for _, contractName := range requestContractList { + _, err := r.FreezeContract(txSimContext, contractName) + if err != nil { + return nil, err + } } - + r.log.Infof("revoke access to contract: %v succeed!", requestContractList) return nil, nil } @@ -161,62 +144,32 @@ func (r *ContractManagerRuntime) revokeContractAccess(txSimContext protocol.TxSi func (r *ContractManagerRuntime) verifyContractAccess(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { var ( - err error - disabledContractList []string - contractName string - method string - multiSignContractName string + err error + disabledContractList []string + contractName string ) - + requestContractListBytes, ok := params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] + if ok { + contractName = string(requestContractListBytes) + } else { + contractName = txSimContext.GetTx().Payload.ContractName + if contractName == syscontract.SystemContract_MULTI_SIGN.String() { + contractName, err = getContractNameForMultiSign(txSimContext.GetTx().Payload.Parameters) + if err != nil { + return nil, err + } + } + } // 1. fetch the disabled native contract list disabledContractList, err = r.fetchDisabledContractList(txSimContext) if err != nil { return nil, err } - - // 2. get the requested contract name and verify if it's on the disabled native contract list - contractName = txSimContext.GetTx().Payload.ContractName - method = txSimContext.GetTx().Payload.Method - for _, cn := range disabledContractList { - if cn == contractName { - return []byte("false"), nil + for _, c := range disabledContractList { + if c == contractName { + return FALSE, errors.New("the contract is in the disabled contract list") } } - - // 3. if the requested contract name is multisignature, get the underlying contract name from - // the tx payload and verify if it has access - if contractName == syscontract.SystemContract_MULTI_SIGN.String() && - method == syscontract.MultiSignFunction_REQ.String() { - - // if the method name is not req, return true since it does not contain contract names in parameters - multiSignMethodName := txSimContext.GetTx().Payload.Method - if multiSignContractName == syscontract.MultiSignFunction_QUERY.String() || - multiSignMethodName == syscontract.MultiSignFunction_VOTE.String() { - return []byte("true"), nil - } - - multiSignContractName, err = getContractNameForMultiSign(txSimContext.GetTx().Payload.Parameters) - if err != nil { - return nil, err - } - - // check if the requested contract is on the disabled contract list - for _, cn := range disabledContractList { - if cn == multiSignContractName { - return FALSE, nil - } - } - - // check if the requested contract list is on the multi sign white list - for _, cn := range contractsForMultiSignWhiteList { - if cn == multiSignContractName { - return TRUE, nil - } - } - - return FALSE, nil - } - return TRUE, nil } @@ -230,6 +183,7 @@ func getContractNameForMultiSign(params []*commonPb.KeyValuePair) (string, error } // fetch the disabled contract list +//获得冻结的合约列表 func (r *ContractManagerRuntime) getDisabledContractList(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { var ( @@ -253,86 +207,20 @@ func (r *ContractManagerRuntime) getDisabledContractList(txSimContext protocol.T return disabledContractListBytes, nil } -// store the disabled contract list to the database -func storeDisabledContractList(txSimContext protocol.TxSimContext, disabledContractListBytes []byte) error { - var ( - err error - refinedDisabledContractListBytes []byte - disabledContractList []string - refinedDisabledContractList []string - ) - err = json.Unmarshal(disabledContractListBytes, &disabledContractList) - if err != nil { - return err - } - - // filter out redundant contract names in the disabled contract list - uniqueMap := make(map[string]string) - for _, cn := range disabledContractList { - if _, ok := uniqueMap[cn]; !ok { - uniqueMap[cn] = cn - refinedDisabledContractList = append(refinedDisabledContractList, cn) - } - } - - refinedDisabledContractListBytes, err = json.Marshal(refinedDisabledContractList) - if err != nil { - return err - } - - err = txSimContext.Put(ContractName, []byte(keyContractName), refinedDisabledContractListBytes) - if err != nil { - return err - } - return nil -} - -// filter out request contracts from disabled contract list, return a newly updated list -func filterContracts(disabledContractList []string, requestedContractList []string) []string { - var updatedContractList []string - - // return the original list if no contracts have been requested - if len(requestedContractList) == 0 { - return disabledContractList - } - - m := make(map[string]int, len(requestedContractList)) - for _, cn := range requestedContractList { - m[cn] = 1 - } - - // populate the updatedContractList - for _, cn := range disabledContractList { - _, found := m[cn] - if !found { - updatedContractList = append(updatedContractList, cn) - } - } - - return updatedContractList -} - // helper method to fetch the disabled contract list from genesis config file // if not initialized or from the database otherwise func (r *ContractManagerRuntime) fetchDisabledContractList(txSimContext protocol.TxSimContext) ([]string, error) { // try to get disabled contract list from database - disabledContractListBytes, err := txSimContext.Get(ContractName, []byte(keyContractName)) + contracts, err := r.GetAllContracts(txSimContext) if err != nil { return nil, err } - - // if the config file does not exist in the database yet, try fetch it from the genesis config file and store it - // to the database - if disabledContractListBytes == nil { - disabledContractListBytes, err = r.initializeDisabledNativeContractList(txSimContext) - if err != nil { - r.log.Error(err) - return nil, err + var disabledContractList []string + for _, c := range contracts { + if c.Status == commonPb.ContractStatus_FROZEN { + disabledContractList = append(disabledContractList, c.Name) } } - - var disabledContractList []string - err = json.Unmarshal(disabledContractListBytes, &disabledContractList) return disabledContractList, err } @@ -346,75 +234,45 @@ func (r *ContractManagerRuntime) getContractInfo(txSimContext protocol.TxSimCont return json.Marshal(contract) } -func (r *ContractManagerRuntime) initializeDisabledNativeContractList( - txSimContext protocol.TxSimContext) ([]byte, error) { - var ( - err error - chainConfig *configPb.ChainConfig - disabledContractListBytes []byte - ) - - // 1. fetch chainConfig from genesis config file - chainConfig, err = chainconfigmgr.GetChainConfig(txSimContext) - if err != nil { - r.log.Error(err) - return nil, err - } - - disabledContractList := chainConfig.DisabledNativeContract - if disabledContractList == nil { - disabledContractList = make([]string, 0) - } - disabledContractListBytes, err = json.Marshal(disabledContractList) - if err != nil { - return nil, err - } - - // 2. store the disabledContractList field to the database - err = storeDisabledContractList(txSimContext, disabledContractListBytes) +func (r *ContractManagerRuntime) getAllContracts(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + contracts, err := r.GetAllContracts(txSimContext) if err != nil { return nil, err } - - return disabledContractListBytes, nil + r.log.Debugf("getAllContracts result: %+v", contracts) + return json.Marshal(contracts) } - -//func (r *ContractManagerRuntime) getAllContracts(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( -// []byte, error) { -// contracts, err := r.GetAllContracts(txSimContext) -// if err != nil { -// return nil, err -// } -// return json.Marshal(contracts) -//} -func (r *ContractManagerRuntime) installContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( - []byte, error) { +func (r *ContractManagerRuntime) installContract(txSimContext protocol.TxSimContext, + parameters map[string][]byte) *commonPb.ContractResult { name, version, byteCode, runtimeType, err := r.parseParam(parameters) if err != nil { - return nil, err + return common.ResultError(err) } - contract, err := r.InstallContract(txSimContext, name, version, byteCode, runtimeType, parameters) + contract, gas, err := r.InstallContract(txSimContext, name, version, byteCode, runtimeType, parameters) if err != nil { - return nil, err + return common.ResultError(err) } r.log.Infof("install contract success[name:%s version:%s runtimeType:%d byteCodeLen:%d]", contract.Name, contract.Version, contract.RuntimeType, len(byteCode)) - return contract.Marshal() + contractBytes, _ := contract.Marshal() + return common.ResultSuccess(contractBytes, gas) } -func (r *ContractManagerRuntime) upgradeContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( - []byte, error) { +func (r *ContractManagerRuntime) upgradeContract(txSimContext protocol.TxSimContext, + parameters map[string][]byte) *commonPb.ContractResult { name, version, byteCode, runtimeType, err := r.parseParam(parameters) if err != nil { - return nil, err + return common.ResultError(err) } - contract, err := r.UpgradeContract(txSimContext, name, version, byteCode, runtimeType, parameters) + contract, gas, err := r.UpgradeContract(txSimContext, name, version, byteCode, runtimeType, parameters) if err != nil { - return nil, err + return common.ResultError(err) } r.log.Infof("upgrade contract success[name:%s version:%s runtimeType:%d byteCodeLen:%d]", contract.Name, contract.Version, contract.RuntimeType, len(byteCode)) - return contract.Marshal() + contractBytes, _ := contract.Marshal() + return common.ResultSuccess(contractBytes, gas) } func (r *ContractManagerRuntime) parseParam(parameters map[string][]byte) (string, string, []byte, @@ -480,7 +338,7 @@ func (r *ContractManagerRuntime) GetContractInfo(context protocol.TxSimContext, r.log.Warnf(err.Error()) return nil, err } - return context.GetContractByName(name) + return getContractByName(context, name) } func (r *ContractManagerRuntime) GetContractByteCode(context protocol.TxSimContext, name string) ([]byte, error) { if utils.IsAnyBlank(name) { @@ -493,8 +351,10 @@ func (r *ContractManagerRuntime) GetContractByteCode(context protocol.TxSimConte //GetAllContracts 查询所有合约的详细信息 func (r *ContractManagerRuntime) GetAllContracts(context protocol.TxSimContext) ([]*commonPb.Contract, error) { - keyPrefix := []byte(utils.PrefixContractInfo) - it, err := context.Select(syscontract.SystemContract_CONTRACT_MANAGE.String(), keyPrefix, keyPrefix) + keyPre := []byte(utils.PrefixContractInfo) + limitKey := []byte(utils.PrefixContractInfo) + limitKey[len(limitKey)-1] = limitKey[len(limitKey)-1] + 1 + it, err := context.Select(syscontract.SystemContract_CONTRACT_MANAGE.String(), keyPre, limitKey) if err != nil { return nil, err } @@ -510,51 +370,56 @@ func (r *ContractManagerRuntime) GetAllContracts(context protocol.TxSimContext) if err != nil { return nil, err } + result = append(result, contract) } return result, nil } //InstallContract 安装新合约 func (r *ContractManagerRuntime) InstallContract(context protocol.TxSimContext, name, version string, byteCode []byte, - runTime commonPb.RuntimeType, initParameters map[string][]byte) (*commonPb.Contract, error) { + runTime commonPb.RuntimeType, initParameters map[string][]byte) (*commonPb.Contract, uint64, error) { if !utils.CheckContractNameFormat(name) { - return nil, errInvalidContractName + return nil, 0, errInvalidContractName } if runTime == commonPb.RuntimeType_EVM && !utils.CheckEvmAddressFormat(name) { - return nil, errInvalidEvmContractName + return nil, 0, errInvalidEvmContractName } key := utils.GetContractDbKey(name) //check name exist existContract, _ := context.Get(ContractName, key) if len(existContract) > 0 { //exist - return nil, errContractExist + return nil, 0, errContractExist + } + creator, err := r.getCreator(context) + if err != nil { + return nil, 0, err } contract := &commonPb.Contract{ Name: name, Version: version, RuntimeType: runTime, Status: commonPb.ContractStatus_NORMAL, - Creator: context.GetSender(), + Creator: creator, } cdata, _ := contract.Marshal() - err := context.Put(ContractName, key, cdata) + err = context.Put(ContractName, key, cdata) if err != nil { - return nil, err + return nil, 0, err } byteCodeKey := utils.GetContractByteCodeDbKey(name) err = context.Put(ContractName, byteCodeKey, byteCode) if err != nil { - return nil, err + return nil, 0, err } //实例化合约,并init合约,产生读写集 - result, statusCode := context.CallContract(contract, protocol.ContractInitMethod, byteCode, initParameters, + result, _, statusCode := context.CallContract(contract, protocol.ContractInitMethod, byteCode, initParameters, 0, commonPb.TxType_INVOKE_CONTRACT) if statusCode != commonPb.TxStatusCode_SUCCESS { - return nil, fmt.Errorf("%s, %s", errContractInitFail, result.Message) + return nil, 0, fmt.Errorf("%s, %s", errContractInitFail, result.Message) } if result.Code > 0 { //throw error - return nil, fmt.Errorf("%s, %s", errContractInitFail, result.Message) + return nil, 0, fmt.Errorf("%s, %s", errContractInitFail, result.Message) } if runTime == commonPb.RuntimeType_EVM { //save bytecode body @@ -562,53 +427,78 @@ func (r *ContractManagerRuntime) InstallContract(context protocol.TxSimContext, if len(result.Result) > 0 { err := context.Put(ContractName, byteCodeKey, result.Result) if err != nil { - return nil, fmt.Errorf("%s, %s", errContractInitFail, err) + return nil, 0, fmt.Errorf("%s, %s", errContractInitFail, err) } } } - return contract, nil + return contract, result.GasUsed, nil } -//UpgradeContract 升级现有合约 -func (r *ContractManagerRuntime) UpgradeContract(context protocol.TxSimContext, name, version string, byteCode []byte, - runTime commonPb.RuntimeType, upgradeParameters map[string][]byte) (*commonPb.Contract, error) { - key := utils.GetContractDbKey(name) - //check name exist - existContract, _ := context.Get(ContractName, key) - if len(existContract) == 0 { //not exist - return nil, errContractNotExist +func (r *ContractManagerRuntime) getCreator(context protocol.TxSimContext) (*accesscontrol.MemberFull, error) { + sender := context.GetSender() + if context.GetBlockVersion() == 220 { //兼容历史数据的问题 + return &accesscontrol.MemberFull{ + OrgId: sender.GetOrgId(), + MemberType: sender.GetMemberType(), + MemberInfo: sender.GetMemberInfo(), + }, nil } - contract := &commonPb.Contract{} - err := contract.Unmarshal(existContract) + ac, err := context.GetAccessControl() if err != nil { + r.log.Warn(err) return nil, err } + + member, err := ac.NewMember(sender) + if err != nil { + r.log.Warn(err) + return nil, err + } + creator := &accesscontrol.MemberFull{ + OrgId: sender.GetOrgId(), + MemberType: sender.GetMemberType(), + MemberInfo: sender.GetMemberInfo(), + MemberId: member.GetMemberId(), + Role: string(member.GetRole()), + Uid: member.GetUid(), + } + return creator, nil +} + +//UpgradeContract 升级现有合约 +func (r *ContractManagerRuntime) UpgradeContract(context protocol.TxSimContext, name, version string, byteCode []byte, + runTime commonPb.RuntimeType, upgradeParameters map[string][]byte) (*commonPb.Contract, uint64, error) { + contract, err := getContractByName(context, name) + if err != nil { + return nil, 0, err + } if contract.Version == version { - return nil, errContractVersionExist + return nil, 0, errContractVersionExist } contract.RuntimeType = runTime contract.Version = version //update ContractInfo cdata, _ := contract.Marshal() + key := utils.GetContractDbKey(name) err = context.Put(ContractName, key, cdata) if err != nil { - return nil, err + return nil, 0, err } //update Contract Bytecode byteCodeKey := utils.GetContractByteCodeDbKey(name) err = context.Put(ContractName, byteCodeKey, byteCode) if err != nil { - return nil, err + return nil, 0, err } //运行新合约的upgrade方法,产生读写集 - result, statusCode := context.CallContract(contract, protocol.ContractUpgradeMethod, byteCode, upgradeParameters, + result, _, statusCode := context.CallContract(contract, protocol.ContractUpgradeMethod, byteCode, upgradeParameters, 0, commonPb.TxType_INVOKE_CONTRACT) if statusCode != commonPb.TxStatusCode_SUCCESS { - return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) + return nil, 0, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) } if result.Code > 0 { //throw error - return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) + return nil, 0, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) } if runTime == commonPb.RuntimeType_EVM { //save bytecode body @@ -616,14 +506,18 @@ func (r *ContractManagerRuntime) UpgradeContract(context protocol.TxSimContext, if len(result.Result) > 0 { err := context.Put(ContractName, byteCodeKey, result.Result) if err != nil { - return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, err) + return nil, 0, fmt.Errorf("%s, %s", errContractUpgradeFail, err) } } } - return contract, nil + return contract, result.GasUsed, nil } func (r *ContractManagerRuntime) FreezeContract(context protocol.TxSimContext, name string) ( *commonPb.Contract, error) { + if name == syscontract.SystemContract_CONTRACT_MANAGE.String() { //合约管理合约不能被冻结 + r.log.Warnf("cannot freeze special contract:%s", name) + return nil, errInvalidContractName + } return r.changeContractStatus(context, name, commonPb.ContractStatus_NORMAL, commonPb.ContractStatus_FROZEN) } func (r *ContractManagerRuntime) UnfreezeContract(context protocol.TxSimContext, name string) ( @@ -637,18 +531,23 @@ func (r *ContractManagerRuntime) RevokeContract(context protocol.TxSimContext, n r.log.Warnf(err.Error()) return nil, err } - contract, err := context.GetContractByName(name) + if name == syscontract.SystemContract_CONTRACT_MANAGE.String() || //某些合约是不能被禁用的 + name == syscontract.SystemContract_CHAIN_CONFIG.String() { + r.log.Warnf("cannot revoke special contract:%s", name) + return nil, errInvalidContractName + } + contract, err := getContractByName(context, name) if err != nil { return nil, err } if contract.Status != commonPb.ContractStatus_NORMAL && contract.Status != commonPb.ContractStatus_FROZEN { - r.log.Warnf("contract[%s] expect status:NORMAL or FROZEN,actual status:%s", + r.log.Warnf("contract[%s] expect status:NORMAL or FROZEN, actual status:%s", name, contract.Status.String()) return nil, errContractStatusInvalid } contract.Status = commonPb.ContractStatus_REVOKED - key := utils.GetContractDbKey(name) cdata, _ := contract.Marshal() + key := utils.GetContractDbKey(name) err = context.Put(ContractName, key, cdata) if err != nil { return nil, err @@ -656,6 +555,21 @@ func (r *ContractManagerRuntime) RevokeContract(context protocol.TxSimContext, n return contract, nil } +//getContractByName 通过名字从保留读写集的方式获得Contract对象 +func getContractByName(context protocol.TxSimContext, name string) (*commonPb.Contract, error) { + key := utils.GetContractDbKey(name) + //check name exist + existContract, _ := context.Get(ContractName, key) + if len(existContract) == 0 { //not exist + return nil, errContractNotExist + } + contract := &commonPb.Contract{} + err := contract.Unmarshal(existContract) + if err != nil { + return nil, err + } + return contract, nil +} func (r *ContractManagerRuntime) changeContractStatus(context protocol.TxSimContext, name string, oldStatus, newStatus commonPb.ContractStatus) (*commonPb.Contract, error) { if utils.IsAnyBlank(name) { @@ -663,7 +577,7 @@ func (r *ContractManagerRuntime) changeContractStatus(context protocol.TxSimCont r.log.Warnf(err.Error()) return nil, err } - contract, err := context.GetContractByName(name) + contract, err := getContractByName(context, name) if err != nil { return nil, err } @@ -674,11 +588,48 @@ func (r *ContractManagerRuntime) changeContractStatus(context protocol.TxSimCont return nil, fmt.Errorf("%s, %s", errContractStatusInvalid, msg) } contract.Status = newStatus - key := utils.GetContractDbKey(name) cdata, _ := contract.Marshal() + key := utils.GetContractDbKey(name) err = context.Put(ContractName, key, cdata) if err != nil { return nil, err } return contract, nil } + +func (r *ContractManagerRuntime) InitNewNativeContract(txSimContext protocol.TxSimContext, _ map[string][]byte) ( + []byte, error) { + contracts, err := r.GetAllContracts(txSimContext) + if err != nil { + return nil, err + } + existNativeContracts := make(map[string]bool) + for _, contract := range contracts { + if contract.RuntimeType == commonPb.RuntimeType_NATIVE { + existNativeContracts[contract.Name] = true + } + } + var returnContracts []*commonPb.Contract + for cname := range syscontract.SystemContract_value { + _, exist := existNativeContracts[cname] + if !exist { + contract := &commonPb.Contract{ + Name: cname, + Version: "v1", + RuntimeType: commonPb.RuntimeType_NATIVE, + Status: commonPb.ContractStatus_NORMAL, + Creator: nil, + } + key := utils.GetContractDbKey(cname) + value, _ := contract.Marshal() + err = txSimContext.Put(ContractName, key, value) + if err != nil { + return nil, err + } + r.log.Infof("init native contract success[name:%s version:%s runtimeType:%d]", + contract.Name, contract.Version, contract.RuntimeType) + returnContracts = append(returnContracts, contract) + } + } + return json.Marshal(returnContracts) +} diff --git a/contractmgr/contract_manger_test.go b/contractmgr/contract_manger_test.go index d451371d16cd316428de755106a1e30c344b7a3c..b8f708ace997e0765a18dcc27061e3dfa92c7e7e 100644 --- a/contractmgr/contract_manger_test.go +++ b/contractmgr/contract_manger_test.go @@ -6,3 +6,267 @@ */ package contractmgr + +import ( + "testing" + + pbac "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/pb-go/v2/store" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/protocol/v2/mock" + "chainmaker.org/chainmaker/protocol/v2/test" + "chainmaker.org/chainmaker/utils/v2" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestContractManagerRuntime_InstallContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + acTest := mock.NewMockAccessControlProvider(ctrl) + acTest.EXPECT().GetHashAlg().Return("SHA256").AnyTimes() + acTest.EXPECT().NewMember(gomock.Any()).Return(&Mb{}, nil).AnyTimes() + txSimContext.EXPECT().GetAccessControl().Return(acTest, nil).AnyTimes() + txSimContext.EXPECT().GetBlockVersion().Return(uint32(220)).AnyTimes() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + txSimContext.EXPECT().CallContract(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(&commonPb.ContractResult{Code: 0}, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS) + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result, gas, err := runtime.InstallContract(txSimContext, "testContractName", "v1", []byte("bytes"), + commonPb.RuntimeType_WASMER, map[string][]byte{}) + assert.Nil(t, err) + t.Log(result) + t.Log(gas) +} +func TestContractManagerRuntime_UpgradeContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_NORMAL} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + txSimContext.EXPECT().CallContract(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(&commonPb.ContractResult{Code: 0}, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS) + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result, gas, err := runtime.UpgradeContract(txSimContext, "testContractName", "v1", []byte("bytes"), + commonPb.RuntimeType_WASMER, map[string][]byte{}) + assert.NotNil(t, err) //version重复 + result, gas, err = runtime.UpgradeContract(txSimContext, "testContractName", "v2", []byte("bytes"), + commonPb.RuntimeType_WASMER, map[string][]byte{}) + t.Log(result) + t.Log(gas) +} +func TestContractManagerRuntime_FreezeContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_NORMAL} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + + result, err := runtime.FreezeContract(txSimContext, "") + assert.NotNil(t, err) + t.Log(result) + result, err = runtime.FreezeContract(txSimContext, "testContractName") + assert.Nil(t, err) + assert.True(t, result.Status == commonPb.ContractStatus_FROZEN) + t.Log(result) +} + +func TestContractManagerRuntime_FreezeContractFail(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + + result, err := runtime.FreezeContract(txSimContext, "") + assert.NotNil(t, err) + t.Log(result) + result, err = runtime.FreezeContract(txSimContext, "testContractName") + assert.NotNil(t, err) + t.Log(result) + +} + +func TestContractManagerRuntime_UnfreezeContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result, err := runtime.UnfreezeContract(txSimContext, "testContractName") + assert.Nil(t, err) + assert.True(t, result.Status == commonPb.ContractStatus_NORMAL) + t.Log(result) +} +func TestContractManagerRuntime_RevokeContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result, err := runtime.RevokeContract(txSimContext, "testContractName") + assert.Nil(t, err) + assert.True(t, result.Status == commonPb.ContractStatus_REVOKED) + t.Log(result) +} +func TestContractManagerRuntime_GetContractInfo(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + c, err := runtime.GetContractInfo(txSimContext, "testContractName") + assert.Nil(t, err) + t.Log(c) +} +func TestContractManagerRuntime_GetAllContracts(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract1 := &commonPb.Contract{Name: "testContractName1", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + contract2 := &commonPb.Contract{Name: "testContractName2", Version: "v1", Status: commonPb.ContractStatus_NORMAL} + contract3 := &commonPb.Contract{Name: "testContractName3", Version: "v1", Status: commonPb.ContractStatus_FROZEN} + list := &ListIter{list: []*commonPb.Contract{contract1, contract2, contract3}} + txSimContext.EXPECT().Select(gomock.Any(), gomock.Any(), gomock.Any()).Return(list, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + clist, err := runtime.GetAllContracts(txSimContext) + assert.Nil(t, err) + t.Log(clist) + assert.EqualValues(t, 3, len(clist)) +} + +type ListIter struct { + list []*commonPb.Contract + idx int +} + +func (i *ListIter) Next() bool { + i.idx++ + return i.idx < len(i.list)+1 +} +func (i *ListIter) Value() (*store.KV, error) { + c := i.list[i.idx-1] + cdata, _ := c.Marshal() + return &store.KV{ + ContractName: "", + Key: utils.GetContractDbKey(c.Name), + Value: cdata, + }, nil +} +func (i *ListIter) Release() { + i.list = make([]*commonPb.Contract, 0) + i.idx = 0 +} +func initParameters() map[string][]byte { + parameters := make(map[string][]byte) + parameters[syscontract.InitContract_CONTRACT_NAME.String()] = []byte("testContractName") + parameters[syscontract.InitContract_CONTRACT_VERSION.String()] = []byte("v1") + parameters[syscontract.InitContract_CONTRACT_BYTECODE.String()] = []byte("byte code!!!") + parameters[syscontract.InitContract_CONTRACT_RUNTIME_TYPE.String()] = []byte("WASMER") + return parameters +} +func TestContractManagerRuntime_InstallContract2(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + acTest := mock.NewMockAccessControlProvider(ctrl) + acTest.EXPECT().GetHashAlg().Return("SHA256").AnyTimes() + acTest.EXPECT().NewMember(gomock.Any()).Return(&Mb{}, nil).AnyTimes() + txSimContext.EXPECT().GetAccessControl().Return(acTest, nil).AnyTimes() + txSimContext.EXPECT().GetBlockVersion().Return(uint32(220)).AnyTimes() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + txSimContext.EXPECT().CallContract(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(&commonPb.ContractResult{Code: 0}, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS) + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result := runtime.installContract(txSimContext, initParameters()) + t.Log(result) + assert.EqualValues(t, "OK", result.Message) + assert.EqualValues(t, 0, result.Code) +} +func TestContractManagerRuntime_UpgradeContract2(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "testContractName", Version: "v0", Status: commonPb.ContractStatus_NORMAL} + cdata, _ := contract.Marshal() + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).Return(cdata, nil).AnyTimes() + txSimContext.EXPECT().GetSender().Return(&pbac.Member{MemberInfo: []byte("user1")}).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + txSimContext.EXPECT().CallContract(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any()).Return(&commonPb.ContractResult{Code: 0}, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS) + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result := runtime.upgradeContract(txSimContext, initParameters()) + assert.EqualValues(t, 0, result.Code) +} + +type Mb struct { +} + +func (m Mb) GetMemberId() string { + return "memberId" +} + +func (m Mb) GetOrgId() string { + return "orgId" +} + +func (m Mb) GetRole() protocol.Role { + return "role" +} + +func (m Mb) GetUid() string { + return "uid" +} + +func (m Mb) Verify(hashType string, msg []byte, sig []byte) error { + panic("implement me") +} + +func (m Mb) GetMember() (*pbac.Member, error) { + panic("implement me") +} + +func TestContractManagerRuntime_InitNewNativeContract(t *testing.T) { + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + defer ctrl.Finish() + contract := &commonPb.Contract{Name: "CHAIN_CONFIG", Version: "v1", RuntimeType: commonPb.RuntimeType_NATIVE, Status: commonPb.ContractStatus_NORMAL} + list := &ListIter{list: []*commonPb.Contract{contract}} + txSimContext.EXPECT().Select(gomock.Any(), gomock.Any(), gomock.Any()).Return(list, nil).AnyTimes() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + runtime := &ContractManagerRuntime{log: &test.GoLogger{}} + result, err := runtime.InitNewNativeContract(txSimContext, initParameters()) + assert.Nil(t, err) + t.Log(string(result)) + assert.NotContains(t, string(result), "CHAIN_CONFIG") +} diff --git a/crosstranscation/cross_transcation_contract.go b/crosstranscation/cross_transcation_contract.go index c064485a94da30fa6a25d24d6c33ef6b070fd5bc..8287a71cd3e54ab645d541fb8218afa82c8ff077 100644 --- a/crosstranscation/cross_transcation_contract.go +++ b/crosstranscation/cross_transcation_contract.go @@ -12,7 +12,7 @@ import ( "encoding/json" "fmt" - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/vm-native/v2/common" "chainmaker.org/chainmaker/utils/v2" @@ -87,13 +87,20 @@ func registerPrivateComputeContractMethods(log protocol.Logger) map[string]commo }, } - queryMethodMap[syscontract.CrossTransactionFunction_EXECUTE.String()] = crossTransactionRuntime.Execute - queryMethodMap[syscontract.CrossTransactionFunction_COMMIT.String()] = crossTransactionRuntime.Commit - queryMethodMap[syscontract.CrossTransactionFunction_ROLLBACK.String()] = crossTransactionRuntime.Rollback - queryMethodMap[syscontract.CrossTransactionFunction_READ_STATE.String()] = crossTransactionRuntime.ReadState - queryMethodMap[syscontract.CrossTransactionFunction_SAVE_PROOF.String()] = crossTransactionRuntime.SaveProof - queryMethodMap[syscontract.CrossTransactionFunction_READ_PROOF.String()] = crossTransactionRuntime.ReadProof - queryMethodMap[syscontract.CrossTransactionFunction_ARBITRATE.String()] = crossTransactionRuntime.Arbitrate + queryMethodMap[syscontract.CrossTransactionFunction_EXECUTE.String()] = common.WrapResultFunc( + crossTransactionRuntime.Execute) + queryMethodMap[syscontract.CrossTransactionFunction_COMMIT.String()] = common.WrapResultFunc( + crossTransactionRuntime.Commit) + queryMethodMap[syscontract.CrossTransactionFunction_ROLLBACK.String()] = common.WrapResultFunc( + crossTransactionRuntime.Rollback) + queryMethodMap[syscontract.CrossTransactionFunction_READ_STATE.String()] = common.WrapResultFunc( + crossTransactionRuntime.ReadState) + queryMethodMap[syscontract.CrossTransactionFunction_SAVE_PROOF.String()] = common.WrapResultFunc( + crossTransactionRuntime.SaveProof) + queryMethodMap[syscontract.CrossTransactionFunction_READ_PROOF.String()] = common.WrapResultFunc( + crossTransactionRuntime.ReadProof) + queryMethodMap[syscontract.CrossTransactionFunction_ARBITRATE.String()] = common.WrapResultFunc( + crossTransactionRuntime.Arbitrate) return queryMethodMap } @@ -567,7 +574,7 @@ func callBusinessContract(ctx protocol.TxSimContext, crossID, params []byte) (*c func callContract(ctx protocol.TxSimContext, contract *Contract) (*commonPb.ContractResult, error) { c := &commonPb.Contract{Name: contract.Name} - result, code := ctx.CallContract(c, contract.Method, nil, contract.Params, 0, commonPb.TxType_INVOKE_CONTRACT) + result, _, code := ctx.CallContract(c, contract.Method, nil, contract.Params, 0, commonPb.TxType_INVOKE_CONTRACT) if code != commonPb.TxStatusCode_SUCCESS { if result != nil { diff --git a/crosstranscation/cross_tx_contract_test.go b/crosstranscation/cross_tx_contract_test.go index b931e5d7815316da20b46f488269aab37bf3df27..ff784b5e680e46188adcc017d52a05381597a3ce 100644 --- a/crosstranscation/cross_tx_contract_test.go +++ b/crosstranscation/cross_tx_contract_test.go @@ -9,22 +9,19 @@ import ( "fmt" "testing" + "chainmaker.org/chainmaker/common/v2/serialize" "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" pbac "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" - - configPb "chainmaker.org/chainmaker/pb-go/v2/config" - "github.com/gogo/protobuf/proto" - - "chainmaker.org/chainmaker/logger/v2" - - "chainmaker.org/chainmaker/common/v2/serialize" commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + configPb "chainmaker.org/chainmaker/pb-go/v2/config" "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/protocol/v2/mock" + "chainmaker.org/chainmaker/protocol/v2/test" + "github.com/gogo/protobuf/proto" "github.com/golang/mock/gomock" "github.com/google/uuid" "github.com/pkg/errors" - "github.com/stretchr/testify/require" ) var ( @@ -34,7 +31,7 @@ var ( StateKey: cacheKey("state"), ProofPreKey: cacheKey("proof"), } - crossContract = NewCrossTransactionContract(logger.GetLogger("CrossTx")) + crossContract = NewCrossTransactionContract(&test.GoLogger{}) gCache = NewCacheMock() crossID = []byte(uuid.New().String()) gProofKey = []byte("1233211234567") @@ -61,21 +58,20 @@ func Test_Execute(t *testing.T) { }, ).AnyTimes() txSimContext.EXPECT().CallContract(gomock.Not(nil), gomock.Eq("exec"), gomock.Nil(), gomock.Any(), gomock.Eq(uint64(0)), gomock.Eq(commonPb.TxType_INVOKE_CONTRACT)).DoAndReturn( - func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, commonPb.TxStatusCode) { + func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, protocol.ExecOrderTxType, commonPb.TxStatusCode) { if contract.Name == contractName { return &commonPb.ContractResult{ Code: 0, Result: []byte("hello world"), - }, commonPb.TxStatusCode_SUCCESS + }, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS } - return nil, commonPb.TxStatusCode_CONTRACT_FAIL + return nil, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_CONTRACT_FAIL }, ) exec := crossContract.GetMethod(syscontract.CrossTransactionFunction_EXECUTE.String()) params := genExecParams(crossID) - ret, err := exec(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := exec(txSimContext, params) + t.Logf("%#v", ret) } func genExecParams(crossID []byte) map[string][]byte { eParams := map[string][]byte{ @@ -116,9 +112,8 @@ func Test_Commit(t *testing.T) { commit := crossContract.GetMethod(syscontract.CrossTransactionFunction_COMMIT.String()) params := map[string][]byte{paramCrossID: crossID} - ret, err := commit(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := commit(txSimContext, params) + t.Logf("%#v", ret) } func Test_Rollback(t *testing.T) { @@ -139,23 +134,22 @@ func Test_Rollback(t *testing.T) { ).AnyTimes() //if state == syscontract.CrossTxState_ExecOK || state == syscontract.CrossTxState_RollbackFail { txSimContext.EXPECT().CallContract(gomock.Not(nil), gomock.Eq("rollback"), gomock.Nil(), gomock.Any(), gomock.Eq(uint64(0)), gomock.Eq(commonPb.TxType_INVOKE_CONTRACT)).DoAndReturn( - func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, commonPb.TxStatusCode) { + func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, protocol.ExecOrderTxType, commonPb.TxStatusCode) { if contract.Name == contractName && method == rollbackMethod { return &commonPb.ContractResult{ Code: 0, Result: []byte("hello world"), - }, commonPb.TxStatusCode_SUCCESS + }, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS } - return nil, commonPb.TxStatusCode_CONTRACT_FAIL + return nil, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_CONTRACT_FAIL }, ) //} call := crossContract.GetMethod(syscontract.CrossTransactionFunction_ROLLBACK.String()) params := map[string][]byte{paramCrossID: crossID} - ret, err := call(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := call(txSimContext, params) + t.Logf("%#v", ret) } func Test_ReadState(t *testing.T) { @@ -170,11 +164,8 @@ func Test_ReadState(t *testing.T) { call := crossContract.GetMethod(syscontract.CrossTransactionFunction_READ_STATE.String()) params := map[string][]byte{paramCrossID: crossID} - ret, err := call(txSimContext, params) - require.Nil(t, err) - result := syscontract.CrossState{} - result.Unmarshal(ret) - t.Log(result) + ret := call(txSimContext, params) + t.Logf("%#v", ret) } func Test_SaveProof(t *testing.T) { @@ -197,9 +188,8 @@ func Test_SaveProof(t *testing.T) { call := crossContract.GetMethod(syscontract.CrossTransactionFunction_SAVE_PROOF.String()) params := map[string][]byte{paramCrossID: crossID, paramProofKey: proofKey, paramTxProof: []byte("中国奥运健儿加油")} - ret, err := call(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := call(txSimContext, params) + t.Logf("%#v", ret) } func Test_ReadProof(t *testing.T) { @@ -215,9 +205,8 @@ func Test_ReadProof(t *testing.T) { call := crossContract.GetMethod(syscontract.CrossTransactionFunction_READ_PROOF.String()) params := map[string][]byte{paramCrossID: crossID, paramProofKey: proofKey} - ret, err := call(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := call(txSimContext, params) + t.Logf("%#v", ret) } func Test_Arbitrate(t *testing.T) { @@ -274,22 +263,21 @@ MmUZz2wJML7wFsZw+IZ1MH28g3IRc67NcHiV7TX97kqwcTrfD10aV8UZn/+8aDQ5 ).AnyTimes() txSimContext.EXPECT().CallContract(gomock.Not(nil), gomock.Not(nil), gomock.Nil(), gomock.Any(), gomock.Eq(uint64(0)), gomock.Eq(commonPb.TxType_INVOKE_CONTRACT)).DoAndReturn( - func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, commonPb.TxStatusCode) { + func(contract *commonPb.Contract, method string, byteCode []byte, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType) (*commonPb.ContractResult, protocol.ExecOrderTxType, commonPb.TxStatusCode) { if contract.Name == "tx" { return &commonPb.ContractResult{ Code: 0, Result: []byte("hello world"), - }, commonPb.TxStatusCode_SUCCESS + }, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_SUCCESS } - return nil, commonPb.TxStatusCode_CONTRACT_FAIL + return nil, protocol.ExecOrderTxTypeNormal, commonPb.TxStatusCode_CONTRACT_FAIL }, ).AnyTimes() call := crossContract.GetMethod(syscontract.CrossTransactionFunction_ARBITRATE.String()) params := map[string][]byte{paramCrossID: crossID, paramArbitrateCmd: []byte(syscontract.CrossArbitrateCmd_ROLLBACK_CMD.String())} - ret, err := call(txSimContext, params) - require.Nil(t, err) - t.Log(string(ret)) + ret := call(txSimContext, params) + t.Logf("%#v", ret) } func realKey(name string, key []byte) string { diff --git a/dposmgr/dpos_erc20_contract.go b/dposmgr/dpos_erc20_contract.go index 804a1c5d5ec528e39ff46ec021983728127563c8..fe24ec1677c6a44f81e35103a5e8532ffe86ec71 100644 --- a/dposmgr/dpos_erc20_contract.go +++ b/dposmgr/dpos_erc20_contract.go @@ -8,13 +8,14 @@ package dposmgr import ( - "crypto/sha256" "encoding/hex" - "errors" "fmt" "strings" - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/common/v2/crypto" + "chainmaker.org/chainmaker/common/v2/crypto/hash" + + "chainmaker.org/chainmaker/vm-native/v2/common" "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" "chainmaker.org/chainmaker/pb-go/v2/syscontract" @@ -69,17 +70,18 @@ func registerDPoSERC20ContractMethods(log protocol.Logger) map[string]common.Con methodMap := make(map[string]common.ContractFunc, 64) // [DPoS] dposRuntime := NewDPoSRuntime(log) - methodMap[syscontract.DPoSERC20Function_GET_BALANCEOF.String()] = dposRuntime.BalanceOf - methodMap[syscontract.DPoSERC20Function_TRANSFER.String()] = dposRuntime.Transfer - //methodMap[syscontract.DPoSERC20Function_TRANSFER_FROM.String()] = dposRuntime.TransferFrom - //methodMap[syscontract.DPoSERC20Function_GET_ALLOWANCE.String()] = dposRuntime.Allowance - //methodMap[syscontract.DPoSERC20Function_APPROVE.String()] = dposRuntime.Approve - methodMap[syscontract.DPoSERC20Function_MINT.String()] = dposRuntime.Mint - //methodMap[syscontract.DPoSERC20Function_BURN.String()] = dposRuntime.Burn - //methodMap[syscontract.DPoSERC20Function_TRANSFER_OWNERSHIP.String()] = dposRuntime.TransferOwnership - methodMap[syscontract.DPoSERC20Function_GET_OWNER.String()] = dposRuntime.Owner - methodMap[syscontract.DPoSERC20Function_GET_DECIMALS.String()] = dposRuntime.Decimals - methodMap[syscontract.DPoSERC20Function_GET_TOTAL_SUPPLY.String()] = dposRuntime.Total + methodMap[syscontract.DPoSERC20Function_GET_BALANCEOF.String()] = common.WrapResultFunc(dposRuntime.BalanceOf) + methodMap[syscontract.DPoSERC20Function_TRANSFER.String()] = common.WrapResultFunc(dposRuntime.Transfer) + //methodMap[syscontract.DPoSERC20Function_TRANSFER_FROM.String()] = common.WrapResultFunc( dposRuntime.TransferFrom) + //methodMap[syscontract.DPoSERC20Function_GET_ALLOWANCE.String()] = common.WrapResultFunc( dposRuntime.Allowance) + //methodMap[syscontract.DPoSERC20Function_APPROVE.String()] = common.WrapResultFunc( dposRuntime.Approve) + methodMap[syscontract.DPoSERC20Function_MINT.String()] = common.WrapResultFunc(dposRuntime.Mint) + //methodMap[syscontract.DPoSERC20Function_BURN.String()] = common.WrapResultFunc( dposRuntime.Burn) + //methodMap[syscontract.DPoSERC20Function_TRANSFER_OWNERSHIP.String()] = common.WrapResultFunc( + //dposRuntime.TransferOwnership) + methodMap[syscontract.DPoSERC20Function_GET_OWNER.String()] = common.WrapResultFunc(dposRuntime.Owner) + methodMap[syscontract.DPoSERC20Function_GET_DECIMALS.String()] = common.WrapResultFunc(dposRuntime.Decimals) + methodMap[syscontract.DPoSERC20Function_GET_TOTAL_SUPPLY.String()] = common.WrapResultFunc(dposRuntime.Total) return methodMap } @@ -542,45 +544,72 @@ func setApproveValue(txSimContext protocol.TxSimContext, from, to string, val *u func loadSenderAddress(txSimContext protocol.TxSimContext) (string, error) { sender := txSimContext.GetSender() - if sender != nil { - // 将sender转换为用户地址 - var member []byte - if sender.MemberType == accesscontrol.MemberType_CERT { - // 长证书 - member = sender.MemberInfo - } else if sender.MemberType == accesscontrol.MemberType_CERT_HASH { - // 短证书 - memberInfoHex := hex.EncodeToString(sender.MemberInfo) - certInfo, err := getWholeCertInfo(txSimContext, memberInfoHex) - if err != nil { - return "", fmt.Errorf( - "can not load whole cert info , contract[%s] member[%s]", - dposErc20ContractName, memberInfoHex) - } - member = certInfo.Cert - } else { - return "", errors.New("invalid member type") + if sender == nil { + return "", fmt.Errorf("can not find sender from tx, contract[%s]", dposErc20ContractName) + } + // 将sender转换为用户地址 + var ( + err error + pubkey []byte + ) + switch sender.MemberType { + case accesscontrol.MemberType_CERT: + // 长证书 + if pubkey, err = getPubkeyFromCert(sender.MemberInfo); err != nil { + return "", err + } + case accesscontrol.MemberType_CERT_HASH: + var certInfo *commonPb.CertInfo + // 短证书 + memberInfoHex := hex.EncodeToString(sender.MemberInfo) + certInfo, err = getWholeCertInfo(txSimContext, memberInfoHex) + if err != nil { + return "", fmt.Errorf( + "can not load whole cert info , contract[%s] member[%s], reason: %s", + dposErc20ContractName, memberInfoHex, err) } - return parseUserAddress(member) + if pubkey, err = getPubkeyFromCert(certInfo.Cert); err != nil { + return "", err + } + case accesscontrol.MemberType_PUBLIC_KEY: + pubkey = sender.MemberInfo + default: + return "", fmt.Errorf("invalid member type: %s", sender.MemberType) + } + ac, err := txSimContext.GetAccessControl() + if err != nil { + return "", err } - return "", fmt.Errorf("can not find sender from tx, contract[%s]", dposErc20ContractName) + return calUserAddr(pubkey, ac.GetHashAlg()) } // parseUserAddress -func parseUserAddress(member []byte) (string, error) { +func getPubkeyFromCert(member []byte) ([]byte, error) { certificate, err := utils.ParseCert(member) if err != nil { - msg := fmt.Errorf("parse cert failed, name[%s] err: %+v", dposErc20ContractName, err) - return "", msg + return nil, fmt.Errorf("parse cert failed, name[%s] err: %+v", dposErc20ContractName, err) } pubKeyBytes, err := certificate.PublicKey.Bytes() if err != nil { - msg := fmt.Errorf("load public key from cert failed, name[%s] err: %+v", dposErc20ContractName, err) - return "", msg + return nil, fmt.Errorf("load public key from cert failed, name[%s] err: %+v", dposErc20ContractName, err) + } + return pubKeyBytes, nil +} + +func calUserAddr(pubkey []byte, hashType string) (string, error) { + var ( + err error + hashBz []byte + ) + if hashType == crypto.CRYPTO_ALGO_SM3 || hashType == crypto.CRYPTO_ALGO_SHA256 { + if hashBz, err = hash.GetByStrType(hashType, pubkey); err != nil { + return "", err + } + } else { + return "", fmt.Errorf("not support hashAlgo: %s", hashType) } - // 转换为SHA-256 - addressBytes := sha256.Sum256(pubKeyBytes) - return base58.Encode(addressBytes[:]), nil + addr := base58.Encode(hashBz[:]) + return addr, nil } func getWholeCertInfo(txSimContext protocol.TxSimContext, certHash string) (*commonPb.CertInfo, error) { diff --git a/dposmgr/dpos_erc20_contract_test.go b/dposmgr/dpos_erc20_contract_test.go index 1488ba3881ce9d35c6be38ac45209aaed96a8b0b..9d7d66a3704baec81f6520871ce969a82fbfce3e 100644 --- a/dposmgr/dpos_erc20_contract_test.go +++ b/dposmgr/dpos_erc20_contract_test.go @@ -12,9 +12,9 @@ import ( "testing" "chainmaker.org/chainmaker/protocol/v2/mock" + "chainmaker.org/chainmaker/protocol/v2/test" "github.com/golang/mock/gomock" - "chainmaker.org/chainmaker/logger/v2" acPb "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" "chainmaker.org/chainmaker/protocol/v2" "github.com/stretchr/testify/require" @@ -180,7 +180,11 @@ func TestDPoSRuntime_TransferFrom(t *testing.T) { } func TestOwnerCert(t *testing.T) { - address, err := parseUserAddress(ownerCert()) + pubkey, err := getPubkeyFromCert(ownerCert()) + if err != nil { + fmt.Println(err) + } + address, err := calUserAddr(pubkey, "SHA256") if err != nil { fmt.Println(err) } @@ -193,6 +197,10 @@ func initEnv(t *testing.T) (*DPoSRuntime, protocol.TxSimContext, func()) { ctrl := gomock.NewController(t) txSimContext := mock.NewMockTxSimContext(ctrl) + acTest := mock.NewMockAccessControlProvider(ctrl) + acTest.EXPECT().GetHashAlg().Return("SHA256").AnyTimes() + txSimContext.EXPECT().GetAccessControl().Return(acTest, nil).AnyTimes() + cache := NewCacheMock() txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( func(name string, key []byte, value []byte) error { @@ -226,8 +234,7 @@ func initEnv(t *testing.T) (*DPoSRuntime, protocol.TxSimContext, func()) { } func NewLogger() protocol.Logger { - cmLogger := logger.GetLogger("DPoS") - return cmLogger + return &test.GoLogger{} } func ownerCert() []byte { diff --git a/dposmgr/dpos_stake_contract.go b/dposmgr/dpos_stake_contract.go index 7dbce390d772943d6ed483aa8a7fa738af013d6d..ef34e0a7d2c7c9f467cd5c4c2f7937ec0270ed46 100644 --- a/dposmgr/dpos_stake_contract.go +++ b/dposmgr/dpos_stake_contract.go @@ -19,7 +19,7 @@ import ( "chainmaker.org/chainmaker/common/v2/bytehelper" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/vm-native/v2/common" "github.com/gogo/protobuf/proto" "github.com/mr-tron/base58" ) @@ -53,6 +53,8 @@ const ( KeyCompletionUnbondingEpochNumber = "UEN" // 这个 number 不能改动,若改动,会遇到 unbonding entry 数组中 completionEpochID 不同的情况 KeyEpochValidatorNumber = "EVN" KeyEpochBlockNumber = "EBN" + + ErrorGetValueByKey = "get value error, key: %s has not been set or value not exists" ) // ToValidatorKey - Key: V + "/" + ValidatorAddress @@ -172,42 +174,42 @@ func registerDPoSStakeContractMethods(log protocol.Logger) map[string]common.Con // implement stakeRuntime := &DPoSStakeRuntime{log: log} - methodMap[syscontract.DPoSStakeFunction_GET_ALL_CANDIDATES.String()] = - stakeRuntime.GetAllCandidates - methodMap[syscontract.DPoSStakeFunction_GET_VALIDATOR_BY_ADDRESS.String()] = - stakeRuntime.GetValidatorByAddress - methodMap[syscontract.DPoSStakeFunction_DELEGATE.String()] = - stakeRuntime.Delegate - methodMap[syscontract.DPoSStakeFunction_GET_DELEGATIONS_BY_ADDRESS.String()] = - stakeRuntime.GetDelegationsByAddress - methodMap[syscontract.DPoSStakeFunction_GET_USER_DELEGATION_BY_VALIDATOR.String()] = - stakeRuntime.GetUserDelegationByValidator - methodMap[syscontract.DPoSStakeFunction_UNDELEGATE.String()] = - stakeRuntime.UnDelegate - methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BY_ID.String()] = - stakeRuntime.ReadEpochByID - methodMap[syscontract.DPoSStakeFunction_READ_LATEST_EPOCH.String()] = - stakeRuntime.ReadLatestEpoch - methodMap[syscontract.DPoSStakeFunction_SET_NODE_ID.String()] = - stakeRuntime.SetNodeID - methodMap[syscontract.DPoSStakeFunction_GET_NODE_ID.String()] = - stakeRuntime.GetNodeID - methodMap[syscontract.DPoSStakeFunction_READ_MIN_SELF_DELEGATION.String()] = - stakeRuntime.ReadMinSelfDelegation - //methodMap[syscontract.DPoSStakeFunction_UPDATE_MIN_SELF_DELEGATION.String()] = - //DPoSStakeRuntime.UpdateMinSelfDelegation - methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_VALIDATOR_NUMBER.String()] = - stakeRuntime.ReadEpochValidatorNumber - //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_VALIDATOR_NUMBER.String()] = - //DPoSStakeRuntime.UpdateEpochValidatorNumber - methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BLOCK_NUMBER.String()] = - stakeRuntime.ReadEpochBlockNumber - methodMap[syscontract.DPoSStakeFunction_READ_SYSTEM_CONTRACT_ADDR.String()] = - stakeRuntime.ReadSystemContractAddr - //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_BLOCK_NUMBER.String()] = - //DPoSStakeRuntime.UpdateEpochBlockNumber - methodMap[syscontract.DPoSStakeFunction_READ_COMPLETE_UNBOUNDING_EPOCH_NUMBER.String()] = - stakeRuntime.ReadCompleteUnBoundingEpochNumber + methodMap[syscontract.DPoSStakeFunction_GET_ALL_CANDIDATES.String()] = common.WrapResultFunc( + stakeRuntime.GetAllCandidates) + methodMap[syscontract.DPoSStakeFunction_GET_VALIDATOR_BY_ADDRESS.String()] = common.WrapResultFunc( + stakeRuntime.GetValidatorByAddress) + methodMap[syscontract.DPoSStakeFunction_DELEGATE.String()] = common.WrapResultFunc( + stakeRuntime.Delegate) + methodMap[syscontract.DPoSStakeFunction_GET_DELEGATIONS_BY_ADDRESS.String()] = common.WrapResultFunc( + stakeRuntime.GetDelegationsByAddress) + methodMap[syscontract.DPoSStakeFunction_GET_USER_DELEGATION_BY_VALIDATOR.String()] = common.WrapResultFunc( + stakeRuntime.GetUserDelegationByValidator) + methodMap[syscontract.DPoSStakeFunction_UNDELEGATE.String()] = common.WrapResultFunc( + stakeRuntime.UnDelegate) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BY_ID.String()] = common.WrapResultFunc( + stakeRuntime.ReadEpochByID) + methodMap[syscontract.DPoSStakeFunction_READ_LATEST_EPOCH.String()] = common.WrapResultFunc( + stakeRuntime.ReadLatestEpoch) + methodMap[syscontract.DPoSStakeFunction_SET_NODE_ID.String()] = common.WrapResultFunc( + stakeRuntime.SetNodeID) + methodMap[syscontract.DPoSStakeFunction_GET_NODE_ID.String()] = common.WrapResultFunc( + stakeRuntime.GetNodeID) + methodMap[syscontract.DPoSStakeFunction_READ_MIN_SELF_DELEGATION.String()] = common.WrapResultFunc( + stakeRuntime.ReadMinSelfDelegation) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_MIN_SELF_DELEGATION.String()] = common.WrapResultFunc( + //DPoSStakeRuntime.UpdateMinSelfDelegation) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_VALIDATOR_NUMBER.String()] = common.WrapResultFunc( + stakeRuntime.ReadEpochValidatorNumber) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_VALIDATOR_NUMBER.String()] = common.WrapResultFunc( + //DPoSStakeRuntime.UpdateEpochValidatorNumber) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BLOCK_NUMBER.String()] = common.WrapResultFunc( + stakeRuntime.ReadEpochBlockNumber) + methodMap[syscontract.DPoSStakeFunction_READ_SYSTEM_CONTRACT_ADDR.String()] = common.WrapResultFunc( + stakeRuntime.ReadSystemContractAddr) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_BLOCK_NUMBER.String()] = common.WrapResultFunc( + //DPoSStakeRuntime.UpdateEpochBlockNumber) + methodMap[syscontract.DPoSStakeFunction_READ_COMPLETE_UNBOUNDING_EPOCH_NUMBER.String()] = common.WrapResultFunc( + stakeRuntime.ReadCompleteUnBoundingEpochNumber) return methodMap } @@ -606,6 +608,9 @@ func (s *DPoSStakeRuntime) canDelete(context protocol.TxSimContext, undelegateVa if err != nil { return err } + if len(bz) <= 0 { + return fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyEpochValidatorNumber")) + } amount := decodeUint64FromBigEndian(bz) collection, err := s.getAllCandidates(context) @@ -633,6 +638,9 @@ func (s *DPoSStakeRuntime) ReadLatestEpoch(context protocol.TxSimContext, params if err != nil { return nil, err } + if len(bz) <= 0 { + return nil, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyCurrentEpoch")) + } return bz, nil } @@ -667,6 +675,9 @@ func (s *DPoSStakeRuntime) ReadMinSelfDelegation( if err != nil { return nil, err } + if len(bz) <= 0 { + return nil, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyMinSelfDelegation")) + } return bz, nil } @@ -724,6 +735,9 @@ func (s *DPoSStakeRuntime) ReadEpochValidatorNumber( if err != nil { return nil, err } + if len(bz) <= 0 { + return nil, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyEpochValidatorNumber")) + } amount := decodeUint64FromBigEndian(bz) return []byte(strconv.Itoa(int(amount))), nil } @@ -783,6 +797,9 @@ func (s *DPoSStakeRuntime) ReadEpochBlockNumber( if err != nil { return nil, err } + if len(bz) <= 0 { + return nil, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyEpochBlockNumber")) + } amount := decodeUint64FromBigEndian(bz) return []byte(strconv.Itoa(int(amount))), nil } @@ -872,7 +889,7 @@ func getOrCreateValidator( // 新建 validator 判断 if delegatorAddress != validatorAddress { // 如果是新建 validator, 抵押人被抵押人必须是同一个人 - return nil, fmt.Errorf("no such validator, validator address: %s", validatorAddress) + return nil, fmt.Errorf("no such validator: %s", validatorAddress) } key := ToNodeIDKey(validatorAddress) if bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), key); err != nil || len(bz) == 0 { @@ -1008,7 +1025,7 @@ func (s *DPoSStakeRuntime) updateValidatorAndDelegationByUndelegate( } if cmp == -1 { // 检查当前网络情况下,节点是否能退出 - if err = s.canDelete(context, ""); err != nil { //TODO Devin Merge + if err = s.canDelete(context, undelegateValidatorAddress); err != nil { return nil, nil, err } @@ -1431,6 +1448,9 @@ func getUnbondingEpochNumber(context protocol.TxSimContext) (uint64, error) { if err != nil { return 0, err } + if len(bz) <= 0 { + return 0, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyCompletionUnbondingEpochNumber")) + } return binary.BigEndian.Uint64(bz), nil } @@ -1440,6 +1460,9 @@ func getMinSelfDelegation(context protocol.TxSimContext) (*big.Int, error) { if err != nil { return nil, err } + if len(bz) <= 0 { + return nil, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyMinSelfDelegation")) + } m, ok := big.NewInt(0).SetString(string(bz), 10) if !ok { return nil, fmt.Errorf("invalid minSelfDelegation in stakeContract config") diff --git a/dposmgr/dpos_stake_contract_test.go b/dposmgr/dpos_stake_contract_test.go index c757b6ca985cb14a42035378f0623c06da378992..7b9beafd5fad5c30ab385aede5d35e7886eb7da2 100644 --- a/dposmgr/dpos_stake_contract_test.go +++ b/dposmgr/dpos_stake_contract_test.go @@ -333,11 +333,37 @@ func TestSortCollections(t *testing.T) { require.Equal(t, c, Collections{"400000000000000", "50000000000", "3", "2", "1"}) } +func TestEmptyBasicParams(t *testing.T) { + rt, ctx, fn := setUp(t) + defer fn() + // remove basic params + ctx.Del(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyMinSelfDelegation)) + ctx.Del(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyCompletionUnbondingEpochNumber)) + ctx.Del(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochValidatorNumber)) + ctx.Del(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochBlockNumber)) + + // call api + var ( + err error + ) + _, err = rt.ReadMinSelfDelegation(ctx, nil) + require.Equal(t, err, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyMinSelfDelegation"))) + _, err = rt.ReadCompleteUnBoundingEpochNumber(ctx, nil) + require.Equal(t, err, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyCompletionUnbondingEpochNumber"))) + _, err = rt.ReadEpochValidatorNumber(ctx, nil) + require.Equal(t, err, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyEpochValidatorNumber"))) + _, err = rt.ReadEpochBlockNumber(ctx, nil) + require.Equal(t, err, fmt.Errorf(fmt.Sprintf(ErrorGetValueByKey, "KeyEpochBlockNumber"))) +} + func setUp(t *testing.T) (*DPoSStakeRuntime, protocol.TxSimContext, func()) { dPoSStakeRuntime := NewDPoSStakeRuntime(NewLogger()) ctrl := gomock.NewController(t) txSimContext := mock.NewMockTxSimContext(ctrl) + acTest := mock.NewMockAccessControlProvider(ctrl) + acTest.EXPECT().GetHashAlg().Return("SHA256").AnyTimes() + txSimContext.EXPECT().GetAccessControl().Return(acTest, nil).AnyTimes() cache := NewCacheMock() txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( func(name string, key []byte, value []byte) error { diff --git a/go.mod b/go.mod index 9dd436befb4e345d120eb7f1f2293cb28a034297..53d4c0f0a1b5912dc8e0e77e984100fbfc872b32 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,15 @@ -module chainmaker.org/chainmaker/vm-native +module chainmaker.org/chainmaker/vm-native/v2 go 1.15 require ( - chainmaker.org/chainmaker/chainconf/v2 v2.0.0-20210913144615-f27c44059848 - chainmaker.org/chainmaker/common/v2 v2.0.1-0.20211013080046-91ad24ce4d14 - chainmaker.org/chainmaker/localconf/v2 v2.0.0-20210913154622-9f9774ed7d1b - chainmaker.org/chainmaker/logger/v2 v2.0.0-20210907134457-53647922a89d - chainmaker.org/chainmaker/pb-go/v2 v2.0.1-0.20211011124513-b828aaef61ff - chainmaker.org/chainmaker/protocol/v2 v2.0.1-0.20210910112253-04256ae9c5ed - chainmaker.org/chainmaker/utils/v2 v2.0.0-20210907033606-84c6c841cbdb + chainmaker.org/chainmaker/chainconf/v2 v2.1.2-0.20220113072252-aecb4f7ffef0 + chainmaker.org/chainmaker/common/v2 v2.1.2-0.20220118101118-f256fc9c55e6 + chainmaker.org/chainmaker/localconf/v2 v2.1.1-0.20220112085516-908b8478be8f + chainmaker.org/chainmaker/logger/v2 v2.1.1-0.20211214124250-621f11b35ab0 + chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220214071858-6aaf92e86f04 + chainmaker.org/chainmaker/protocol/v2 v2.1.2-0.20220113081648-bbf6c1946b59 + chainmaker.org/chainmaker/utils/v2 v2.1.1-0.20220114120415-8e1af1e262a7 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 @@ -17,5 +17,4 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 - google.golang.org/protobuf v1.27.1 // indirect ) diff --git a/go.sum b/go.sum index 2b268d1d832a84efd209e44872ed43ced3766ab6..47d26759442fed9a99e56e98f5de534579f07d04 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,26 @@ -chainmaker.org/chainmaker/chainconf/v2 v2.0.0-20210913144615-f27c44059848 h1:T+9L0zZvwZitHBD4guSneNI0PtjBz1N90/r+LqN44Fg= -chainmaker.org/chainmaker/chainconf/v2 v2.0.0-20210913144615-f27c44059848/go.mod h1:wDj2Rp/Lwo/ptB7nh0vcCCY1qEALCHa9p3/mfvNzoCY= -chainmaker.org/chainmaker/common/v2 v2.0.1-0.20210901114756-9114511c2b70/go.mod h1:5PBx3EAorpJ+2PMtC15DHGUDLjLfXiEFp6LX67xxCAo= -chainmaker.org/chainmaker/common/v2 v2.0.1-0.20210906095952-6d8f2c6cede0/go.mod h1:5PBx3EAorpJ+2PMtC15DHGUDLjLfXiEFp6LX67xxCAo= -chainmaker.org/chainmaker/common/v2 v2.0.1-0.20210909033927-2a4cfc146579/go.mod h1:5PBx3EAorpJ+2PMtC15DHGUDLjLfXiEFp6LX67xxCAo= -chainmaker.org/chainmaker/common/v2 v2.0.1-0.20211013080046-91ad24ce4d14 h1:tPgJHS1S9sQmnRTYVn7Rzsff0aC49XjlS60S3rVgqDk= -chainmaker.org/chainmaker/common/v2 v2.0.1-0.20211013080046-91ad24ce4d14/go.mod h1:efmjrWLyQctsftWcmYkS2zu+wLjQITvDWKuCiufHyhc= -chainmaker.org/chainmaker/localconf/v2 v2.0.0-20210913154622-9f9774ed7d1b h1:OZrG2iel8/je9kHOIh2JHehg6YzI0eq2KUFg7OojlAE= -chainmaker.org/chainmaker/localconf/v2 v2.0.0-20210913154622-9f9774ed7d1b/go.mod h1:SPqpohsoeMrRFhPHnDQMRiWylLr5PfMQIlxbrPppzhI= -chainmaker.org/chainmaker/logger/v2 v2.0.0-20210907133316-af00cea33c97/go.mod h1:/6mAB4cPLK2GB9epL3uU8srK/iMXZb2dbg2lcJa+3bg= -chainmaker.org/chainmaker/logger/v2 v2.0.0-20210907134457-53647922a89d h1:D27rC2lDGsVH1piY1jCR8eTIPsqJGCWeWgt9XeXN4l0= -chainmaker.org/chainmaker/logger/v2 v2.0.0-20210907134457-53647922a89d/go.mod h1:/6mAB4cPLK2GB9epL3uU8srK/iMXZb2dbg2lcJa+3bg= -chainmaker.org/chainmaker/pb-go/v2 v2.0.1-0.20210901132412-435b75070bf2/go.mod h1:gDZodc1Kp6snzGXugS/REqfCqNNizhniQmjeOKUVf64= -chainmaker.org/chainmaker/pb-go/v2 v2.0.1-0.20211011124513-b828aaef61ff h1:Qw7bU367mLAfHKTzcEbTknD1ACkVWwCPAryh0ZZsqRs= -chainmaker.org/chainmaker/pb-go/v2 v2.0.1-0.20211011124513-b828aaef61ff/go.mod h1:gDZodc1Kp6snzGXugS/REqfCqNNizhniQmjeOKUVf64= -chainmaker.org/chainmaker/protocol/v2 v2.0.1-0.20210901134008-4b83cf573272/go.mod h1:JW18QbTxfZLnyhZ847hltgQ/qiOeEhkpS0X5lJKcUiA= -chainmaker.org/chainmaker/protocol/v2 v2.0.1-0.20210910112253-04256ae9c5ed h1:rXUVHq9Y3h7bCwez7fY6iND/OD21SXZdMTkDMDuNfUY= -chainmaker.org/chainmaker/protocol/v2 v2.0.1-0.20210910112253-04256ae9c5ed/go.mod h1:JW18QbTxfZLnyhZ847hltgQ/qiOeEhkpS0X5lJKcUiA= -chainmaker.org/chainmaker/utils/v2 v2.0.0-20210907033606-84c6c841cbdb h1:zhyfW8GK0HoIrys0sPupNSFva2fk/KmjOo9MAm37REs= -chainmaker.org/chainmaker/utils/v2 v2.0.0-20210907033606-84c6c841cbdb/go.mod h1:XcBXE+g1t1FtajaiIE6sVQbzdWK2ekt6oL+jj2I67gU= +chainmaker.org/chainmaker/chainconf/v2 v2.1.2-0.20220113072252-aecb4f7ffef0 h1:iCWWSFcQTy/jos6Q3X0QUl3Blp/lyFKFnxKRpWUSmQY= +chainmaker.org/chainmaker/chainconf/v2 v2.1.2-0.20220113072252-aecb4f7ffef0/go.mod h1:AR2MszGq1lxI9sHfqj/80cYQ0TMICMT1cANDeNNxv+s= +chainmaker.org/chainmaker/common/v2 v2.1.1-0.20211214041159-fe0b2240f08c/go.mod h1:mxLliE20J5mML421llb1T8vj9VtULEMGDA88TITgl68= +chainmaker.org/chainmaker/common/v2 v2.1.2-0.20211223085411-e4d0e79b2fb7/go.mod h1:mxLliE20J5mML421llb1T8vj9VtULEMGDA88TITgl68= +chainmaker.org/chainmaker/common/v2 v2.1.2-0.20220118101118-f256fc9c55e6 h1:S1cCAfr20W+yV2oiFi64Mm0tCi/amQ01vc6W5fubQwQ= +chainmaker.org/chainmaker/common/v2 v2.1.2-0.20220118101118-f256fc9c55e6/go.mod h1:mxLliE20J5mML421llb1T8vj9VtULEMGDA88TITgl68= +chainmaker.org/chainmaker/localconf/v2 v2.1.1-0.20220112085516-908b8478be8f h1:LrJM1BxZSNuVu4856jIHefku2/0dNGwVoIsvHCgEQi8= +chainmaker.org/chainmaker/localconf/v2 v2.1.1-0.20220112085516-908b8478be8f/go.mod h1:ylpW9ir14psujTtKb6qQW81aKhnhjzWW3n9XpjD9S0A= +chainmaker.org/chainmaker/logger/v2 v2.1.1-0.20211214124250-621f11b35ab0 h1:62Lqj463DA9D9g+B8Ciy9RgVf9KmP+4Ayyu0MHiGIJs= +chainmaker.org/chainmaker/logger/v2 v2.1.1-0.20211214124250-621f11b35ab0/go.mod h1:pGuJzxvh/JywvHX2+ezy+Xts/Pajw4PGspKGc27U1ow= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20211214073209-1288f39035e8/go.mod h1:gDZodc1Kp6snzGXugS/REqfCqNNizhniQmjeOKUVf64= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220110032709-5947499a1a6d/go.mod h1:b5fg5e93xCjSHU1b5yk/mnslab+z7N08kMkNVDoSpcI= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220111065457-38aa34ce86a3/go.mod h1:b5fg5e93xCjSHU1b5yk/mnslab+z7N08kMkNVDoSpcI= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220119062501-d1b3a201f7fb h1:HmLJvvtUyRmiDc8rCtLdentg0alEXCRgtZB+WSqYs+4= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220119062501-d1b3a201f7fb/go.mod h1:b5fg5e93xCjSHU1b5yk/mnslab+z7N08kMkNVDoSpcI= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220214071858-6aaf92e86f04 h1:OLttQm33khJS+uFhomYEert2YHmtJVR5F8vYn9Tz3vI= +chainmaker.org/chainmaker/pb-go/v2 v2.1.1-0.20220214071858-6aaf92e86f04/go.mod h1:b5fg5e93xCjSHU1b5yk/mnslab+z7N08kMkNVDoSpcI= +chainmaker.org/chainmaker/protocol/v2 v2.1.2-0.20220110033503-d6b4e5a065d9/go.mod h1:7VlxwX9MHyHpfAFw7OW+y7hUqawbp/GZKLeQlRDVZdk= +chainmaker.org/chainmaker/protocol/v2 v2.1.2-0.20220113081648-bbf6c1946b59 h1:SR3GsTur2WAsDllkmAWCxFtcWjzVWG9DIWDsYWnzfYs= +chainmaker.org/chainmaker/protocol/v2 v2.1.2-0.20220113081648-bbf6c1946b59/go.mod h1:SYkMoufkVVj4wI1JOU/YpV4Re4Z2i1WXgk+sn0ulWDk= +chainmaker.org/chainmaker/utils/v2 v2.1.1-0.20220110033929-0723ce6bd6ac/go.mod h1:gcBoQ+BL9xodHvb5oh8SLfdo9IEOYzGx+XLsECTj5xk= +chainmaker.org/chainmaker/utils/v2 v2.1.1-0.20220114120415-8e1af1e262a7 h1:RT1NbZf0M7i4p9WmDOoGD59W1FygpEMd5mL8Otzqa4w= +chainmaker.org/chainmaker/utils/v2 v2.1.1-0.20220114120415-8e1af1e262a7/go.mod h1:GeDrATiYzHJ6tdzV3+81kBjCBy5Bb9fCjTQLZLE6kJo= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -26,15 +29,43 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.4.0/go.mod h1:ZusYJWlOshgSBGbt6K3GnB3MT3H1xs2id9+TCl4fDBA= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -60,6 +91,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/appleboy/gin-jwt/v2 v2.6.3/go.mod h1:MfPYA4ogzvOcVkRwAxT7quHOtQmVKDpTwxyUrC2DNw0= @@ -68,6 +100,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.26.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -110,6 +143,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -122,6 +156,7 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI= @@ -163,6 +198,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= @@ -175,8 +212,8 @@ github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzP github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsouza/fake-gcs-server v1.15.0/go.mod h1:HNxAJ/+FY/XSsxuwz8iIYdp2GtMmPbJ8WQjjGMxd6Qk= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -192,6 +229,7 @@ github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7N github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -226,6 +264,7 @@ github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/goccy/go-graphviz v0.0.5/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v0.0.0-20180717141946-636bf0302bc9/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -242,11 +281,17 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -255,6 +300,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -264,10 +310,12 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -275,16 +323,36 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190930153522-6ce02741cba3/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200407044318-7d83b28da2e9/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -294,7 +362,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -311,17 +379,23 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -334,8 +408,11 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hokaccha/go-prettyjson v0.0.0-20201222001619-a42f9ac2ec8e h1:1vxUQ6PL1sROZtmO5IBbWKpq2y0CxjeZJl50rnen5js= github.com/hokaccha/go-prettyjson v0.0.0-20201222001619-a42f9ac2ec8e/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -343,6 +420,7 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/hypnoglow/gormzap v0.3.0/go.mod h1:5Wom8B7Jl2oK0Im9hs6KQ+Kl92w4Y7gKCrj66rhyvw0= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -369,11 +447,11 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -389,9 +467,11 @@ github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -415,24 +495,27 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -442,6 +525,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= github.com/mgechev/revive v1.0.2/go.mod h1:rb0dQy1LVAxW9SWy5R3LPUjevzUbUS316U5MFySA2lo= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -449,19 +534,20 @@ github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1 github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= @@ -527,8 +613,9 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.3.0 h1:e5+lF2E4Y2WCIxBefVowBuB0iHrUH4HZ8q+6mGF7fJc= github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d/go.mod h1:lXfE4PvvTW5xOjO6Mba8zDPyw8M93B6AQ7frTGnMlA8= @@ -594,9 +681,11 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= @@ -639,6 +728,7 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -653,9 +743,7 @@ github.com/shurcooL/vfsgen v0.0.0-20181020040650-a97a25d856ca/go.mod h1:TrYk7fJV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= @@ -664,17 +752,20 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -682,8 +773,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= +github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -722,8 +813,6 @@ github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/tinylru v1.0.2/go.mod h1:HDVL7TsWeezQ4g44Um84TOVBMFcq7Xa9giqNc805KJ8= -github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= -github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -752,23 +841,32 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.10.0/go.mod h1:vLRicqpG/qQEzno4SYU86iCwfT95EZza+Eba0ItuxqY= @@ -776,9 +874,9 @@ go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -787,8 +885,8 @@ go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -799,17 +897,18 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -817,6 +916,9 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -828,16 +930,20 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -860,30 +966,60 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -912,7 +1048,9 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -920,24 +1058,55 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -964,6 +1133,7 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -980,16 +1150,41 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200325203130-f53864d0dba1/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1004,12 +1199,34 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.1/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181004005441-af9cb2a35e7f/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1025,8 +1242,47 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v0.0.0-20180607172857-7a6a684ca69e/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1041,10 +1297,26 @@ google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRn google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1053,6 +1325,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -1073,8 +1346,9 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= +gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1087,22 +1361,25 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20180531100431-4c381bd170b4/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/government/government_contract.go b/government/government_contract.go index 83fa56683ff072dd6d811f125736cc9ef9700a41..06dd8a80256421d8db2905e225f69cca547a58eb 100644 --- a/government/government_contract.go +++ b/government/government_contract.go @@ -10,7 +10,7 @@ package government import ( "fmt" - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/vm-native/v2/common" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" @@ -40,7 +40,9 @@ func registerGovernmentContractMethods(log protocol.Logger) map[string]common.Co methodMap := make(map[string]common.ContractFunc, 64) // cert manager governmentRuntime := &GovernmentRuntime{log: log} - methodMap[syscontract.ChainQueryFunction_GET_GOVERNANCE_CONTRACT.String()] = governmentRuntime.GetGovernmentContract + methodMap[syscontract.ChainQueryFunction_GET_GOVERNANCE_CONTRACT.String()] = common.WrapResultFunc( + governmentRuntime.GetGovernmentContract) + return methodMap } diff --git a/multisign/multi_sign_contract.go b/multisign/multi_sign_contract.go index 7f3f2a127c194403901aa8f48b96bd3ea1d338db..06f884980d72e8e66b6edcaddbbf79fe056e48b6 100644 --- a/multisign/multi_sign_contract.go +++ b/multisign/multi_sign_contract.go @@ -11,12 +11,11 @@ import ( "errors" "fmt" - "chainmaker.org/chainmaker/vm-native/common" - commonPb "chainmaker.org/chainmaker/pb-go/v2/common" "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" "github.com/gogo/protobuf/proto" ) @@ -35,6 +34,7 @@ func NewMultiSignContract(log protocol.Logger) *MultiSignContract { methods: InitMultiContractMethods(log), } } + func (c *MultiSignContract) GetMethod(methodName string) common.ContractFunc { return c.methods[methodName] } @@ -42,9 +42,9 @@ func (c *MultiSignContract) GetMethod(methodName string) common.ContractFunc { func InitMultiContractMethods(log protocol.Logger) map[string]common.ContractFunc { methodMap := make(map[string]common.ContractFunc, 64) runtime := &MultiSignRuntime{log: log} - methodMap[syscontract.MultiSignFunction_REQ.String()] = runtime.Req - methodMap[syscontract.MultiSignFunction_VOTE.String()] = runtime.Vote - methodMap[syscontract.MultiSignFunction_QUERY.String()] = runtime.Query + methodMap[syscontract.MultiSignFunction_REQ.String()] = common.WrapResultFunc(runtime.Req) + methodMap[syscontract.MultiSignFunction_VOTE.String()] = common.WrapResultFunc(runtime.Vote) + methodMap[syscontract.MultiSignFunction_QUERY.String()] = common.WrapResultFunc(runtime.Query) return methodMap } @@ -52,19 +52,24 @@ type MultiSignRuntime struct { log protocol.Logger } -// Req request to multi sign +// Req request to multi sign, call a native contract func (r *MultiSignRuntime) Req(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( result []byte, err error) { - // 1、校验并获取参数 + // 1、verify param sysContractName := parameters[syscontract.MultiReq_SYS_CONTRACT_NAME.String()] sysMethod := parameters[syscontract.MultiReq_SYS_METHOD.String()] r.log.Infof("multi sign req start. ContractName[%s] Method[%s]", sysContractName, sysMethod) + if utils.IsAnyBlank(sysContractName, sysMethod) { err = fmt.Errorf("multi req params verify fail. sysContractName/sysMethod cannot be empty") return nil, err } + if !supportMultiSign(string(sysContractName), string(sysMethod)) { + err = fmt.Errorf("multi sign not support %s, only support CONTRACT_MANAGE", sysContractName) + return nil, err + } - // 构建多签对象并记录 + // building multi sign objects tx := txSimContext.GetTx() multiSignInfo := &syscontract.MultiSignInfo{ Payload: tx.Payload, @@ -77,10 +82,11 @@ func (r *MultiSignRuntime) Req(txSimContext protocol.TxSimContext, parameters ma for _, endorser := range tx.Endorsers { multiSignInfo.VoteInfos = append(multiSignInfo.VoteInfos, &syscontract.MultiSignVoteInfo{ Vote: syscontract.VoteStatus_AGREE, - Endorsement: endorser, // 签名在接收交易时已被验证 + Endorsement: endorser, }) } + // save status multiSignInfoBytes, _ := multiSignInfo.Marshal() err = txSimContext.Put(contractName, []byte(tx.Payload.TxId), multiSignInfoBytes) if err != nil { @@ -88,32 +94,36 @@ func (r *MultiSignRuntime) Req(txSimContext protocol.TxSimContext, parameters ma return nil, err } - r.log.Infof("multi sign req end") + r.log.Infof("multi sign req end. ContractName[%s] Method[%s], votes count %d", + sysContractName, sysMethod, len(multiSignInfo.VoteInfos)) return []byte(tx.Payload.TxId), nil } func (r *MultiSignRuntime) Vote(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( result []byte, err error) { - // 1、检查参数 - // 2、获取历史投票记录 - // 3、判断是否继续可以对该多签交易投票 - // 4、根据传入参数的状态修改多签结果 - // 5、根据结果调用accessControl校验是否认证成功 + // 1、verify param + // 2、get history vote record + // 3、judge vote authority + // 4、change vote status + // 5、call actual native contract + voteInfoBytes := parameters[syscontract.MultiVote_VOTE_INFO.String()] txId := parameters[syscontract.MultiVote_TX_ID.String()] r.log.Infof("multi sign vote start. MultiVote_TX_ID[%s]", txId) + if utils.IsAnyBlank(voteInfoBytes, txId) { - err = fmt.Errorf("multi vote params verify fail. voteInfo/txId cannot be empty") + err = fmt.Errorf("multi sign vote params verify fail. voteInfo/txId cannot be empty") r.log.Warn(err) return nil, err } + multiSignInfoBytes, err := txSimContext.Get(contractName, txId) if err != nil { r.log.Warn(err) return nil, err } if multiSignInfoBytes == nil { - return nil, fmt.Errorf("not found tx id from db %s", txId) + return nil, fmt.Errorf("not found tx id[%s]", txId) } multiSignInfo := &syscontract.MultiSignInfo{} @@ -122,30 +132,29 @@ func (r *MultiSignRuntime) Vote(txSimContext protocol.TxSimContext, parameters m r.log.Warn(err) return nil, err } - // 校验:该多签是否已完成投票 + + // verify: has the user voted reqVoteInfo := &syscontract.MultiSignVoteInfo{} err = proto.Unmarshal(voteInfoBytes, reqVoteInfo) if err != nil { r.log.Warn(err) return nil, err } - ac, err := txSimContext.GetAccessControl() if err != nil { r.log.Warn(err) return nil, err } - // 校验:该用户是否已投票 - err = r.verifyMemberVote(ac, reqVoteInfo, multiSignInfo, txId) - if err != nil { + if err = r.hasVoted(ac, reqVoteInfo, multiSignInfo, txId); err != nil { r.log.Warn(err) return nil, err } + // verify: sign mPayloadByte, _ := multiSignInfo.Payload.Marshal() resourceName := multiSignInfo.ContractName + "-" + multiSignInfo.Method - // 校验当前签名 - principal, err := ac.CreatePrincipal(resourceName, []*commonPb.EndorsementEntry{reqVoteInfo.Endorsement}, + principal, err := ac.CreatePrincipal(resourceName, + []*commonPb.EndorsementEntry{reqVoteInfo.Endorsement}, mPayloadByte) if err != nil { r.log.Warn(err) @@ -157,47 +166,36 @@ func (r *MultiSignRuntime) Vote(txSimContext protocol.TxSimContext, parameters m return nil, err } if len(endorsement) == 0 { - err = fmt.Errorf("the multi sign vote signature[org:%s] is err, error:%s", - reqVoteInfo.Endorsement.Signer.OrgId, err) + err = fmt.Errorf("the multi sign vote signature[org:%s] is invalid", + reqVoteInfo.Endorsement.Signer.OrgId) r.log.Error(err) return nil, err } multiSignInfo.VoteInfos = append(multiSignInfo.VoteInfos, reqVoteInfo) - var ( - contractResultBytes []byte - contractErr error - ) - // 校验多签签名 + + // verify: multi sign endorsers := make([]*commonPb.EndorsementEntry, 0) for _, info := range multiSignInfo.VoteInfos { - endorsers = append(endorsers, info.Endorsement) - } - principal1, err := ac.CreatePrincipal(resourceName, endorsers, mPayloadByte) - if err != nil { - r.log.Warn(err) - return nil, err - } - endorsement1, err := ac.GetValidEndorsements(principal1) //problem - if err != nil { - r.log.Warn(err) - return nil, err - } - if len(endorsement1) == 0 { - err = fmt.Errorf("the multi vote is err, error: %s", err.Error()) - r.log.Warn(err) - return nil, err - } - multiSignVerify, err := ac.VerifyPrincipal(principal1) - if err != nil { - r.log.Warn("multi sign vote verify fail.", err) + if info.Vote == syscontract.VoteStatus_AGREE { + endorsers = append(endorsers, info.Endorsement) + } } - - if multiSignVerify { - r.log.Info("multi sign vote verify success.") - contractResultBytes, contractErr = r.invokeContract(txSimContext, multiSignInfo) + if len(endorsers) != 0 { + if ok, err2 := r.verifySignature(ac, resourceName, endorsers, mPayloadByte); err2 != nil { + return nil, err2 + } else if ok { + r.log.Infof("multi sign vote [org:%s] verify success, currently %d valid signatures are collected", + reqVoteInfo.Endorsement.Signer.OrgId, len(endorsers)) + // call contract and set status + r.invokeContract(txSimContext, multiSignInfo) + } + //} else { + // do nothing + // maybe: authentication fail not enough participants support this action: + // 3 valid endorsements required, 1 valid endorsements received } - // 7、记录状态 + // record status multiSignInfoBytes, err = multiSignInfo.Marshal() if err != nil { r.log.Error(err) @@ -208,21 +206,42 @@ func (r *MultiSignRuntime) Vote(txSimContext protocol.TxSimContext, parameters m r.log.Error(err) return nil, err } - // return must not nil - if len(contractResultBytes) == 0 { - contractResultBytes = []byte("vote success") - } r.log.Infof("multi sign vote[%s] end", txId) - return contractResultBytes, contractErr + return []byte("OK"), nil +} + +func (r *MultiSignRuntime) verifySignature(ac protocol.AccessControlProvider, resourceName string, + endorsers []*commonPb.EndorsementEntry, mPayloadByte []byte) (bool, error) { + principal, err := ac.CreatePrincipal(resourceName, endorsers, mPayloadByte) + if err != nil { + r.log.Warn(err) + return false, err + } + endorsement, err := ac.GetValidEndorsements(principal) + if err != nil { + r.log.Warn(err) + return false, err + } + if len(endorsement) == 0 { + err = fmt.Errorf("multi sign vote error,endorsement:%s is invalid", endorsement) + r.log.Warn(err) + return false, err + } + multiSignVerify, err := ac.VerifyPrincipal(principal) + if err != nil { + r.log.Warn("multi sign vote verify fail.", err) + } + return multiSignVerify, nil } -func (r *MultiSignRuntime) verifyMemberVote(ac protocol.AccessControlProvider, +func (r *MultiSignRuntime) hasVoted(ac protocol.AccessControlProvider, reqVoteInfo *syscontract.MultiSignVoteInfo, multiSignInfo *syscontract.MultiSignInfo, txId []byte) error { if multiSignInfo.Status != syscontract.MultiSignStatus_PROCESSING { err := fmt.Errorf("the multi sign[%s] has been completed", txId) r.log.Warn(err) return err } + signer, err := ac.NewMember(reqVoteInfo.Endorsement.Signer) if err != nil { r.log.Warn(err) @@ -241,7 +260,7 @@ func (r *MultiSignRuntime) verifyMemberVote(ac protocol.AccessControlProvider, } func (r *MultiSignRuntime) invokeContract(txSimContext protocol.TxSimContext, - multiSignInfo *syscontract.MultiSignInfo) (contractResultBytes []byte, contractErr error) { + multiSignInfo *syscontract.MultiSignInfo) { txId := txSimContext.GetTx().Payload.TxId contract := &commonPb.Contract{ Name: multiSignInfo.ContractName, @@ -260,23 +279,23 @@ func (r *MultiSignRuntime) invokeContract(txSimContext protocol.TxSimContext, initParam[parameter.Key] = parameter.Value } byteCode := initParam[syscontract.InitContract_CONTRACT_BYTECODE.String()] - contractResult, statusCode := txSimContext.CallContract(contract, multiSignInfo.Method, byteCode, + contractResult, _, statusCode := txSimContext.CallContract(contract, multiSignInfo.Method, byteCode, initParam, 0, commonPb.TxType_INVOKE_CONTRACT) if statusCode == commonPb.TxStatusCode_SUCCESS { - contractResultBytes = contractResult.Result + multiSignInfo.Message = "OK" multiSignInfo.Status = syscontract.MultiSignStatus_ADOPTED - r.log.Infof("multi sign vote[%s] finished, result: %s", txId, contractResultBytes) + multiSignInfo.Result = contractResult.Result + r.log.Infof("multi sign vote[%s] finished, result: %s", txId, contractResult.Result) } else { - contractErr = errors.New(contractResult.Message) + contractErr := errors.New(contractResult.Message) + multiSignInfo.Message = contractErr.Error() multiSignInfo.Status = syscontract.MultiSignStatus_FAILED r.log.Warnf("multi sign vote[%s] failed, msg: %s", txId, contractErr) } - return contractResultBytes, contractErr } func (r *MultiSignRuntime) Query(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( result []byte, err error) { - // 1、校验并获取参数 txId := parameters[syscontract.MultiVote_TX_ID.String()] if utils.IsAnyBlank(txId) { err = fmt.Errorf("multi sign query params verify fail. txId cannot be empty") @@ -291,3 +310,7 @@ func (r *MultiSignRuntime) Query(txSimContext protocol.TxSimContext, parameters return multiSignInfoDB, nil } + +func supportMultiSign(contractName, method string) bool { + return contractName == syscontract.SystemContract_CONTRACT_MANAGE.String() +} diff --git a/native.go b/native.go index 3a1c41d191dbc9fb6575d25edcc69fe6296625b4..8b342a976ee9e11bf68d9d5a4c7f35b26347e257 100644 --- a/native.go +++ b/native.go @@ -7,27 +7,34 @@ package native import ( + "fmt" "sync" - "chainmaker.org/chainmaker/vm-native/multisign" - - "chainmaker.org/chainmaker/vm-native/crosstranscation" - - "chainmaker.org/chainmaker/vm-native/privatecompute" - - "chainmaker.org/chainmaker/pb-go/v2/syscontract" - - "chainmaker.org/chainmaker/vm-native/blockcontract" - "chainmaker.org/chainmaker/vm-native/certmgr" - "chainmaker.org/chainmaker/vm-native/chainconfigmgr" - "chainmaker.org/chainmaker/vm-native/common" - "chainmaker.org/chainmaker/vm-native/contractmgr" - "chainmaker.org/chainmaker/vm-native/dposmgr" - "chainmaker.org/chainmaker/vm-native/government" - "chainmaker.org/chainmaker/logger/v2" commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/vm-native/v2/accountmgr" + "chainmaker.org/chainmaker/vm-native/v2/blockcontract" + "chainmaker.org/chainmaker/vm-native/v2/certmgr" + "chainmaker.org/chainmaker/vm-native/v2/chainconfigmgr" + "chainmaker.org/chainmaker/vm-native/v2/common" + "chainmaker.org/chainmaker/vm-native/v2/contractmgr" + "chainmaker.org/chainmaker/vm-native/v2/crosstranscation" + "chainmaker.org/chainmaker/vm-native/v2/dposmgr" + "chainmaker.org/chainmaker/vm-native/v2/government" + "chainmaker.org/chainmaker/vm-native/v2/multisign" + "chainmaker.org/chainmaker/vm-native/v2/privatecompute" + "chainmaker.org/chainmaker/vm-native/v2/pubkeymgr" + "chainmaker.org/chainmaker/vm-native/v2/testcontract" + contractmgr210 "chainmaker.org/chainmaker/vm-native/v2/v210/contractmgr" + dposmgr210 "chainmaker.org/chainmaker/vm-native/v2/v210/dposmgr" + multisign210 "chainmaker.org/chainmaker/vm-native/v2/v210/multisign" +) + +const ( + blockVersion210 = uint32(20) + contractName210Suffix = "_210" ) var ( @@ -37,12 +44,13 @@ var ( type RuntimeInstance struct { // contracts map[contractName]Contract - contracts map[string]common.Contract - log protocol.Logger + contracts map[string]common.Contract + log protocol.Logger + defaultGas uint64 } // GetRuntimeInstance get singleton RuntimeInstance -func GetRuntimeInstance(chainId string) *RuntimeInstance { +func GetRuntimeInstance(chainId string, defaultGas uint64) *RuntimeInstance { instance, ok := nativeInstance[chainId] if !ok { nativeLock.Lock() @@ -51,8 +59,9 @@ func GetRuntimeInstance(chainId string) *RuntimeInstance { if !ok { log := logger.GetLoggerByChain(logger.MODULE_VM, chainId) instance = &RuntimeInstance{ - log: log, - contracts: initContract(log), + log: log, + contracts: initContract(log), + defaultGas: defaultGas, } nativeInstance[chainId] = instance } @@ -72,6 +81,21 @@ func initContract(log protocol.Logger) map[string]common.Contract { contracts[syscontract.SystemContract_DPOS_STAKE.String()] = dposmgr.NewDPoSStakeContract(log) contracts[syscontract.SystemContract_CONTRACT_MANAGE.String()] = contractmgr.NewContractManager(log) contracts[syscontract.SystemContract_CROSS_TRANSACTION.String()] = crosstranscation.NewCrossTransactionContract(log) + contracts[syscontract.SystemContract_PUBKEY_MANAGE.String()] = pubkeymgr.NewPubkeyManageContract(log) + contracts[syscontract.SystemContract_ACCOUNT_MANAGER.String()] = accountmgr.NewAccountManager(log) + contracts[syscontract.SystemContract_T.String()] = testcontract.NewManager(log) + + // history version v2.1.0 + var ( + erc20210 = syscontract.SystemContract_DPOS_ERC20.String() + contractName210Suffix + stake210 = syscontract.SystemContract_DPOS_STAKE.String() + contractName210Suffix + multiSign210 = syscontract.SystemContract_MULTI_SIGN.String() + contractName210Suffix + contractManage210 = syscontract.SystemContract_CONTRACT_MANAGE.String() + contractName210Suffix + ) + contracts[erc20210] = dposmgr210.NewDPoSERC20Contract(log) + contracts[stake210] = dposmgr210.NewDPoSStakeContract(log) + contracts[multiSign210] = multisign210.NewMultiSignContract(log) + contracts[contractManage210] = contractmgr210.NewContractManager(log) return contracts } @@ -83,102 +107,101 @@ func (r *RuntimeInstance) Invoke(contract *commonPb.Contract, methodName string, Code: uint32(1), Message: "contract internal error", Result: nil, + GasUsed: r.defaultGas, } - - //txType := txContext.GetTx().Header.TxType - //if txType == commonPb.TxType_INVOKE_CONTRACT { - // if err := r.verifySequence(txContext); err != nil { - // result.Message = fmt.Sprintf(err.Error()+",txType: %s", txType) - // return result - // } - //} - - f, err := r.getContractFunc(contract, methodName) + blockVersion := txContext.GetBlockVersion() + // get native func + f, err := r.getContractFunc(contract, methodName, blockVersion) if err != nil { r.log.Warn(err) result.Message = err.Error() return result } - // verification - var verifyAccessFunc common.ContractFunc - var accessResultBytes []byte - verifyAccessContract := &commonPb.Contract{ - Name: syscontract.SystemContract_CONTRACT_MANAGE.String(), - Version: contract.Version, - RuntimeType: commonPb.RuntimeType_NATIVE, - Status: commonPb.ContractStatus_NORMAL, - Creator: nil, - } - verifyMethodName := "VERIFY_CONTRACT_ACCESS" - verifyAccessFunc, err = r.getContractFunc(verifyAccessContract, verifyMethodName) - if err != nil { - r.log.Warn(err) - result.Message = err.Error() - return result - } - - accessResultBytes, err = verifyAccessFunc(txContext, nil) - if err != nil { - r.log.Error(err) - result.Message = err.Error() - return result - } - if string(accessResultBytes) == "true" { - // exec - bytes, err := f(txContext, parameters) - if err != nil { - r.log.Error(err) - result.Message = err.Error() + switch blockVersion { + case blockVersion210: + if err := r.verify210(contract.Version, txContext); err != nil { + result.Code = 1 + result.Message = "Access Denied" + result.Result = nil return result } - result.Code = 0 - result.Message = "OK" - result.Result = bytes - return result } - result.Code = 1 - result.Message = "Access Denied" - result.Result = nil + // invoke native func + result = f(txContext, parameters) + + //calc gas + if r.defaultGas > 0 { + //check gas table + gas := common.GetGas(contract.Name, methodName, r.defaultGas) + result.GasUsed += gas + } return result } -//func (r *RuntimeInstance) verifySequence(txContext protocol.TxSimContext) error { -// tx := txContext.GetTx() -// payload := tx.Payload -// -// bytes, err := txContext.Get(syscontract.SystemContract_CHAIN_CONFIG.String(), -// []byte(syscontract.SystemContract_CHAIN_CONFIG.String())) -// var chainConfig configPb.ChainConfig -// err = proto.Unmarshal(bytes, &chainConfig) -// if err != nil { -// r.log.Errorw(common.ErrUnmarshalFailed.Error(), "Position", "configPb.ChainConfig Unmarshal", "err", err) -// return common.ErrUnmarshalFailed -// } -// -// if payload.Sequence != chainConfig.Sequence+1 { -// // the sequence is not incre 1 -// r.log.Errorw(common.ErrSequence.Error(), "chainConfig", chainConfig.Sequence, "sdk chainConfig", payload.Sequence) -// return common.ErrSequence -// } -// return nil -//} - -func (r *RuntimeInstance) getContractFunc(contract *commonPb.Contract, methodName string) (common.ContractFunc, error) { - if contract == nil { - return nil, common.ErrContractIdIsNil +func (r *RuntimeInstance) getContractFunc(contract *commonPb.Contract, methodName string, blockVersion uint32) ( + f common.ContractFunc, err error) { + var ( + contractInst common.Contract + contractName = contract.Name + ) + + switch blockVersion { + case blockVersion210: + if useHistoryContract210(contractName) { + contractName = contractName + contractName210Suffix + } } - contractName := contract.Name - contractInst := r.contracts[contractName] + contractInst = r.contracts[contractName] if contractInst == nil { return nil, common.ErrContractNotFound } - f := contractInst.GetMethod(methodName) + f = contractInst.GetMethod(methodName) if f == nil { return nil, common.ErrMethodNotFound } + return f, nil } + +func useHistoryContract210(contractName string) bool { + switch contractName { + case syscontract.SystemContract_DPOS_ERC20.String(): + return true + case syscontract.SystemContract_DPOS_STAKE.String(): + return true + case syscontract.SystemContract_MULTI_SIGN.String(): + return true + case syscontract.SystemContract_CONTRACT_MANAGE.String(): + return true + default: + return false + } +} + +func (r *RuntimeInstance) verify210(version string, txContext protocol.TxSimContext) error { + // verification + var verifyAccessFunc common.ContractFunc + verifyAccessContract := &commonPb.Contract{ + Name: syscontract.SystemContract_CONTRACT_MANAGE.String(), + Version: version, + RuntimeType: commonPb.RuntimeType_NATIVE, + Status: commonPb.ContractStatus_NORMAL, + Creator: nil, + } + verifyMethodName := "VERIFY_CONTRACT_ACCESS" + verifyAccessFunc, err := r.getContractFunc(verifyAccessContract, verifyMethodName, blockVersion210) + if err != nil { + return err + } + + accessResult := verifyAccessFunc(txContext, nil) + if string(accessResult.Result) != "true" { //无权访问 + accessResult.GasUsed = r.defaultGas + return fmt.Errorf("access denied") + } + return nil +} diff --git a/privatecompute/private_compute_contract.go b/privatecompute/private_compute_contract.go index 1c4679ebb7549d12a93a6f5cc10177d447197171..f517a9d16568b6548db13737a10fd58cd915cf1b 100644 --- a/privatecompute/private_compute_contract.go +++ b/privatecompute/private_compute_contract.go @@ -24,7 +24,6 @@ import ( "chainmaker.org/chainmaker/common/v2/crypto" "chainmaker.org/chainmaker/common/v2/crypto/asym/rsa" "chainmaker.org/chainmaker/common/v2/crypto/hash" - "chainmaker.org/chainmaker/common/v2/crypto/tee" bcx509 "chainmaker.org/chainmaker/common/v2/crypto/x509" "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" commonPb "chainmaker.org/chainmaker/pb-go/v2/common" @@ -32,8 +31,7 @@ import ( teePb "chainmaker.org/chainmaker/pb-go/v2/tee" "chainmaker.org/chainmaker/protocol/v2" "chainmaker.org/chainmaker/utils/v2" - - "chainmaker.org/chainmaker/vm-native/common" + "chainmaker.org/chainmaker/vm-native/v2/common" ) const ( @@ -66,31 +64,38 @@ func registerPrivateComputeContractMethods(log protocol.Logger) map[string]commo // cert manager privateComputeRuntime := &PrivateComputeRuntime{log: log} - queryMethodMap[syscontract.PrivateComputeFunction_GET_CONTRACT.String()] = privateComputeRuntime.GetContract - queryMethodMap[syscontract.PrivateComputeFunction_GET_DATA.String()] = privateComputeRuntime.GetData - queryMethodMap[syscontract.PrivateComputeFunction_SAVE_CA_CERT.String()] = privateComputeRuntime.SaveEnclaveCACert - queryMethodMap[syscontract.PrivateComputeFunction_SAVE_DIR.String()] = privateComputeRuntime.SaveDir - queryMethodMap[syscontract.PrivateComputeFunction_SAVE_DATA.String()] = privateComputeRuntime.SaveData - queryMethodMap[syscontract.PrivateComputeFunction_SAVE_ENCLAVE_REPORT.String()] = - privateComputeRuntime.SaveEnclaveReport - queryMethodMap[syscontract.PrivateComputeFunction_GET_DIR.String()] = privateComputeRuntime.GetDir - queryMethodMap[syscontract.PrivateComputeFunction_GET_CA_CERT.String()] = privateComputeRuntime.GetEnclaveCACert - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_PROOF.String()] = - privateComputeRuntime.GetEnclaveProof - queryMethodMap[syscontract.PrivateComputeFunction_CHECK_CALLER_CERT_AUTH.String()] = - privateComputeRuntime.CheckCallerCertAuth - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_ENCRYPT_PUB_KEY.String()] = - privateComputeRuntime.GetEnclaveEncryptPubKey - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_VERIFICATION_PUB_KEY.String()] = - privateComputeRuntime.GetEnclaveVerificationPubKey - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_REPORT.String()] = - privateComputeRuntime.GetEnclaveReport - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_CHALLENGE.String()] = - privateComputeRuntime.GetEnclaveChallenge - queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_SIGNATURE.String()] = - privateComputeRuntime.GetEnclaveSignature - queryMethodMap[syscontract.PrivateComputeFunction_SAVE_REMOTE_ATTESTATION.String()] = - privateComputeRuntime.SaveRemoteAttestation + queryMethodMap[syscontract.PrivateComputeFunction_GET_CONTRACT.String()] = common.WrapResultFunc( + privateComputeRuntime.GetContract) + queryMethodMap[syscontract.PrivateComputeFunction_GET_DATA.String()] = common.WrapResultFunc( + privateComputeRuntime.GetData) + queryMethodMap[syscontract.PrivateComputeFunction_SAVE_CA_CERT.String()] = common.WrapResultFunc( + privateComputeRuntime.SaveEnclaveCACert) + queryMethodMap[syscontract.PrivateComputeFunction_SAVE_DIR.String()] = common.WrapResultFunc( + privateComputeRuntime.SaveDir) + queryMethodMap[syscontract.PrivateComputeFunction_SAVE_DATA.String()] = common.WrapResultFunc( + privateComputeRuntime.SaveData) + queryMethodMap[syscontract.PrivateComputeFunction_SAVE_ENCLAVE_REPORT.String()] = common.WrapResultFunc( + privateComputeRuntime.SaveEnclaveReport) + queryMethodMap[syscontract.PrivateComputeFunction_GET_DIR.String()] = common.WrapResultFunc( + privateComputeRuntime.GetDir) + queryMethodMap[syscontract.PrivateComputeFunction_GET_CA_CERT.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveCACert) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_PROOF.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveProof) + queryMethodMap[syscontract.PrivateComputeFunction_CHECK_CALLER_CERT_AUTH.String()] = common.WrapResultFunc( + privateComputeRuntime.CheckCallerCertAuth) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_ENCRYPT_PUB_KEY.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveEncryptPubKey) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_VERIFICATION_PUB_KEY.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveVerificationPubKey) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_REPORT.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveReport) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_CHALLENGE.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveChallenge) + queryMethodMap[syscontract.PrivateComputeFunction_GET_ENCLAVE_SIGNATURE.String()] = common.WrapResultFunc( + privateComputeRuntime.GetEnclaveSignature) + queryMethodMap[syscontract.PrivateComputeFunction_SAVE_REMOTE_ATTESTATION.String()] = common.WrapResultFunc( + privateComputeRuntime.SaveRemoteAttestation) return queryMethodMap } @@ -698,7 +703,7 @@ func (r *PrivateComputeRuntime) SaveRemoteAttestation(context protocol.TxSimCont r.log.Errorf(formatErr.Error()) return nil, formatErr } - passed, proof, err := tee.GrapheneAttestationVerify( + passed, proof, err := utils.GrapheneAttestationVerify( proofT, verifyOption, reportFromChain) diff --git a/privatecompute/private_compute_contract_test.go b/privatecompute/private_compute_contract_test.go index fbf90d672d9b13556b8cf89a870f1447607031c4..2f1b15a6c27d9435d45ba45b7e42fa7c9b18ce72 100644 --- a/privatecompute/private_compute_contract_test.go +++ b/privatecompute/private_compute_contract_test.go @@ -16,6 +16,7 @@ import ( "chainmaker.org/chainmaker/logger/v2" "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2/test" ) var ( @@ -44,7 +45,7 @@ func TestSaveEnclaveCaCert(t *testing.T) { mockCtx := newTxContextMock(ds) privateComputeRuntime := PrivateComputeRuntime{ - log: logger.GetLogger("test-logger"), + log: &test.GoLogger{}, } // 读取CA证书 @@ -65,7 +66,7 @@ func TestSaveEnclaveReport(t *testing.T) { mockCtx := newTxContextMock(ds) privateComputeRuntime := PrivateComputeRuntime{ - log: logger.GetLogger("test-logger"), + log: &test.GoLogger{}, } // 读取report diff --git a/privatecompute/remote_attestation.go b/privatecompute/remote_attestation.go index 3bffe0d1e363732f1f2c71081c3ee4564bcce154..0198a4e3fe3dfa5a52d1cd3ec0381cc5aae0ac9f 100644 --- a/privatecompute/remote_attestation.go +++ b/privatecompute/remote_attestation.go @@ -13,7 +13,8 @@ import ( bccrypto "chainmaker.org/chainmaker/common/v2/crypto" "chainmaker.org/chainmaker/common/v2/crypto/asym" - "chainmaker.org/chainmaker/common/v2/crypto/tee" + "chainmaker.org/chainmaker/utils/v2" + bcx509 "chainmaker.org/chainmaker/common/v2/crypto/x509" ) @@ -35,7 +36,7 @@ func getPubkeyPairFromCert(pemData []byte) (verificationPubKey bccrypto.PublicKe } // get pem data of crypto public key from cert - encryptPubkeyPemData, err := bcx509.GetExtByOid(tee.OidKeyBag, cert.Extensions) + encryptPubkeyPemData, err := bcx509.GetExtByOid(utils.OidKeyBag, cert.Extensions) if err != nil { retErr = fmt.Errorf("get crypto pubkey by oid error: %v", err) return diff --git a/privatecompute/tx_context_mock.go b/privatecompute/tx_context_mock.go index bf72e949b6cc0470bc43fe468453b7aae5b903b3..361130c1adb99d45d907276f2cfe42a6f46b754a 100644 --- a/privatecompute/tx_context_mock.go +++ b/privatecompute/tx_context_mock.go @@ -22,6 +22,30 @@ type TxContextMock struct { cacheMap dataStore } +func (s *TxContextMock) GetNoRecord(contractName string, key []byte) ([]byte, error) { + panic("implement me") +} + +func (s *TxContextMock) GetBlockTimestamp() int64 { + panic("implement me") +} + +func (s *TxContextMock) GetIterHandle(index int32) (interface{}, bool) { + panic("implement me") +} + +func (s *TxContextMock) SetIterHandle(index int32, iter interface{}) { + panic("implement me") +} + +func (s *TxContextMock) GetHistoryIterForKey(contractName string, key []byte) (protocol.KeyHistoryIterator, error) { + panic("implement me") +} + +func (mock *TxContextMock) PutIntoReadSet(contractName string, key []byte, value []byte) { + panic("implement me") +} + func (mock *TxContextMock) GetContractByName(name string) (*commonPb.Contract, error) { panic("implement me") } @@ -83,7 +107,7 @@ func (*TxContextMock) CallContract(contract *commonPb.Contract, parameter map[string][]byte, gasUsed uint64, refTxType commonPb.TxType, -) (*commonPb.ContractResult, commonPb.TxStatusCode) { +) (*commonPb.ContractResult, protocol.ExecOrderTxType, commonPb.TxStatusCode) { panic("implement me") } @@ -155,19 +179,3 @@ func (mock *TxContextMock) PutRecord(contractName string, value []byte, sqlType func (mock *TxContextMock) Select(name string, startKey []byte, limit []byte) (protocol.StateIterator, error) { panic("implement me") } - -func (mock *TxContextMock) SetStateSqlHandle(i int32, rows protocol.SqlRows) { - panic("implement me") -} - -func (mock *TxContextMock) GetStateSqlHandle(i int32) (protocol.SqlRows, bool) { - panic("implement me") -} - -func (mock *TxContextMock) GetStateKvHandle(int32) (protocol.StateIterator, bool) { - panic("implement me") -} - -func (mock *TxContextMock) SetStateKvHandle(int32, protocol.StateIterator) { - panic("implement me") -} diff --git a/pubkeymgr/pubkey_manage_contract.go b/pubkeymgr/pubkey_manage_contract.go new file mode 100644 index 0000000000000000000000000000000000000000..e773fada17a67932529e32a74453b5a92cc4f635 --- /dev/null +++ b/pubkeymgr/pubkey_manage_contract.go @@ -0,0 +1,219 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package pubkeymgr + +import ( + "crypto/sha256" + "errors" + "fmt" + "strings" + + "chainmaker.org/chainmaker/common/v2/crypto/asym" + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" + "github.com/gogo/protobuf/proto" + "github.com/mr-tron/base58" +) + +const ( + paramNameRole = "role" + paramNamePubkey = "pubkey" +) + +type PubkeyManageContract struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewPubkeyManageContract(log protocol.Logger) *PubkeyManageContract { + return &PubkeyManageContract{ + log: log, + methods: registerPubkeyManageContractMethods(log), + } +} + +func (c *PubkeyManageContract) GetMethod(methodName string) common.ContractFunc { + return c.methods[methodName] +} + +func registerPubkeyManageContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + // pubkey manager + pubkeyManageRuntime := &PubkeyManageRuntime{log: log} + + methodMap[syscontract.PubkeyManageFunction_PUBKEY_ADD.String()] = common.WrapResultFunc( + pubkeyManageRuntime.AddPubkey) + methodMap[syscontract.PubkeyManageFunction_PUBKEY_DELETE.String()] = common.WrapResultFunc( + pubkeyManageRuntime.DeletePubkey) + methodMap[syscontract.PubkeyManageFunction_PUBKEY_QUERY.String()] = common.WrapResultFunc( + pubkeyManageRuntime.QueryPubkey) + + return methodMap +} + +type PubkeyManageRuntime struct { + log protocol.Logger +} + +func NewPubkeyManageRuntime(log protocol.Logger) *PubkeyManageRuntime { + return &PubkeyManageRuntime{log: log} +} + +func pubkeyHash(pubkey []byte) string { + pkHash := sha256.Sum256(pubkey) + strPkHash := base58.Encode(pkHash[:]) + return strPkHash +} + +// Add pubkey +func (r *PubkeyManageRuntime) AddPubkey(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + org_id := string(params[protocol.ConfigNameOrgId]) + if utils.IsAnyBlank(org_id) { + err := fmt.Errorf("%s, param[org_id] of AddPubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + + role := string(params[paramNameRole]) + if utils.IsAnyBlank(role) { + err := fmt.Errorf("%s, param[role] of AddPubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + // check role + upperRole := strings.ToUpper(role) + if protocol.Role(upperRole) != protocol.RoleClient && protocol.Role(upperRole) != protocol.RoleLight && + protocol.Role(upperRole) != protocol.RoleCommonNode { + err := fmt.Errorf("%s, illegal param[role] of AddPubkey: %s", common.ErrParams.Error(), role) + r.log.Errorf(err.Error()) + return nil, err + } + + pubkey := string(params[paramNamePubkey]) + if utils.IsAnyBlank(pubkey) { + err := fmt.Errorf("%s, param[pubkey] of AddPubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + + pk, err := asym.PublicKeyFromPEM([]byte(pubkey)) + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkBytes, err := pk.Bytes() + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkHashKey := pubkeyHash(pkBytes) + + pkInfo := &accesscontrol.PKInfo{ + OrgId: org_id, + Role: upperRole, + PkBytes: pkBytes, + } + value, err := proto.Marshal(pkInfo) + if err != nil { + err := fmt.Errorf("marshal error in AddPubkey") + r.log.Errorf(err.Error()) + return nil, err + } + if err := context.Put(syscontract.SystemContract_PUBKEY_MANAGE.String(), []byte(pkHashKey), value); err != nil { + r.log.Errorf("Put failed in AddPubkey, err: %s", err.Error()) + return nil, err + } + + r.log.Infof("pubkey add success") + return []byte("Success"), nil +} + +// Delete pubkey +func (r *PubkeyManageRuntime) DeletePubkey(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + org_id := string(params[protocol.ConfigNameOrgId]) + if utils.IsAnyBlank(org_id) { + err := fmt.Errorf("%s, param[org_id] of DeletePubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + pubkey := string(params[paramNamePubkey]) + if utils.IsAnyBlank(pubkey) { + err := fmt.Errorf("%s, param[pubkey] of DeletePubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + pk, err := asym.PublicKeyFromPEM([]byte(pubkey)) + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkBytes, err := pk.Bytes() + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkHashKey := pubkeyHash(pkBytes) + bytes, err := context.Get(syscontract.SystemContract_PUBKEY_MANAGE.String(), []byte(pkHashKey)) + if err != nil { + r.log.Errorf("DeletePubkey get pubkey failed, pubkey[%s], err: %s", pubkey, err.Error()) + return nil, err + } + + if len(bytes) == 0 { + msg := fmt.Sprintf("DeletePubkey get pubkey failed, pubkey[%s], err: not exist", pubkey) + r.log.Error(msg) + return nil, errors.New(msg) + } + r.log.Infof("pubkey exists") + + err = context.Del(syscontract.SystemContract_PUBKEY_MANAGE.String(), []byte(pkHashKey)) + if err != nil { + r.log.Errorf("DeletePubkey for pubkey failed, pubkey[%s], err: %s", pubkey, err.Error()) + return nil, err + } + + r.log.Infof("pubkey delete success") + return []byte("Success"), nil +} + +// Query pubkey +func (r *PubkeyManageRuntime) QueryPubkey(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + pubkey := string(params[paramNamePubkey]) + if utils.IsAnyBlank(pubkey) { + err := fmt.Errorf("%s, param[pubkey] of QueryPubkey not found", common.ErrParams.Error()) + r.log.Errorf(err.Error()) + return nil, err + } + pk, err := asym.PublicKeyFromPEM([]byte(pubkey)) + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkBytes, err := pk.Bytes() + if err != nil { + r.log.Errorf(err.Error()) + return nil, err + } + + pkHashKey := pubkeyHash(pkBytes) + bytes, err := context.Get(syscontract.SystemContract_PUBKEY_MANAGE.String(), []byte(pkHashKey)) + if err != nil { + r.log.Errorf("QueryPubkey get pubkey failed, pubkey[%s], err: %s", pubkey, err.Error()) + return nil, err + } + + return bytes, nil +} diff --git a/pubkeymgr/pubkey_manage_contract_test.go b/pubkeymgr/pubkey_manage_contract_test.go new file mode 100644 index 0000000000000000000000000000000000000000..cbb44ec4a650fbee3b1a54d5cc1c610d6f35122b --- /dev/null +++ b/pubkeymgr/pubkey_manage_contract_test.go @@ -0,0 +1,178 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package pubkeymgr + +import ( + "fmt" + "testing" + + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/protocol/v2/mock" + "chainmaker.org/chainmaker/protocol/v2/test" + "github.com/gogo/protobuf/proto" + "github.com/golang/mock/gomock" +) + +const KeyFormat = "%s-%s" + +func realKey(name, key string) string { + return fmt.Sprintf(KeyFormat, name, key) +} + +type CacheMock struct { + content map[string][]byte +} + +func NewCacheMock() *CacheMock { + return &CacheMock{ + content: make(map[string][]byte, 64), + } +} + +func (c *CacheMock) Put(name, key string, value []byte) { + c.content[realKey(name, key)] = value +} + +func (c *CacheMock) Get(name, key string) []byte { + return c.content[realKey(name, key)] +} + +func (c *CacheMock) Del(name, key string) []byte { + delete(c.content, realKey(name, key)) + return []byte("Success") +} + +func (c *CacheMock) GetByKey(key string) []byte { + return c.content[key] +} + +func (c *CacheMock) Keys() []string { + sc := make([]string, 0) + for k := range c.content { + sc = append(sc, k) + } + return sc +} + +func newLogger() protocol.Logger { + return &test.GoLogger{} +} + +func initTestEnv(t *testing.T) (*PubkeyManageRuntime, protocol.TxSimContext, func()) { + pmRuntime := NewPubkeyManageRuntime(newLogger()) + ctrl := gomock.NewController(t) + txSimContext := mock.NewMockTxSimContext(ctrl) + + cache := NewCacheMock() + txSimContext.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte, value []byte) error { + cache.Put(name, string(key), value) + return nil + }).AnyTimes() + + txSimContext.EXPECT().Get(gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte) ([]byte, error) { + return cache.Get(name, string(key)), nil + }).AnyTimes() + + txSimContext.EXPECT().Del(gomock.Any(), gomock.Any()).DoAndReturn( + func(name string, key []byte) ([]byte, error) { + return cache.Del(name, string(key)), nil + }).AnyTimes() + return pmRuntime, txSimContext, func() { ctrl.Finish() } +} + +var strPubkey = "-----BEGIN PUBLIC KEY-----\n" + + "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAqM6qzNzBprMIqUbdDzkU\n" + + "Fwz8rhi4/ASZB4UNMgxZlbeIZKDqOmQ8I6QjKQ5ZGGMzMeB6oEVv2TQ/8Az8F/mj\n" + + "ok/w6vFrKM1m6j44W2x4DsO05jqgepOa9jr4Y4YSujOkMedS/mG3jSGLZtl+8nYB\n" + + "UmquIoacLHNsFmmqB+CY2u1lQ0EaB3XQ/scoQzvtwN54OLUg5xOTViODb59a/w+P\n" + + "ehu4YdTo5dLUY6idL24hCCVHIZQZMmBzg+lupxC4u8K5gPukEwcsYQ3IVhUHhvWC\n" + + "AqtRxMywSo3aXfeo+7HJiWouK8dIsL+3VrTQdV8fn9/TImCFDORtyfCGlxLvS9J9\n" + + "aUcpZrrk+qZUykZY3xRJ8pbhrgGghbmFJw/qCpeyTMfCooIdMezlBFoj2GdVLRLc\n" + + "LEIief1a4Qg9sg9bJ6Dtj+tEMwjF5opLWm7x36zoakMAu9dQ/O6X0za+jPjY7hTO\n" + + "BoACd/z8bWJEzVxb6jrFi+cGJY9i/n9CR4lWimzgYPQtAgMBAAE=\n" + + "-----END PUBLIC KEY-----" + +func TestAddPubkey(t *testing.T) { + pmRuntime, context, fn := initTestEnv(t) + defer fn() + + params := map[string][]byte{} + + params["pubkey"] = []byte(strPubkey) + params["org_id"] = []byte("org1") + params["role"] = []byte("client") + result, err := pmRuntime.AddPubkey(context, params) + if err != nil { + t.Fatalf("AddPubkey error: %v", err) + } + + fmt.Printf("result = %v \n", string(result)) +} + +func TestDelPubkey(t *testing.T) { + pmRuntime, context, fn := initTestEnv(t) + defer fn() + + params := map[string][]byte{} + + params["pubkey"] = []byte(strPubkey) + params["org_id"] = []byte("org1") + params["role"] = []byte("client") + result, err := pmRuntime.AddPubkey(context, params) + if err != nil { + t.Fatalf("AddPubkey error: %v", err) + } + + fmt.Printf("result = %v \n", string(result)) + + delparams := map[string][]byte{} + + delparams["org_id"] = []byte("org1") + delparams["pubkey"] = []byte(strPubkey) + + result2, err := pmRuntime.DeletePubkey(context, delparams) + + if err != nil { + t.Fatalf("DeletePubkey error: %v", err) + } + + fmt.Printf("result = %v \n", string(result2)) +} + +func TestQueryPubkey(t *testing.T) { + pmRuntime, context, fn := initTestEnv(t) + defer fn() + + params := map[string][]byte{} + + params["pubkey"] = []byte(strPubkey) + params["org_id"] = []byte("org1") + params["role"] = []byte("client") + result, err := pmRuntime.AddPubkey(context, params) + if err != nil { + t.Fatalf("AddPubkey error: %v", err) + } + + fmt.Printf("result = %v \n", string(result)) + queryparams := map[string][]byte{} + + queryparams["pubkey"] = []byte(strPubkey) + + result2, err := pmRuntime.QueryPubkey(context, queryparams) + if err != nil { + t.Fatalf("QueryPubkey error: %v", err) + } + info := &accesscontrol.PKInfo{} + if err = proto.Unmarshal(result2, info); err != nil { + t.Fatalf("Unmarshal error: %v", err) + } + fmt.Printf("org_id = %s, role = %s \n", info.OrgId, info.Role) +} diff --git a/testcontract/T.go b/testcontract/T.go new file mode 100644 index 0000000000000000000000000000000000000000..77f0cb4a1333fdd35cffd92887f296cd600813ab --- /dev/null +++ b/testcontract/T.go @@ -0,0 +1,66 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package testcontract + +import ( + "chainmaker.org/chainmaker/vm-native/v2/common" + + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" +) + +var ( + ContractName = syscontract.SystemContract_T.String() +) + +type Manager struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewManager(log protocol.Logger) *Manager { + return &Manager{ + log: log, + methods: registerTestContractMethods(log), + } +} + +func (c *Manager) GetMethod(methodName string) common.ContractFunc { + return c.methods[methodName] +} + +func registerTestContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + runtime := &ManagerRuntime{log: log} + methodMap[syscontract.TestContractFunction_P.String()] = common.WrapResultFunc(runtime.put) + methodMap[syscontract.TestContractFunction_G.String()] = common.WrapResultFunc(runtime.get) + methodMap[syscontract.TestContractFunction_D.String()] = common.WrapResultFunc(runtime.del) + methodMap[syscontract.TestContractFunction_N.String()] = common.WrapResultFunc(runtime.nothing) + return methodMap +} + +type ManagerRuntime struct { + log protocol.Logger +} + +func (r *ManagerRuntime) get(context protocol.TxSimContext, parameters map[string][]byte) ([]byte, error) { + return context.Get(ContractName, parameters["k"]) +} +func (r *ManagerRuntime) put(context protocol.TxSimContext, parameters map[string][]byte) ([]byte, error) { + k := parameters["k"] + v := parameters["v"] + return nil, context.Put(ContractName, k, v) +} + +func (r *ManagerRuntime) del(context protocol.TxSimContext, parameters map[string][]byte) ([]byte, error) { + return nil, context.Del(ContractName, parameters["k"]) +} +func (r *ManagerRuntime) nothing(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + return nil, nil +} diff --git a/v210/common/errors.go b/v210/common/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..2071080e2e554237fe931dedf938fb2e17c6f213 --- /dev/null +++ b/v210/common/errors.go @@ -0,0 +1,33 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package common210 + +import "errors" + +var ( + // ErrContractIdIsNil err msg + ErrContractIdIsNil = errors.New("the contractId is empty") + // ErrContractNotFound err msg + ErrContractNotFound = errors.New("the contractName is not exist") + // ErrTxTypeNotSupport err msg + ErrTxTypeNotSupport = errors.New("the txType does not support") + // ErrMethodNotFound err msg + ErrMethodNotFound = errors.New("the method does not found") + // ErrParamsEmpty err msg + ErrParamsEmpty = errors.New("the params is empty") + // ErrContractName err msg + ErrContractName = errors.New("the contractName is error") + // ErrOutOfRange err msg + ErrOutOfRange = errors.New("out of range") + // ErrParams err msg + ErrParams = errors.New("params is error") + // ErrSequence err msg + ErrSequence = errors.New("sequence is error") + // ErrUnmarshalFailed err msg + ErrUnmarshalFailed = errors.New("unmarshal is error") +) diff --git a/v210/common/gas.go b/v210/common/gas.go new file mode 100644 index 0000000000000000000000000000000000000000..611bcdc77b254cb1b854b8493ba3a8702de85455 --- /dev/null +++ b/v210/common/gas.go @@ -0,0 +1,31 @@ +package common210 + +import "chainmaker.org/chainmaker/pb-go/v2/syscontract" + +const DefaultGas = uint64(100000) + +// contractName: [functionName:gas] +var gasTable = map[string]map[string]uint64{ + syscontract.SystemContract_CHAIN_QUERY.String(): {"": DefaultGas}, //key: ""表示默认方法 + syscontract.SystemContract_CONTRACT_MANAGE.String(): { + syscontract.ContractManageFunction_INIT_CONTRACT.String(): 1000000, + syscontract.ContractManageFunction_UPGRADE_CONTRACT.String(): 1000000, + "": DefaultGas, + }, +} + +func GetGas(contractName, method string, defaultGas uint64) uint64 { + methodGasMap, ok := gasTable[contractName] + if !ok { //找不到合约的Gas设置 + return defaultGas + } + gas, ok2 := methodGasMap[method] + if !ok2 { //找不到匹配的,就找key为空的 + contractGas, ok3 := methodGasMap[""] + if !ok3 { + return defaultGas + } + return contractGas + } + return gas +} diff --git a/v210/common/interface.go b/v210/common/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..37c9aeee65c410714e4fce01787efe543d237ecb --- /dev/null +++ b/v210/common/interface.go @@ -0,0 +1,20 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package common210 + +import ( + "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2" +) + +type ContractFunc func(context protocol.TxSimContext, params map[string][]byte) *common.ContractResult + +// Contract define native Contract interface +type Contract interface { + GetMethod(methodName string) ContractFunc +} diff --git a/v210/common/result.go b/v210/common/result.go new file mode 100644 index 0000000000000000000000000000000000000000..740fc5f957eaaa8e24d31f657c6867eaf24fa48a --- /dev/null +++ b/v210/common/result.go @@ -0,0 +1,78 @@ +package common210 + +import ( + "encoding/json" + + "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2" +) + +func ResultSuccess(result []byte, gas uint64) *common.ContractResult { + return &common.ContractResult{ + Code: 0, + Result: result, + Message: "OK", + GasUsed: gas, + ContractEvent: nil, + } +} +func ResultError(err error) *common.ContractResult { + return &common.ContractResult{ + Code: 1, + Result: nil, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } +} +func ResultBytesAndError(returnResult []byte, err error) *common.ContractResult { + if err != nil { + return &common.ContractResult{ + Code: 1, + Result: nil, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } + } + return &common.ContractResult{ + Code: 0, + Result: returnResult, + Message: "OK", + GasUsed: 0, + ContractEvent: nil, + } +} +func ResultErrorWithGasUsed(err error, gas uint64) *common.ContractResult { + return &common.ContractResult{ + Code: 1, + Result: nil, + Message: err.Error(), + GasUsed: 0, + ContractEvent: nil, + } +} + +func ResultJson(obj interface{}) (*common.ContractResult, error) { + data, err := json.Marshal(obj) + if err != nil { + return nil, err + } + return &common.ContractResult{ + Code: 0, + Result: data, + Message: "OK", + GasUsed: 0, + ContractEvent: nil, + }, nil +} + +//WrapResultFunc 包装原有的返回[]byte的函数,改为返回ContractResult的函数 +func WrapResultFunc(f func(txSimContext protocol.TxSimContext, parameters map[string][]byte) ([]byte, error)) func( + txSimContext protocol.TxSimContext, parameters map[string][]byte) *common.ContractResult { + f2 := func(txSimContext protocol.TxSimContext, parameters map[string][]byte) *common.ContractResult { + result, err := f(txSimContext, parameters) + return ResultBytesAndError(result, err) + } + return f2 +} diff --git a/v210/contractmgr/contract_manager.go b/v210/contractmgr/contract_manager.go new file mode 100644 index 0000000000000000000000000000000000000000..46d29594e4b40fe2391253f36f3c3459c75dae5e --- /dev/null +++ b/v210/contractmgr/contract_manager.go @@ -0,0 +1,729 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package contractmgr210 + +import ( + "encoding/json" + "errors" + "fmt" + + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + + "chainmaker.org/chainmaker/vm-native/v2/chainconfigmgr" + "chainmaker.org/chainmaker/vm-native/v2/common" + common210 "chainmaker.org/chainmaker/vm-native/v2/v210/common" + + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + configPb "chainmaker.org/chainmaker/pb-go/v2/config" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/utils/v2" +) + +var ( + ContractName = syscontract.SystemContract_CONTRACT_MANAGE.String() + keyContractName = "_Native_Contract_List" + contractsForMultiSignWhiteList = []string{ + syscontract.SystemContract_CONTRACT_MANAGE.String(), + } + TRUE = []byte("true") + FALSE = []byte("false") +) + +type ContractManager struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewContractManager(log protocol.Logger) *ContractManager { + return &ContractManager{ + log: log, + methods: registerContractManagerMethods(log), + } +} + +func (c *ContractManager) GetMethod(methodName string) common.ContractFunc { + return c.methods[methodName] +} + +func registerContractManagerMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + runtime := &ContractManagerRuntime{log: log} + methodMap[syscontract.ContractManageFunction_INIT_CONTRACT.String()] = common210.WrapResultFunc( + runtime.installContract) + methodMap[syscontract.ContractManageFunction_UPGRADE_CONTRACT.String()] = common210.WrapResultFunc( + runtime.upgradeContract) + methodMap[syscontract.ContractManageFunction_FREEZE_CONTRACT.String()] = common210.WrapResultFunc( + runtime.freezeContract) + methodMap[syscontract.ContractManageFunction_UNFREEZE_CONTRACT.String()] = common210.WrapResultFunc( + runtime.unfreezeContract) + methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT.String()] = common210.WrapResultFunc( + runtime.revokeContract) + methodMap[syscontract.ContractQueryFunction_GET_CONTRACT_INFO.String()] = common210.WrapResultFunc( + runtime.getContractInfo) + methodMap[syscontract.ContractQueryFunction_GET_CONTRACT_LIST.String()] = common210.WrapResultFunc( + runtime.getAllContracts) + + methodMap[syscontract.ContractManageFunction_GRANT_CONTRACT_ACCESS.String()] = common210.WrapResultFunc( + runtime.grantContractAccess) + methodMap[syscontract.ContractManageFunction_REVOKE_CONTRACT_ACCESS.String()] = common210.WrapResultFunc( + runtime.revokeContractAccess) + methodMap[syscontract.ContractManageFunction_VERIFY_CONTRACT_ACCESS.String()] = common210.WrapResultFunc( + runtime.verifyContractAccess) + methodMap[syscontract.ContractQueryFunction_GET_DISABLED_CONTRACT_LIST.String()] = common210.WrapResultFunc( + runtime.getDisabledContractList) + + return methodMap + +} + +// enable access to a native contract +// this method will take off the contract name from the disabled contract list +func (r *ContractManagerRuntime) grantContractAccess(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + + var ( + err error + requestContractListBytes []byte + updatedContractListBytes []byte + disabledContractList []string + requestContractList []string + updatedContractList []string + ) + + // 1. fetch the disabled contract list + disabledContractList, err = r.fetchDisabledContractList(txSimContext) + if err != nil { + return nil, err + } + + // 2. get the requested contracts to enable access from parameters + requestContractListBytes = params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] + err = json.Unmarshal(requestContractListBytes, &requestContractList) + if err != nil { + return nil, err + } + for _, cn := range requestContractList { + if cn == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return nil, errors.New("can't grant contract_manage") + } + } + + // 3. adjust the disabled native contract list per the requested contract names + updatedContractList = filterContracts(disabledContractList, requestContractList) + updatedContractListBytes, err = json.Marshal(updatedContractList) + if err != nil { + return nil, err + } + + // 4. store the adjusted native contract list back to the database + err = storeDisabledContractList(txSimContext, updatedContractListBytes) + if err != nil { + return nil, err + } + + r.log.Infof("grant access to contract: %v succeed!", requestContractList) + return nil, nil +} + +// disable access to a native contract +// this method will add the contract names to the disabled contract list +func (r *ContractManagerRuntime) revokeContractAccess(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + var ( + err error + requestContractListBytes []byte + updatedContractListBytes []byte + disabledContractList []string + requestContractList []string + updatedContractList []string + ) + + // 1. fetch the disabled contract list + disabledContractList, err = r.fetchDisabledContractList(txSimContext) + if err != nil { + return nil, err + } + + // 2. get the requested contracts to disable access from parameters + requestContractListBytes = params[syscontract.ContractAccess_NATIVE_CONTRACT_NAME.String()] + err = json.Unmarshal(requestContractListBytes, &requestContractList) + if err != nil { + return nil, err + } + for _, cn := range requestContractList { + if cn == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return nil, errors.New("can't revoke contract_manage") + } + } + + // 3. adjust the disabled native contract list per the requested contract names + updatedContractList = append(disabledContractList, requestContractList...) + + updatedContractListBytes, err = json.Marshal(updatedContractList) + if err != nil { + return nil, err + } + + // 4. store the updated native contract list back to the database + err = storeDisabledContractList(txSimContext, updatedContractListBytes) + if err != nil { + return nil, err + } + + return nil, nil +} + +// verify if access to the requested contract is enabled according to the disabled contract list +// returns true as []byte if so or false otherwise +func (r *ContractManagerRuntime) verifyContractAccess(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + var ( + err error + disabledContractList []string + contractName string + method string + multiSignContractName string + ) + + // 1. fetch the disabled native contract list + disabledContractList, err = r.fetchDisabledContractList(txSimContext) + if err != nil { + return nil, err + } + + // 2. get the requested contract name and verify if it's on the disabled native contract list + contractName = txSimContext.GetTx().Payload.ContractName + method = txSimContext.GetTx().Payload.Method + if contractName == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return TRUE, nil + } + for _, cn := range disabledContractList { + if cn == contractName { + return FALSE, errors.New("the contract is in the disabled contract list") + } + } + + // 3. if the requested contract name is multisignature, get the underlying contract name from + // the tx payload and verify if it has access + // if the method name is not req, return true since it does not contain contract names in parameters + if contractName == syscontract.SystemContract_MULTI_SIGN.String() && + method == syscontract.MultiSignFunction_VOTE.String() { + return TRUE, nil + } + if contractName == syscontract.SystemContract_MULTI_SIGN.String() && + method == syscontract.MultiSignFunction_QUERY.String() { + return TRUE, nil + } + if contractName == syscontract.SystemContract_MULTI_SIGN.String() && + method == syscontract.MultiSignFunction_REQ.String() { + + multiSignContractName, err = getContractNameForMultiSign(txSimContext.GetTx().Payload.Parameters) + if err != nil { + return nil, err + } + if multiSignContractName == syscontract.SystemContract_CONTRACT_MANAGE.String() { + return TRUE, nil + } + // check if the requested contract is on the disabled contract list + for _, cn := range disabledContractList { + if cn == multiSignContractName { + return FALSE, errors.New("the contract is in the disabled contract list") + } + } + + // check if the requested contract list is on the multi sign white list + for _, cn := range contractsForMultiSignWhiteList { + if cn == multiSignContractName { + return TRUE, nil + } + } + + return FALSE, errors.New("the contract is not open for multi-sign") + } + + return TRUE, nil +} + +func getContractNameForMultiSign(params []*commonPb.KeyValuePair) (string, error) { + for i, pair := range params { + if pair.Key == syscontract.MultiReq_SYS_CONTRACT_NAME.String() { + return string(params[i].Value), nil + } + } + return "", errors.New("can't find the contract name for multi sign") +} + +// fetch the disabled contract list +func (r *ContractManagerRuntime) getDisabledContractList(txSimContext protocol.TxSimContext, + params map[string][]byte) ([]byte, error) { + var ( + err error + disabledContractList []string + disabledContractListBytes []byte + ) + + disabledContractList, err = r.fetchDisabledContractList(txSimContext) + fmt.Printf("the result is %v\n", disabledContractList) + + if err != nil { + return nil, err + } + + disabledContractListBytes, err = json.Marshal(disabledContractList) + + if err != nil { + return nil, err + } + return disabledContractListBytes, nil +} + +// store the disabled contract list to the database +func storeDisabledContractList(txSimContext protocol.TxSimContext, disabledContractListBytes []byte) error { + var ( + err error + refinedDisabledContractListBytes []byte + disabledContractList []string + refinedDisabledContractList []string + ) + err = json.Unmarshal(disabledContractListBytes, &disabledContractList) + if err != nil { + return err + } + + // filter out redundant contract names in the disabled contract list + uniqueMap := make(map[string]string) + for _, cn := range disabledContractList { + if _, ok := uniqueMap[cn]; !ok { + uniqueMap[cn] = cn + refinedDisabledContractList = append(refinedDisabledContractList, cn) + } + } + + refinedDisabledContractListBytes, err = json.Marshal(refinedDisabledContractList) + if err != nil { + return err + } + + err = txSimContext.Put(ContractName, []byte(keyContractName), refinedDisabledContractListBytes) + if err != nil { + return err + } + return nil +} + +// filter out request contracts from disabled contract list, return a newly updated list +func filterContracts(disabledContractList []string, requestedContractList []string) []string { + var updatedContractList []string + + // return the original list if no contracts have been requested + if len(requestedContractList) == 0 { + return disabledContractList + } + + m := make(map[string]int, len(requestedContractList)) + for _, cn := range requestedContractList { + m[cn] = 1 + } + + // populate the updatedContractList + for _, cn := range disabledContractList { + _, found := m[cn] + if !found { + updatedContractList = append(updatedContractList, cn) + } + } + + return updatedContractList +} + +// helper method to fetch the disabled contract list from genesis config file +// if not initialized or from the database otherwise +func (r *ContractManagerRuntime) fetchDisabledContractList(txSimContext protocol.TxSimContext) ([]string, error) { + // try to get disabled contract list from database + disabledContractListBytes, err := txSimContext.Get(ContractName, []byte(keyContractName)) + if err != nil { + return nil, err + } + + // if the config file does not exist in the database yet, try fetch it from the genesis config file and store it + // to the database + if disabledContractListBytes == nil { + disabledContractListBytes, err = r.initializeDisabledNativeContractList(txSimContext) + if err != nil { + r.log.Error(err) + return nil, err + } + } + + var disabledContractList []string + err = json.Unmarshal(disabledContractListBytes, &disabledContractList) + return disabledContractList, err +} + +func (r *ContractManagerRuntime) getContractInfo(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name := string(parameters[syscontract.GetContractInfo_CONTRACT_NAME.String()]) + contract, err := r.GetContractInfo(txSimContext, name) + if err != nil { + return nil, err + } + return json.Marshal(contract) +} + +func (r *ContractManagerRuntime) initializeDisabledNativeContractList( + txSimContext protocol.TxSimContext) ([]byte, error) { + var ( + err error + chainConfig *configPb.ChainConfig + disabledContractListBytes []byte + ) + + // 1. fetch chainConfig from genesis config file + chainConfig, err = chainconfigmgr.GetChainConfig(txSimContext) + if err != nil { + r.log.Error(err) + return nil, err + } + + disabledContractList := chainConfig.DisabledNativeContract + if disabledContractList == nil { + disabledContractList = make([]string, 0) + } + disabledContractListBytes, err = json.Marshal(disabledContractList) + if err != nil { + return nil, err + } + + // 2. store the disabledContractList field to the database + err = storeDisabledContractList(txSimContext, disabledContractListBytes) + if err != nil { + return nil, err + } + + return disabledContractListBytes, nil +} + +func (r *ContractManagerRuntime) getAllContracts(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + contracts, err := r.GetAllContracts(txSimContext) + if err != nil { + return nil, err + } + r.log.Debugf("getAllContracts result: %+v", contracts) + return json.Marshal(contracts) +} +func (r *ContractManagerRuntime) installContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name, version, byteCode, runtimeType, err := r.parseParam(parameters) + if err != nil { + return nil, err + } + contract, err := r.InstallContract(txSimContext, name, version, byteCode, runtimeType, parameters) + if err != nil { + return nil, err + } + r.log.Infof("install contract success[name:%s version:%s runtimeType:%d byteCodeLen:%d]", contract.Name, + contract.Version, contract.RuntimeType, len(byteCode)) + return contract.Marshal() +} + +func (r *ContractManagerRuntime) upgradeContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name, version, byteCode, runtimeType, err := r.parseParam(parameters) + if err != nil { + return nil, err + } + contract, err := r.UpgradeContract(txSimContext, name, version, byteCode, runtimeType, parameters) + if err != nil { + return nil, err + } + r.log.Infof("upgrade contract success[name:%s version:%s runtimeType:%d byteCodeLen:%d]", contract.Name, + contract.Version, contract.RuntimeType, len(byteCode)) + return contract.Marshal() +} + +func (r *ContractManagerRuntime) parseParam(parameters map[string][]byte) (string, string, []byte, + commonPb.RuntimeType, error) { + name := string(parameters[syscontract.InitContract_CONTRACT_NAME.String()]) + version := string(parameters[syscontract.InitContract_CONTRACT_VERSION.String()]) + byteCode := parameters[syscontract.InitContract_CONTRACT_BYTECODE.String()] + runtime := parameters[syscontract.InitContract_CONTRACT_RUNTIME_TYPE.String()] + if utils.IsAnyBlank(name, version, byteCode, runtime) { + return "", "", nil, 0, errors.New("params contractName/version/byteCode/runtimeType cannot be empty") + } + runtimeInt := commonPb.RuntimeType_value[string(runtime)] + if runtimeInt == 0 || int(runtimeInt) >= len(commonPb.RuntimeType_value) { + return "", "", nil, 0, errors.New("params runtimeType[" + string(runtime) + "] is error") + } + runtimeType := commonPb.RuntimeType(runtimeInt) + return name, version, byteCode, runtimeType, nil +} + +func (r *ContractManagerRuntime) freezeContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name := string(parameters[syscontract.GetContractInfo_CONTRACT_NAME.String()]) + contract, err := r.FreezeContract(txSimContext, name) + if err != nil { + return nil, err + } + r.log.Infof("freeze contract success[name:%s version:%s runtimeType:%d]", contract.Name, contract.Version, + contract.RuntimeType) + return json.Marshal(contract) +} +func (r *ContractManagerRuntime) unfreezeContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name := string(parameters[syscontract.GetContractInfo_CONTRACT_NAME.String()]) + contract, err := r.UnfreezeContract(txSimContext, name) + if err != nil { + return nil, err + } + r.log.Infof("unfreeze contract success[name:%s version:%s runtimeType:%d]", contract.Name, contract.Version, + contract.RuntimeType) + return json.Marshal(contract) +} +func (r *ContractManagerRuntime) revokeContract(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + []byte, error) { + name := string(parameters[syscontract.GetContractInfo_CONTRACT_NAME.String()]) + contract, err := r.RevokeContract(txSimContext, name) + if err != nil { + return nil, err + } + r.log.Infof("revoke contract success[name:%s version:%s runtimeType:%d]", contract.Name, contract.Version, + contract.RuntimeType) + return json.Marshal(contract) +} + +type ContractManagerRuntime struct { + log protocol.Logger +} + +//GetContractInfo 根据合约名字查询合约的详细信息 +func (r *ContractManagerRuntime) GetContractInfo(context protocol.TxSimContext, name string) (*commonPb.Contract, + error) { + if utils.IsAnyBlank(name) { + err := fmt.Errorf("%s, param[contract_name] of get contract not found", common.ErrParams.Error()) + r.log.Warnf(err.Error()) + return nil, err + } + return context.GetContractByName(name) +} +func (r *ContractManagerRuntime) GetContractByteCode(context protocol.TxSimContext, name string) ([]byte, error) { + if utils.IsAnyBlank(name) { + err := fmt.Errorf("%s, param[contract_name] of get contract not found", common.ErrParams.Error()) + r.log.Warnf(err.Error()) + return nil, err + } + return context.GetContractBytecode(name) +} + +//GetAllContracts 查询所有合约的详细信息 +func (r *ContractManagerRuntime) GetAllContracts(context protocol.TxSimContext) ([]*commonPb.Contract, error) { + keyPre := []byte(utils.PrefixContractInfo) + limitKey := []byte(utils.PrefixContractInfo) + limitKey[len(limitKey)-1] = limitKey[len(limitKey)-1] + 1 + it, err := context.Select(syscontract.SystemContract_CONTRACT_MANAGE.String(), keyPre, limitKey) + if err != nil { + return nil, err + } + defer it.Release() + var result []*commonPb.Contract + for it.Next() { + contract := &commonPb.Contract{} + kv, err := it.Value() + if err != nil { + return nil, err + } + err = contract.Unmarshal(kv.Value) + if err != nil { + return nil, err + } + result = append(result, contract) + } + return result, nil +} + +//InstallContract 安装新合约 +func (r *ContractManagerRuntime) InstallContract(context protocol.TxSimContext, name, version string, byteCode []byte, + runTime commonPb.RuntimeType, initParameters map[string][]byte) (*commonPb.Contract, error) { + if !utils.CheckContractNameFormat(name) { + return nil, errInvalidContractName + } + if runTime == commonPb.RuntimeType_EVM && !utils.CheckEvmAddressFormat(name) { + return nil, errInvalidEvmContractName + } + key := utils.GetContractDbKey(name) + //check name exist + existContract, _ := context.Get(ContractName, key) + if len(existContract) > 0 { //exist + return nil, errContractExist + } + creator := r.getCreator(context) + contract := &commonPb.Contract{ + Name: name, + Version: version, + RuntimeType: runTime, + Status: commonPb.ContractStatus_NORMAL, + Creator: creator, + } + cdata, _ := contract.Marshal() + + err := context.Put(ContractName, key, cdata) + if err != nil { + return nil, err + } + byteCodeKey := utils.GetContractByteCodeDbKey(name) + err = context.Put(ContractName, byteCodeKey, byteCode) + if err != nil { + return nil, err + } + //实例化合约,并init合约,产生读写集 + result, _, statusCode := context.CallContract(contract, protocol.ContractInitMethod, byteCode, initParameters, + 0, commonPb.TxType_INVOKE_CONTRACT) + if statusCode != commonPb.TxStatusCode_SUCCESS { + return nil, fmt.Errorf("%s, %s", errContractInitFail, result.Message) + } + if result.Code > 0 { //throw error + return nil, fmt.Errorf("%s, %s", errContractInitFail, result.Message) + } + if runTime == commonPb.RuntimeType_EVM { + //save bytecode body + //EVM的特殊处理,在调用构造函数后会返回真正需要存的字节码,这里将之前的字节码覆盖 + if len(result.Result) > 0 { + err := context.Put(ContractName, byteCodeKey, result.Result) + if err != nil { + return nil, fmt.Errorf("%s, %s", errContractInitFail, err) + } + } + } + return contract, nil +} + +//UpgradeContract 升级现有合约 +func (r *ContractManagerRuntime) UpgradeContract(context protocol.TxSimContext, name, version string, byteCode []byte, + runTime commonPb.RuntimeType, upgradeParameters map[string][]byte) (*commonPb.Contract, error) { + key := utils.GetContractDbKey(name) + //check name exist + existContract, _ := context.Get(ContractName, key) + if len(existContract) == 0 { //not exist + return nil, errContractNotExist + } + contract := &commonPb.Contract{} + err := contract.Unmarshal(existContract) + if err != nil { + return nil, err + } + if contract.Version == version { + return nil, errContractVersionExist + } + contract.RuntimeType = runTime + contract.Version = version + //update ContractInfo + cdata, _ := contract.Marshal() + err = context.Put(ContractName, key, cdata) + if err != nil { + return nil, err + } + //update Contract Bytecode + byteCodeKey := utils.GetContractByteCodeDbKey(name) + err = context.Put(ContractName, byteCodeKey, byteCode) + if err != nil { + return nil, err + } + //运行新合约的upgrade方法,产生读写集 + result, _, statusCode := context.CallContract(contract, protocol.ContractUpgradeMethod, byteCode, upgradeParameters, + 0, commonPb.TxType_INVOKE_CONTRACT) + if statusCode != commonPb.TxStatusCode_SUCCESS { + return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) + + } + if result.Code > 0 { //throw error + return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, result.Message) + } + if runTime == commonPb.RuntimeType_EVM { + //save bytecode body + //EVM的特殊处理,在调用构造函数后会返回真正需要存的字节码,这里将之前的字节码覆盖 + if len(result.Result) > 0 { + err := context.Put(ContractName, byteCodeKey, result.Result) + if err != nil { + return nil, fmt.Errorf("%s, %s", errContractUpgradeFail, err) + } + } + } + return contract, nil +} +func (r *ContractManagerRuntime) FreezeContract(context protocol.TxSimContext, name string) ( + *commonPb.Contract, error) { + return r.changeContractStatus(context, name, commonPb.ContractStatus_NORMAL, commonPb.ContractStatus_FROZEN) +} +func (r *ContractManagerRuntime) UnfreezeContract(context protocol.TxSimContext, name string) ( + *commonPb.Contract, error) { + return r.changeContractStatus(context, name, commonPb.ContractStatus_FROZEN, commonPb.ContractStatus_NORMAL) +} +func (r *ContractManagerRuntime) RevokeContract(context protocol.TxSimContext, name string) ( + *commonPb.Contract, error) { + if utils.IsAnyBlank(name) { + err := fmt.Errorf("%s, param[contract_name] not found", common.ErrParams.Error()) + r.log.Warnf(err.Error()) + return nil, err + } + contract, err := context.GetContractByName(name) + if err != nil { + return nil, err + } + if contract.Status != commonPb.ContractStatus_NORMAL && contract.Status != commonPb.ContractStatus_FROZEN { + r.log.Warnf("contract[%s] expect status:NORMAL or FROZEN,actual status:%s", + name, contract.Status.String()) + return nil, errContractStatusInvalid + } + contract.Status = commonPb.ContractStatus_REVOKED + key := utils.GetContractDbKey(name) + cdata, _ := contract.Marshal() + err = context.Put(ContractName, key, cdata) + if err != nil { + return nil, err + } + return contract, nil +} + +func (r *ContractManagerRuntime) changeContractStatus(context protocol.TxSimContext, name string, + oldStatus, newStatus commonPb.ContractStatus) (*commonPb.Contract, error) { + if utils.IsAnyBlank(name) { + err := fmt.Errorf("%s, param[contract_name] not found", common.ErrParams.Error()) + r.log.Warnf(err.Error()) + return nil, err + } + contract, err := context.GetContractByName(name) + if err != nil { + return nil, err + } + if contract.Status != oldStatus { + msg := fmt.Sprintf("contract[%s] expect status:%s,actual status:%s", + name, oldStatus.String(), contract.Status.String()) + r.log.Warnf(msg) + return nil, fmt.Errorf("%s, %s", errContractStatusInvalid, msg) + } + contract.Status = newStatus + key := utils.GetContractDbKey(name) + cdata, _ := contract.Marshal() + err = context.Put(ContractName, key, cdata) + if err != nil { + return nil, err + } + return contract, nil +} + +func (r *ContractManagerRuntime) getCreator(context protocol.TxSimContext) *accesscontrol.MemberFull { + sender := context.GetSender() + creator := &accesscontrol.MemberFull{ + OrgId: sender.GetOrgId(), + MemberType: sender.GetMemberType(), + MemberInfo: sender.GetMemberInfo(), + } + return creator +} diff --git a/v210/contractmgr/errors.go b/v210/contractmgr/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..814f0f8644266618e81b5dfe10326fde6153f3b6 --- /dev/null +++ b/v210/contractmgr/errors.go @@ -0,0 +1,21 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package contractmgr210 + +import "errors" + +var ( + errContractExist = errors.New("contract exist") + errContractInitFail = errors.New("contract initial fail") + errContractUpgradeFail = errors.New("contract upgrade fail") + errContractNotExist = errors.New("contract not exist") + errContractVersionExist = errors.New("contract version exist") + errContractStatusInvalid = errors.New("contract status invalid") + errInvalidContractName = errors.New("invalid contract name") + errInvalidEvmContractName = errors.New("invalid EVM contract name") +) diff --git a/v210/dposmgr/dpos_erc20_contract.go b/v210/dposmgr/dpos_erc20_contract.go new file mode 100644 index 0000000000000000000000000000000000000000..ab56c968565cad1d764aa5a31565e39b96744f6f --- /dev/null +++ b/v210/dposmgr/dpos_erc20_contract.go @@ -0,0 +1,697 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package dposmgr210 + +import ( + "encoding/hex" + "fmt" + "strings" + + "chainmaker.org/chainmaker/common/v2/crypto" + "chainmaker.org/chainmaker/common/v2/crypto/hash" + + "chainmaker.org/chainmaker/vm-native/v2/common" + common210 "chainmaker.org/chainmaker/vm-native/v2/v210/common" + + "chainmaker.org/chainmaker/pb-go/v2/accesscontrol" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/utils/v2" + "github.com/mr-tron/base58/base58" +) + +const ( + //DecBase = 10 + + paramNameOwner = "owner" + paramNameFrom = "from" + paramNameTo = "to" + paramNameValue = "value" + + // Balance:map[Account]Value + KeyBalanceFormat = "B/%s" + // map[sender][to]Value + KeyApproveFormat = "A/%s/%s" + // The Key of total Supply + KeyTotalSupply = "TS" + // The Key of Decimals,value:uint32 + KeyDecimals = "DEC" + // The Key of owner for contract,value:string + KeyOwner = "OWN" +) + +var ( + dposErc20ContractName = syscontract.SystemContract_DPOS_ERC20.String() +) + +type DPoSERC20Contract struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewDPoSERC20Contract(log protocol.Logger) *DPoSERC20Contract { + return &DPoSERC20Contract{ + log: log, + methods: registerDPoSERC20ContractMethods(log), + } +} + +func (c *DPoSERC20Contract) GetMethod(methodName string) common.ContractFunc { + return c.methods[methodName] +} + +func registerDPoSERC20ContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + // [DPoS] + dposRuntime := NewDPoSRuntime(log) + methodMap[syscontract.DPoSERC20Function_GET_BALANCEOF.String()] = common210.WrapResultFunc(dposRuntime.BalanceOf) + methodMap[syscontract.DPoSERC20Function_TRANSFER.String()] = common210.WrapResultFunc(dposRuntime.Transfer) + //methodMap[syscontract.DPoSERC20Function_TRANSFER_FROM.String()] = + //common210.WrapResultFunc( dposRuntime.TransferFrom) + //methodMap[syscontract.DPoSERC20Function_GET_ALLOWANCE.String()] = common210.WrapResultFunc( dposRuntime.Allowance) + //methodMap[syscontract.DPoSERC20Function_APPROVE.String()] = common210.WrapResultFunc( dposRuntime.Approve) + methodMap[syscontract.DPoSERC20Function_MINT.String()] = common210.WrapResultFunc(dposRuntime.Mint) + //methodMap[syscontract.DPoSERC20Function_BURN.String()] = common210.WrapResultFunc( dposRuntime.Burn) + //methodMap[syscontract.DPoSERC20Function_TRANSFER_OWNERSHIP.String()] = common210.WrapResultFunc( + //dposRuntime.TransferOwnership) + methodMap[syscontract.DPoSERC20Function_GET_OWNER.String()] = common210.WrapResultFunc(dposRuntime.Owner) + methodMap[syscontract.DPoSERC20Function_GET_DECIMALS.String()] = common210.WrapResultFunc(dposRuntime.Decimals) + methodMap[syscontract.DPoSERC20Function_GET_TOTAL_SUPPLY.String()] = common210.WrapResultFunc(dposRuntime.Total) + return methodMap +} + +// [DPoS] +type DPoSRuntime struct { + log protocol.Logger +} + +// NewDPoSRuntime +func NewDPoSRuntime(log protocol.Logger) *DPoSRuntime { + return &DPoSRuntime{log: log} +} + +// BalanceOf return balance(token) of owner +// params["owner"]:${owner} +// return balance of ${owner} +func (r *DPoSRuntime) BalanceOf(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + owner := string(params[paramNameOwner]) + if owner == "" { + r.log.Errorf("contract[%s] param [%s] is nil", dposErc20ContractName, paramNameOwner) + return nil, common.ErrParams + } + bigInteger, err := balanceOf(txSimContext, owner) + if err != nil { + r.log.Errorf("load balance of owner[%s] error: %s", owner, err.Error()) + return nil, err + } + if bigInteger == nil { + bigInteger = utils.NewZeroBigInteger() + } + return []byte(bigInteger.String()), nil +} + +// Transfer +// It is equal with transfer(to string, value uint64) for ETH +// params["to"]:${to} +// params["value"]:${value} +// return token value of ${sender} after transfer +func (r *DPoSRuntime) Transfer(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + to := string(params[paramNameTo]) + value := string(params[paramNameValue]) + val, err := loadAndCheckValue(value) + if err != nil { + // 转账的值不正确 + r.log.Errorf("contract[%s] param [%s] is illegal", dposErc20ContractName, paramNameValue) + return nil, err + } + // 获取当前用户 + from, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + result, err := transfer(txSimContext, from, to, val) + if err != nil { + r.log.Errorf("transfer from [%s] to [%s] failed: %s", from, to, err.Error()) + } + return result, err +} + +// TransferFrom 交易的发送者,从from的账号中转移指定数目的token给to账户 +// 该操作需要approve,即from已经提前允许当前用户允许转移操作 +// params["from"]:${from} +// params["to"]:${to} +// params["value"]:${value} +// return token value of ${from} after transfer +func (r *DPoSRuntime) TransferFrom(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + from := string(params[paramNameFrom]) + to := string(params[paramNameTo]) + value := string(params[paramNameValue]) + val, err := loadAndCheckValue(value) + if err != nil { + // 转账的值不正确 + r.log.Errorf("contract[%s] param [%s] is illegal", dposErc20ContractName, paramNameValue) + return nil, err + } + // 获取当前用户 + sender, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + // 检查当前用户是否获得授权 + approveVal, err := approveValue(txSimContext, from, sender) + if err != nil { + r.log.Errorf("load approve from[%s] for[%s] failed, %s", from, sender, err.Error()) + return nil, err + } + if approveVal == nil { + r.log.Errorf("load approve from[%s] for[%s] is zero", from, sender) + return nil, fmt.Errorf("load approve from[%s] for[%s] is zero", from, sender) + } + // 判断授权是否满足 + if approveVal.Cmp(val) < 0 { + r.log.Errorf("address approve is not enough, contract[%s] sender[%s] from[%s] approve[%s] value[%s]", + dposErc20ContractName, sender, from, approveVal.String(), val.String()) + return nil, fmt.Errorf("address approve is not enough, contract[%s] sender[%s] from[%s] approve[%s] value[%s]", + dposErc20ContractName, sender, from, approveVal.String(), val.String()) + } + // 将授权值重置,然后进行转账操作 + newApproveVal := utils.Sub(approveVal, val) + err = setApproveValue(txSimContext, from, sender, newApproveVal) + if err != nil { + return nil, err + } + return transfer(txSimContext, from, to, val) +} + +// Approve +// It is equal with approve(spender string, value uint64) error; for ETH +// params["to"]:${to} +// params["value"]:${value} +// return token value for ${sender} to ${to} +func (r *DPoSRuntime) Approve(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + approveTo := string(params[paramNameTo]) + value := string(params[paramNameValue]) + //if approveTo, ok := params[paramNameTo]; ok { + // 判断value是否合法 + //if value, ok := params[paramNameValue]; ok { + val, err := loadAndCheckValue(value) + if err != nil { + // 授权的值不正确 + r.log.Errorf("contract[%s] param [%s] is illegal", dposErc20ContractName, paramNameValue) + return nil, err + } + // 获取当前用户 + from, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + err = setApproveValue(txSimContext, from, approveTo, val) + if err != nil { + return nil, err + } + return []byte(val.String()), nil + //} + // return nil, fmt.Errorf("can not find param, contract[%s] param[%s]", dposErc20ContractName, paramNameValue) + //} + //return nil, fmt.Errorf("can not find param, contract[%s] param[%s]", dposErc20ContractName, paramNameTo) +} + +// Mint 增发 +// params["to"]:${to} +// params["value"]:${value} +// return newest token of ${to} after mint +func (r *DPoSRuntime) Mint(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + mintTo := string(params[paramNameTo]) + value := string(params[paramNameValue]) + //if mintTo, ok := params[paramNameTo]; ok { + // if value, ok := params[paramNameValue]; ok { + val, err := loadAndCheckValue(value) + if err != nil { + // 增发的值不正确 + r.log.Errorf("contract[%s] param [%s] is illegal", dposErc20ContractName, paramNameValue) + return nil, err + } + // 获取当前用户 + from, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + // 当前用户必须是Owner + owner, err := owner(txSimContext) + if err != nil { + r.log.Errorf("load contract[%s] owner failed, err: %s", dposErc20ContractName, err.Error()) + return nil, fmt.Errorf("load contract[%s] owner failed, err: %s", dposErc20ContractName, err.Error()) + } + if !strings.EqualFold(string(owner), from) { + r.log.Errorf("contract[%s]'s owner is not sender, owner[%s] sender[%s]", + dposErc20ContractName, string(owner), from) + return nil, fmt.Errorf("contract[%s]'s owner is not sender, owner[%s] sender[%s]", + dposErc20ContractName, string(owner), from) + } + // 增发即增加具体值和总量 + // 获取总量 + totalSupply, err := totalSupply(txSimContext) + if err != nil { + r.log.Errorf("load contract[%s] total supply failed, err: %s", dposErc20ContractName, err.Error()) + return nil, fmt.Errorf("load contract[%s] total supply failed, err: %s", dposErc20ContractName, err.Error()) + } + if totalSupply == nil { + // 默认设置为0 + totalSupply = utils.NewZeroBigInteger() + } + // 获取增发用户原始的值 + toBalance, err := balanceOf(txSimContext, mintTo) + if err != nil { + r.log.Errorf("load to address balance error, contract[%s] address[%s]", dposErc20ContractName, mintTo) + return nil, fmt.Errorf("load to address balance error, contract[%s] address[%s]", dposErc20ContractName, mintTo) + } + // 重设总量 + newTotalSupply := utils.Sum(totalSupply, val) + // 增发给具体用户 + newToBalance := utils.Sum(toBalance, val) + // 写入到数据库 + err = txSimContext.Put(dposErc20ContractName, []byte(totalSupplyKey()), []byte(newTotalSupply.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + err = txSimContext.Put(dposErc20ContractName, []byte(BalanceKey(mintTo)), []byte(newToBalance.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + // 返回增发后该账户的值 + return []byte(newToBalance.String()), nil + //} + // return nil, fmt.Errorf("can not find param, contract[%s] param[%s]", dposErc20ContractName, paramNameValue) + //} + //return nil, fmt.Errorf("can not find param, contract[%s] param[%s]", dposErc20ContractName, paramNameTo) +} + +// Burn 交易的发送者燃烧一定数量的代币,最多可燃烧殆尽 +// params["value"]:${value} +// return balance of sender after burn +func (r *DPoSRuntime) Burn(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + value := string(params[paramNameValue]) + + //if value, ok := params[paramNameValue]; ok { + val, err := loadAndCheckValue(value) + if err != nil { + // 燃烧的值不正确 + r.log.Errorf("contract[%s] param [%s] is illegal", dposErc20ContractName, paramNameValue) + return nil, err + } + // 获取当前用户 + from, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + // 获取当前用户的token数量 + beforeFromBalance, err := balanceOf(txSimContext, from) + if err != nil { + r.log.Errorf("load address balance error, contract[%s] address[%s]", dposErc20ContractName, from) + return nil, fmt.Errorf("load address balance error, contract[%s] address[%s]", dposErc20ContractName, from) + } + if beforeFromBalance == nil { + r.log.Errorf("load address balance error which is zero, contract[%s] address[%s]", dposErc20ContractName, from) + return nil, fmt.Errorf( + "load address balance error which is zero, contract[%s] address[%s]", + dposErc20ContractName, from) + } + // 处理总量 + beforeTotalSupply, err := totalSupply(txSimContext) + if err != nil { + r.log.Errorf("load contract[%s] total supply failed, err: %s", dposErc20ContractName, err.Error()) + return nil, fmt.Errorf("load contract[%s] total supply failed, err: %s", dposErc20ContractName, err.Error()) + } + // 检查是否会燃烧殆尽 + var afterTotalSupply, afterFromBalance *utils.BigInteger + // 检查总量是否够燃烧 + if beforeTotalSupply.Cmp(val) < 0 { + r.log.Errorf( + "total supply is not enough for burn, before[%s] burn-value[%s]", beforeTotalSupply.String(), val.String()) + return nil, fmt.Errorf( + "total supply is not enough for burn, before[%s] burn-value[%s]", beforeTotalSupply.String(), val.String()) + } + // 计算燃烧后的值 + afterTotalSupply = utils.Sub(beforeTotalSupply, val) + // 检查当前账号总量是否够燃烧 + if beforeFromBalance.Cmp(val) < 0 { + r.log.Errorf( + "address[%s] is not enough for burn, before[%s] burn-value[%s]", + from, beforeTotalSupply.String(), val.String()) + return nil, fmt.Errorf( + "address[%s] is not enough for burn, before[%s] burn-value[%s]", + from, beforeTotalSupply.String(), val.String()) + } + afterFromBalance = utils.Sub(beforeFromBalance, val) + // 重置总量和当前账号的值 + // 写入到数据库 + err = txSimContext.Put(dposErc20ContractName, []byte(totalSupplyKey()), []byte(afterTotalSupply.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + err = txSimContext.Put(dposErc20ContractName, []byte(BalanceKey(from)), []byte(afterFromBalance.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + // 返回燃烧后的值 + return []byte(afterFromBalance.String()), nil + //} + //return nil, fmt.Errorf("can not find param, contract[%s] param[%s]", dposErc20ContractName, paramNameValue) +} + +// TransferOwnership 转移拥有者给其他账户 +// params["to"]:${to} +// return new owner +func (r *DPoSRuntime) TransferOwnership(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + to := string(params[paramNameTo]) + + // 获取当前用户 + from, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + // 当前用户必须是Owner + owner, err := owner(txSimContext) + if err != nil { + r.log.Errorf("load contract[%s] owner failed, err: %s", dposErc20ContractName, err.Error()) + return nil, fmt.Errorf("load contract[%s] owner failed, err: %s", dposErc20ContractName, err.Error()) + } + if !strings.EqualFold(string(owner), from) { + r.log.Errorf("contract[%s]'s owner is not sender, owner[%s] sender[%s]", + dposErc20ContractName, string(owner), from) + return nil, fmt.Errorf("contract[%s]'s owner is not sender, owner[%s] sender[%s]", + dposErc20ContractName, string(owner), from) + } + // 将owner设置魏to + // 返回新的owner + return setOwner(txSimContext, to) +} + +// Allowance +// params["from"]:${from} +// params["to"]:${to} +// return value of approve +func (r *DPoSRuntime) Allowance(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + if params == nil { + return nil, common.ErrParamsEmpty + } + to := string(params[paramNameTo]) + from := string(params[paramNameFrom]) + // 检查是否有from + var fromAddress string + if len(from) != 0 { + fromAddress = from + } else { + // 获取当前用户 + sender, err := loadSenderAddress(txSimContext) + if err != nil { + r.log.Errorf("contract[%s] load sender address failed, %s", dposErc20ContractName, err.Error()) + return nil, err + } + fromAddress = sender + } + return allowance(txSimContext, fromAddress, to) +} + +// Owner +// return owner of DPoS +func (r *DPoSRuntime) Owner(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { + return owner(txSimContext) +} + +// Total +// return total supply of tokens +func (r *DPoSRuntime) Total(txSimContext protocol.TxSimContext, params map[string][]byte) (result []byte, err error) { + total, err := totalSupply(txSimContext) + if err != nil { + return nil, err + } + return []byte(total.String()), nil +} + +// Decimals +// return decimals of DPoS +func (r *DPoSRuntime) Decimals(txSimContext protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + decimalsBytes, err := txSimContext.Get(dposErc20ContractName, []byte(KeyDecimals)) + if err != nil { + r.log.Errorf("load [%s] from cache failed, %s", KeyDecimals, err.Error()) + return nil, err + } + return decimalsBytes, nil +} + +func BalanceKey(account string) string { + return fmt.Sprintf(KeyBalanceFormat, account) +} + +func approveKey(account, to string) string { + return fmt.Sprintf(KeyApproveFormat, account, to) +} + +func totalSupplyKey() string { + return KeyTotalSupply +} + +func setOwner(txSimContext protocol.TxSimContext, owner string) ([]byte, error) { + err := txSimContext.Put(dposErc20ContractName, []byte(KeyOwner), []byte(owner)) + if err != nil { + return nil, err + } + return []byte(owner), nil +} + +func owner(txSimContext protocol.TxSimContext) ([]byte, error) { + owner, err := txSimContext.Get(dposErc20ContractName, []byte(KeyOwner)) + if err != nil { + return nil, err + } + return owner, err +} + +func totalSupply(txSimContext protocol.TxSimContext) (*utils.BigInteger, error) { + totalSupply, err := txSimContext.Get(dposErc20ContractName, []byte(totalSupplyKey())) + if err != nil { + return nil, err + } + return utils.NewBigInteger(string(totalSupply)), nil +} + +func approveValue(txSimContext protocol.TxSimContext, from, to string) (*utils.BigInteger, error) { + approveKey := approveKey(from, to) + valueBytes, err := txSimContext.Get(dposErc20ContractName, []byte(approveKey)) + if err != nil { + return nil, err + } + return utils.NewBigInteger(string(valueBytes)), nil +} + +func allowance(txSimContext protocol.TxSimContext, from, to string) ([]byte, error) { + approveKey := approveKey(from, to) + return txSimContext.Get(dposErc20ContractName, []byte(approveKey)) +} + +func setApproveValue(txSimContext protocol.TxSimContext, from, to string, val *utils.BigInteger) error { + approveKey := approveKey(from, to) + // 无需关注之前的结果,直接更新当前信息即可 + err := txSimContext.Put(dposErc20ContractName, []byte(approveKey), []byte(val.String())) + if err != nil { + return fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + return nil +} + +func loadSenderAddress(txSimContext protocol.TxSimContext) (string, error) { + sender := txSimContext.GetSender() + if sender == nil { + return "", fmt.Errorf("can not find sender from tx, contract[%s]", dposErc20ContractName) + } + // 将sender转换为用户地址 + var ( + err error + pubkey []byte + ) + switch sender.MemberType { + case accesscontrol.MemberType_CERT: + // 长证书 + if pubkey, err = getPubkeyFromCert(sender.MemberInfo); err != nil { + return "", err + } + case accesscontrol.MemberType_CERT_HASH: + var certInfo *commonPb.CertInfo + // 短证书 + memberInfoHex := hex.EncodeToString(sender.MemberInfo) + certInfo, err = getWholeCertInfo(txSimContext, memberInfoHex) + if err != nil { + return "", fmt.Errorf( + "can not load whole cert info , contract[%s] member[%s], reason: %s", + dposErc20ContractName, memberInfoHex, err) + } + if pubkey, err = getPubkeyFromCert(certInfo.Cert); err != nil { + return "", err + } + case accesscontrol.MemberType_PUBLIC_KEY: + pubkey = sender.MemberInfo + default: + return "", fmt.Errorf("invalid member type: %s", sender.MemberType) + } + ac, err := txSimContext.GetAccessControl() + if err != nil { + return "", err + } + return calUserAddr(pubkey, ac.GetHashAlg()) +} + +// parseUserAddress +func getPubkeyFromCert(member []byte) ([]byte, error) { + certificate, err := utils.ParseCert(member) + if err != nil { + return nil, fmt.Errorf("parse cert failed, name[%s] err: %+v", dposErc20ContractName, err) + } + pubKeyBytes, err := certificate.PublicKey.Bytes() + if err != nil { + return nil, fmt.Errorf("load public key from cert failed, name[%s] err: %+v", dposErc20ContractName, err) + } + return pubKeyBytes, nil +} + +func calUserAddr(pubkey []byte, hashType string) (string, error) { + var ( + err error + hashBz []byte + ) + if hashType == crypto.CRYPTO_ALGO_SM3 || hashType == crypto.CRYPTO_ALGO_SHA256 { + if hashBz, err = hash.GetByStrType(hashType, pubkey); err != nil { + return "", err + } + } else { + return "", fmt.Errorf("not support hashAlgo: %s", hashType) + } + addr := base58.Encode(hashBz[:]) + return addr, nil +} + +func getWholeCertInfo(txSimContext protocol.TxSimContext, certHash string) (*commonPb.CertInfo, error) { + certBytes, err := txSimContext.Get(syscontract.SystemContract_CERT_MANAGE.String(), []byte(certHash)) + if err != nil { + return nil, err + } + return &commonPb.CertInfo{ + Hash: certHash, + Cert: certBytes, + }, nil +} + +func balanceOf(txSimContext protocol.TxSimContext, address string) (*utils.BigInteger, error) { + balanceKey := BalanceKey(address) + balanceBytes, err := txSimContext.Get(dposErc20ContractName, []byte(balanceKey)) + if err != nil { + msg := fmt.Errorf("txSimContext get failed, name[%s] key[%s] err: %+v", dposErc20ContractName, balanceKey, err) + return nil, msg + } + if len(balanceBytes) == 0 { + return utils.NewZeroBigInteger(), nil + } + return utils.NewBigInteger(string(balanceBytes)), nil +} + +func loadAndCheckValue(value string) (*utils.BigInteger, error) { + val := utils.NewBigInteger(value) + if val == nil { + // 转账的值不正确 + return nil, fmt.Errorf("param is error, contract[%s] param[%s]", dposErc20ContractName, paramNameValue) + } + if val.Cmp(utils.NewZeroBigInteger()) <= 0 { + // 转账的值不能<=0 + return nil, fmt.Errorf("param is illegal, contract[%s] param[%s]", dposErc20ContractName, paramNameValue) + } + return val, nil +} + +func transfer(txSimContext protocol.TxSimContext, from, to string, val *utils.BigInteger) ([]byte, error) { + // 获取双方的Money + fromBalance, err := balanceOf(txSimContext, from) + if err != nil { + return nil, fmt.Errorf("load from address balance error, contract[%s] address[%s]", dposErc20ContractName, from) + } + if fromBalance == nil { + return nil, fmt.Errorf( + "load from address balance error which is zero, contract[%s] address[%s]", + dposErc20ContractName, from) + } + // 判断其值是否满足 + if fromBalance.Cmp(val) < 0 { + // 账户剩余的钱不满足需求 + return nil, fmt.Errorf( + "address balance is not enough, contract[%s] from address[%s] balance[%s] < value[%s]", + dposErc20ContractName, from, fromBalance.String(), val.String()) + } + toBalance, err := balanceOf(txSimContext, to) + if err != nil { + return nil, fmt.Errorf("load to address balance error, contract[%s] address[%s]", dposErc20ContractName, to) + } + if toBalance == nil { + toBalance = utils.NewZeroBigInteger() + } + // 同一账户转账 + if from == to { + return []byte(fromBalance.String()), nil + } + // 不同账户间转账 + // 记录原始值 + beforeSum := utils.Sum(fromBalance, toBalance) + // 进行转账操作 + afterFromBalance, afterToBalance := utils.Sub(fromBalance, val), utils.Sum(toBalance, val) + // 判断操作后值是否一致 + afterSum := utils.Sum(afterFromBalance, afterToBalance) + if beforeSum.Cmp(afterSum) != 0 { + // 前后值存在问题 + return nil, fmt.Errorf( + "balance is not equal before and after operation, contract[%s] before-balance[%s] after-balance[%s]", + dposErc20ContractName, beforeSum.String(), afterSum.String()) + } + // 一致的情况下更新存储 + fromBalanceKey, toBalanceKey := BalanceKey(from), BalanceKey(to) + err = txSimContext.Put(dposErc20ContractName, []byte(fromBalanceKey), []byte(afterFromBalance.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + err = txSimContext.Put(dposErc20ContractName, []byte(toBalanceKey), []byte(afterToBalance.String())) + if err != nil { + return nil, fmt.Errorf("txSimContext put failed, err: %s", err.Error()) + } + return []byte(afterFromBalance.String()), nil +} diff --git a/v210/dposmgr/dpos_stake_contract.go b/v210/dposmgr/dpos_stake_contract.go new file mode 100644 index 0000000000000000000000000000000000000000..7bd9ab2f388e5542e049ee7722c6194920979365 --- /dev/null +++ b/v210/dposmgr/dpos_stake_contract.go @@ -0,0 +1,1557 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package dposmgr210 + +import ( + "crypto/sha256" + "encoding/binary" + "fmt" + "math" + "math/big" + "sort" + "strconv" + + common210 "chainmaker.org/chainmaker/vm-native/v2/v210/common" + + "chainmaker.org/chainmaker/common/v2/bytehelper" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" + "github.com/gogo/protobuf/proto" + "github.com/mr-tron/base58" +) + +const ( + paramNodeID = "node_id" + paramAddress = "address" + paramTo = "to" + paramFrom = "from" + paramAmount = "amount" + paramEpochID = "epoch_id" + paramValidatorAddress = "validator_address" + paramDelegatorAddress = "delegator_address" + paramMinSelfDelegation = "min_self_delegation" + paramEpochValidatorNumber = "epoch_validator_number" + paramEpochBlockNumber = "epoch_block_number" + + prefixValidator = "V/" + prefixDelegation = "D/" + prefixUnDelegation = "U/" + + KeyNodeIDFormat = "N/%s" + KeyRevNodeFormat = "NR/%s" + KeyValidatorFormat = "V/%s" + KeyDelegationFormat = "D/%s/%s" + KeyEpochFormat = "E/%s" + KeyUnbondingDelegationFormat = "U/%s/%s/%s" + + KeyCurrentEpoch = "CE" + KeyMinSelfDelegation = "MSD" + KeyCompletionUnbondingEpochNumber = "UEN" // 这个 number 不能改动,若改动,会遇到 unbonding entry 数组中 completionEpochID 不同的情况 + KeyEpochValidatorNumber = "EVN" + KeyEpochBlockNumber = "EBN" +) + +// ToValidatorKey - Key: V + "/" + ValidatorAddress +func ToValidatorKey(validatorAddress string) []byte { + return []byte(fmt.Sprintf(KeyValidatorFormat, validatorAddress)) +} + +// ToValidatorPrefix - Key: V + "/" +func ToValidatorPrefix() []byte { + return []byte(fmt.Sprint(prefixValidator)) +} + +// ToDelegationKey - Key: D + "/" + DelegatorAddress + "/" + ValidatorAddress +func ToDelegationKey(delegatorAddress, validatorAddress string) []byte { + return []byte(fmt.Sprintf(KeyDelegationFormat, delegatorAddress, validatorAddress)) +} + +// ToDelegationPrefix - Key: D + "/" + DelegatorAddress +func ToDelegationPrefix(delegatorAddress string) []byte { + return []byte(prefixDelegation + delegatorAddress) +} + +// ToEpochKey - Key:E + "/" + EpochID +func ToEpochKey(epochID string) []byte { + return []byte(fmt.Sprintf(KeyEpochFormat, epochID)) +} + +// ToNodeIDKey - Key:N + "/" + NodeID +func ToNodeIDKey(addr string) []byte { + return []byte(fmt.Sprintf(KeyNodeIDFormat, addr)) +} + +// ToUnbondingDelegationKey - Key:U + "/" + BigEndian(EpochID) + "/" + DelegatorAddress + "/" + ValidatorAddress +func ToUnbondingDelegationKey(epochID uint64, delegatorAddress, validatorAddress string) []byte { + bz := encodeUint64ToBigEndian(epochID) + return []byte(fmt.Sprintf(KeyUnbondingDelegationFormat, bz, delegatorAddress, validatorAddress)) +} + +// ToUnbondingDelegationPrefix - Key:U + "/" + BigEndian(EpochID) +func ToUnbondingDelegationPrefix(epochID uint64) []byte { + bz := encodeUint64ToBigEndian(epochID) + return []byte(prefixUnDelegation + string(bz)) +} + +// ToReverseNodeIDKey - Key:NR + "/" + NodeID +func ToReverseNodeIDKey(nodeID string) []byte { + return []byte(fmt.Sprintf(KeyRevNodeFormat, nodeID)) +} + +// StakeContractAddr - convert stake contract name string to address: base58.Encode(sha256(stake_contract_name)) +func StakeContractAddr() string { + stakeAddrHash := sha256.Sum256([]byte(syscontract.SystemContract_DPOS_STAKE.String())) + stakeAddr := base58.Encode(stakeAddrHash[:]) + return stakeAddr +} + +func newValidator(validatorAddress string) *syscontract.Validator { + return &syscontract.Validator{ + ValidatorAddress: validatorAddress, + Jailed: false, + Status: syscontract.BondStatus_UNBONDED, + Tokens: "0", + DelegatorShares: "0", + UnbondingEpochId: math.MaxInt64, + UnbondingCompletionEpochId: math.MaxInt64, + SelfDelegation: "0", + } +} + +func newDelegation(delegatorAddress, validatorAddress string, shares string) *syscontract.Delegation { + return &syscontract.Delegation{ + DelegatorAddress: delegatorAddress, + ValidatorAddress: validatorAddress, + Shares: shares, + } +} + +func newUnbondingDelegation( + epochID uint64, delegatorAddress, validatorAddress string) *syscontract.UnbondingDelegation { + unbondingDelegationEntry := make([]*syscontract.UnbondingDelegationEntry, 0) + return &syscontract.UnbondingDelegation{ + EpochId: strconv.Itoa(int(epochID)), + DelegatorAddress: delegatorAddress, + ValidatorAddress: validatorAddress, + Entries: unbondingDelegationEntry, + } +} + +func newUnbondingDelegationEntry( + creationEpochID, completionEpochID uint64, amount string) *syscontract.UnbondingDelegationEntry { + return &syscontract.UnbondingDelegationEntry{ + CreationEpochId: creationEpochID, + CompletionEpochId: completionEpochID, + Amount: amount, + } +} + +// main implement here +type DPoSStakeContract struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func (d *DPoSStakeContract) GetMethod(methodName string) common.ContractFunc { + return d.methods[methodName] +} + +func NewDPoSStakeContract(log protocol.Logger) *DPoSStakeContract { + return &DPoSStakeContract{ + log: log, + methods: registerDPoSStakeContractMethods(log), + } +} + +func registerDPoSStakeContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + // implement + stakeRuntime := &DPoSStakeRuntime{log: log} + + methodMap[syscontract.DPoSStakeFunction_GET_ALL_CANDIDATES.String()] = common210.WrapResultFunc( + stakeRuntime.GetAllCandidates) + methodMap[syscontract.DPoSStakeFunction_GET_VALIDATOR_BY_ADDRESS.String()] = common210.WrapResultFunc( + stakeRuntime.GetValidatorByAddress) + methodMap[syscontract.DPoSStakeFunction_DELEGATE.String()] = common210.WrapResultFunc( + stakeRuntime.Delegate) + methodMap[syscontract.DPoSStakeFunction_GET_DELEGATIONS_BY_ADDRESS.String()] = common210.WrapResultFunc( + stakeRuntime.GetDelegationsByAddress) + methodMap[syscontract.DPoSStakeFunction_GET_USER_DELEGATION_BY_VALIDATOR.String()] = common210.WrapResultFunc( + stakeRuntime.GetUserDelegationByValidator) + methodMap[syscontract.DPoSStakeFunction_UNDELEGATE.String()] = common210.WrapResultFunc( + stakeRuntime.UnDelegate) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BY_ID.String()] = common210.WrapResultFunc( + stakeRuntime.ReadEpochByID) + methodMap[syscontract.DPoSStakeFunction_READ_LATEST_EPOCH.String()] = common210.WrapResultFunc( + stakeRuntime.ReadLatestEpoch) + methodMap[syscontract.DPoSStakeFunction_SET_NODE_ID.String()] = common210.WrapResultFunc( + stakeRuntime.SetNodeID) + methodMap[syscontract.DPoSStakeFunction_GET_NODE_ID.String()] = common210.WrapResultFunc( + stakeRuntime.GetNodeID) + methodMap[syscontract.DPoSStakeFunction_READ_MIN_SELF_DELEGATION.String()] = common210.WrapResultFunc( + stakeRuntime.ReadMinSelfDelegation) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_MIN_SELF_DELEGATION.String()] = common210.WrapResultFunc( + //DPoSStakeRuntime.UpdateMinSelfDelegation) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_VALIDATOR_NUMBER.String()] = common210.WrapResultFunc( + stakeRuntime.ReadEpochValidatorNumber) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_VALIDATOR_NUMBER.String()] = common210.WrapResultFunc( + //DPoSStakeRuntime.UpdateEpochValidatorNumber) + methodMap[syscontract.DPoSStakeFunction_READ_EPOCH_BLOCK_NUMBER.String()] = common210.WrapResultFunc( + stakeRuntime.ReadEpochBlockNumber) + methodMap[syscontract.DPoSStakeFunction_READ_SYSTEM_CONTRACT_ADDR.String()] = common210.WrapResultFunc( + stakeRuntime.ReadSystemContractAddr) + //methodMap[syscontract.DPoSStakeFunction_UPDATE_EPOCH_BLOCK_NUMBER.String()] = common210.WrapResultFunc( + //DPoSStakeRuntime.UpdateEpochBlockNumber) + methodMap[syscontract.DPoSStakeFunction_READ_COMPLETE_UNBOUNDING_EPOCH_NUMBER.String()] = common210.WrapResultFunc( + stakeRuntime.ReadCompleteUnBoundingEpochNumber) + return methodMap +} + +type DPoSStakeRuntime struct { + log protocol.Logger +} + +// 新建 stake Runtime +func NewDPoSStakeRuntime(log protocol.Logger) *DPoSStakeRuntime { + return &DPoSStakeRuntime{ + log: log, + } +} + +// SetNodeID - 系统加入节点绑定自身身份 +func (s *DPoSStakeRuntime) SetNodeID(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramNodeID) + if err != nil { + return nil, err + } + nodeID := string(params[paramNodeID]) + // get message sender + sender, err := loadSenderAddress(context) // Use ERC20 parse method + if err != nil { + s.log.Errorf("get sender address error: ", err.Error()) + return nil, err + } + // construct kv pair + // key: N/{sender} V: nodeID + // reverse key: NR/{nodeID} V: sender + reverseKey := ToReverseNodeIDKey(nodeID) + key := ToNodeIDKey(sender) + // check reverseKey, check nodeIDKey is unnecessary + if val, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), reverseKey); err != nil { + s.log.Errorf("query state from context failed, reason: %s", err) + return nil, fmt.Errorf("query state from context failed, reason: %s", err) + } else if len(val) > 0 { + s.log.Errorf("the nodeID:[%s] has been set by [%s]", nodeID, val) + return nil, fmt.Errorf("the nodeID:[%s] has been set by [%s]", nodeID, val) + } + // save to context + if err := context.Put(syscontract.SystemContract_DPOS_STAKE.String(), key, []byte(nodeID)); err != nil { + s.log.Errorf("context put key: [%s], value: [&s] error, error: ", key, nodeID, err) + return nil, err + } + if err := context.Put(syscontract.SystemContract_DPOS_STAKE.String(), reverseKey, []byte(sender)); err != nil { + s.log.Errorf("context put key: [%s], value: [&s] error, error: ", reverseKey, sender, err) + return nil, err + } + return []byte(nodeID), nil +} + +// GetNodeID - 系统节点自身身份查询 +func (s *DPoSStakeRuntime) GetNodeID(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramAddress) + if err != nil { + return nil, err + } + address := string(params[paramAddress]) + // construct kv pair + // key: N/{sender} V: nodeID + key := ToNodeIDKey(address) + // check reverseKey, check nodeIDKey is unnecessary + if val, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), key); err != nil { + s.log.Errorf("query nodeID from context failed, error: %s", err) + return nil, fmt.Errorf("query nodeID from context failed, error: %s", err) + } else if len(val) <= 0 { + s.log.Errorf("[%s] the address's nodeID has not been set", address) + return nil, fmt.Errorf("[%s] the address's nodeID has not been set", address) + } else { + return val, nil + } +} + +// GetAllValidator() []ValidatorAddress // 返回所有满足最低抵押条件验证人候选人 +// return ValidatorVector +func (s *DPoSStakeRuntime) GetAllCandidates(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + collection, err := s.getAllCandidates(context) + if err != nil { + s.log.Errorf("get validator collection error: %s", err) + return nil, err + } + // 序列化 + bz, err := proto.Marshal(collection) + if err != nil { + s.log.Errorf("marshal validator collection error: ", err.Error()) + return nil, err + } + return bz, nil +} + +func (s *DPoSStakeRuntime) getAllCandidates(context protocol.TxSimContext) (*syscontract.ValidatorVector, error) { + // 获取验证人数据 + vc, err := getAllValidatorByPrefix(context, ToValidatorPrefix()) + if err != nil { + s.log.Error("get validator address error") + return nil, err + } + + // 过滤 + collection := &syscontract.ValidatorVector{} + for _, v := range vc { + if v == nil { + s.log.Errorf("validator is nil", v) + continue + } + cmp, err := compareMinSelfDelegation(context, v.SelfDelegation) + if err != nil { + s.log.Errorf("compare min self delegation error, amount: %s", v.SelfDelegation) + return nil, fmt.Errorf( + "convert self delegate string to integer error, amount: %s, err: %s", + v.SelfDelegation, err.Error()) + } + if v.Jailed || cmp == -1 || v.Status != syscontract.BondStatus_BONDED { + continue + } + collection.Vector = append(collection.Vector, v.ValidatorAddress) + } + return collection, nil +} + +// GetValidatorByAddress() Validator // 返回所有满足最低抵押条件验证人 +// @params["address"] +// return Validator +func (s *DPoSStakeRuntime) GetValidatorByAddress( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramAddress) + if err != nil { + return nil, err + } + + address := string(params[paramAddress]) + // 获取验证人数据 + bz, err := getValidatorBytes(context, address) + if err != nil { + s.log.Errorf("get validator error, address: %s", address) + return nil, err + } + return bz, nil +} + +// * Delegate(to string, amount string) (delegation, error) // 创建抵押,更新验证人,如果MsgSender是给自己,即给自己抵押,则创建验证人 +// @params["to"] 抵押的目标验证人 +// @params["amount"] 抵押数量,乘上erc20合约 decimal 的结果值,比如用户认知的1USD,系统内是 1 * 10 ^ 18 +// return Delegation +func (s *DPoSStakeRuntime) Delegate(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramTo, paramAmount) + if err != nil { + return nil, err + } + + to := string(params[paramTo]) // delegate target + amount := string(params[paramAmount]) // amount must be a integer + + // check amount + if !assertStringAmountOverZero(amount) { + s.log.Errorf("amount is less than or equal to 0") + return nil, fmt.Errorf("amount is less than or equal to 0") + } + // 解析交易发送方地址 + from, err := loadSenderAddress(context) // Use ERC20 parse method + if err != nil { + s.log.Errorf("get sender address error: ", err.Error()) + return nil, err + } + + // 查看 validator 是否存在 + v, err := getOrCreateValidator(context, from, to) + if err != nil { + s.log.Errorf("get or create validator error: ", err.Error()) + return nil, err + } + + // 获取或者创建 Delegation + d, err := getOrCreateDelegation(context, from, to) + if err != nil { + s.log.Errorf("get or create delegation error: ", err.Error()) + return nil, err + } + + // 计算抵押获得的 share + shares, err := calcShareByAmount(v.Tokens, v.DelegatorShares, amount) + if err != nil { + s.log.Errorf("calculate share by amount error: ", err.Error()) + return nil, err + } + + // 更新 delegation 的 share + err = updateDelegateShares(d, shares) + if err != nil { + s.log.Errorf("update delegate share error", err.Error()) + return nil, err + } + + // 更新 validator + err = updateValidatorShares(v, shares) + if err != nil { + s.log.Errorf("update shares error: ", err.Error()) + return nil, err + } + err = updateValidatorTokens(v, amount) + if err != nil { + s.log.Errorf("update tokens error: ", err.Error()) + return nil, err + } + var cmp int + if from == to { + err = updateValidatorSelfDelegate(v, amount) + if err != nil { + s.log.Errorf("update self delegate error: ", err.Error()) + return nil, err + } + cmp, err = compareMinSelfDelegation(context, v.SelfDelegation) + if err != nil { + s.log.Errorf("compare min self delegation error: ", err.Error()) + return nil, err + } + if v.Status != syscontract.BondStatus_BONDED && cmp >= 0 { + updateValidatorStatus(v, syscontract.BondStatus_BONDED) + } else if v.Status != syscontract.BondStatus_BONDED && cmp == -1 { + updateValidatorStatus(v, syscontract.BondStatus_UNBONDING) + } + } + + // 跨合约转账 + // 获取 runtime 对象 + erc20RunTime := NewDPoSRuntime(s.log) + // stake 地址 + stakeAddr := StakeContractAddr() + // prepare params + transferParams := map[string][]byte{ + paramNameTo: []byte(stakeAddr), + paramNameValue: []byte(amount), + } + _, err = erc20RunTime.Transfer(context, transferParams) + if err != nil { + s.log.Errorf("cross call contract ERC20, method transfer error: ", err.Error()) + return nil, err + } + + // 写入存储 + err = save(context, ToDelegationKey(from, to), d) + if err != nil { + s.log.Errorf("save delegate error: ", err.Error()) + return nil, err + } + err = save(context, ToValidatorKey(to), v) + if err != nil { + s.log.Errorf("save validator error: ", err.Error()) + return nil, err + } + + // return Delegate info + return proto.Marshal(d) +} + +// GetDelegationsByAddress() []Delegation // 返回所有 Delegation +// @params["address"] +// return DelegationInfo +func (s *DPoSStakeRuntime) GetDelegationsByAddress( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramAddress) + if err != nil { + return nil, err + } + + address := string(params[paramAddress]) + // 获取验证人数据 + di, err := getDelegationsByAddress(context, address) + if err != nil { + s.log.Errorf("get delegation of address [%s] error, error: %s", address, err.Error()) + return nil, err + } + return proto.Marshal(di) +} + +// GetUserDelegationByValidator() Delegation // 返回所有 Delegation +// @params["validator_address"] +// return Delegation +func (s *DPoSStakeRuntime) GetUserDelegationByValidator( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramDelegatorAddress, paramValidatorAddress) + if err != nil { + return nil, err + } + + delegatorAddress := string(params[paramDelegatorAddress]) + validatorAddress := string(params[paramValidatorAddress]) + + // 获取验证人数据 + bz, err := getDelegationBytes(context, delegatorAddress, validatorAddress) + if err != nil { + s.log.Errorf("get delegation of address [%s] error, error: %s", validatorAddress, err.Error()) + return nil, err + } + return bz, nil +} + +// Undelegation(from string, amount string) bool // 解除抵押,更新验证人 +// @params["from"] 解质押的验证人 +// @params["amount"] 解质押数量,1 * 10 ^ 18 +// return UnbondingDelegation +func (s *DPoSStakeRuntime) UnDelegate(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramFrom, paramAmount) + if err != nil { + return nil, err + } + + // get params + undelegateValidatorAddress := string(params[paramFrom]) + amount := string(params[paramAmount]) + + // check amount + if !assertStringAmountPositive(amount) { + s.log.Errorf("amount is less than 0") + return nil, fmt.Errorf("amount is less than 0") + } + // read epoch + epoch, err := s.readEpoch(context) + if err != nil { + s.log.Errorf("undelegate unmarshal latest epoch error") + return nil, err + } + // parse sender + sender, err := loadSenderAddress(context) // Use ERC20 parse method + if err != nil { + s.log.Errorf("get sender address error: ", err.Error()) + return nil, err + } + // check epoch undelegate amount + shares, err := s.checkEpochUnDelegateAmount(context, sender, undelegateValidatorAddress, amount) + if err != nil { + s.log.Errorf("check epoch undelegate amount error: ", err.Error()) + return nil, err + } + // get completion epochID + epochNum, err := getUnbondingEpochNumber(context) + if err != nil { + s.log.Errorf("get completion epoch error: ", err.Error()) + return nil, err + } + completeEpoch := epochNum + epoch.EpochId + // new entry + entry := newUnbondingDelegationEntry(epoch.EpochId, completeEpoch, amount) + // update delegation + ud, err := getOrCreateUnbondingDelegation(context, completeEpoch, sender, undelegateValidatorAddress) + if err != nil { + s.log.Errorf("get or create unbonding delegation error: ", err.Error()) + return nil, err + } + ud.Entries = append(ud.Entries, entry) + + // update validator and delegation + v, d, err := s.updateValidatorAndDelegationByUndelegate(context, sender, undelegateValidatorAddress, amount, shares) + if err != nil { + s.log.Errorf("update validator and delegation error: ", err.Error()) + return nil, err + } + // save + err = save(context, ToUnbondingDelegationKey(completeEpoch, sender, undelegateValidatorAddress), ud) + if err != nil { + s.log.Errorf("save unbonding delegation error: ", err.Error()) + return nil, err + } + err = save(context, ToValidatorKey(undelegateValidatorAddress), v) + if err != nil { + s.log.Errorf("save validator error: ", err.Error()) + return nil, err + } + if d.Shares == "0" { + err = del(context, ToDelegationKey(sender, undelegateValidatorAddress)) + if err != nil { + s.log.Errorf("delete delegation error: ", err.Error()) + return nil, err + } + } else { + err = save(context, ToDelegationKey(sender, undelegateValidatorAddress), d) + if err != nil { + s.log.Errorf("save delegation error: ", err.Error()) + return nil, err + } + } + + return proto.Marshal(ud) +} + +func (s *DPoSStakeRuntime) canDelete(context protocol.TxSimContext, undelegateValidatorAddress string) error { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochValidatorNumber)) + if err != nil { + return err + } + amount := decodeUint64FromBigEndian(bz) + + collection, err := s.getAllCandidates(context) + if err != nil { + return err + } + var contains bool + for _, validator := range collection.Vector { + if validator == undelegateValidatorAddress { + contains = true + } + } + // 如果共识中 当前节点为共识节点 并且 退出后剩余节点数量 少于 共识所需的节点数量 + if amount > uint64(len(collection.Vector)-1) && contains { + return fmt.Errorf("the number of candidates[%d] after the undelegate "+ + "is less than the number of validators[%d]", len(collection.Vector)-1, amount) + } + return nil +} + +// ReadEpochByID() []ValidatorAddress // 读取当前世代数据 +// return Epoch +func (s *DPoSStakeRuntime) ReadLatestEpoch(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyCurrentEpoch)) + if err != nil { + return nil, err + } + return bz, nil +} + +// ReadEpochByID() []ValidatorAddress // 读取指定ID的世代数据 +// @params["epoch_id"] 查询的世代ID +// return Epoch +func (s *DPoSStakeRuntime) ReadEpochByID(context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramEpochID) + if err != nil { + return nil, err + } + + epochID := string(params[paramEpochID]) + if !assertStringAmountPositive(epochID) { + s.log.Errorf("epoch_id less than 0") + return nil, fmt.Errorf("epoch_id less than 0") + } + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), ToEpochKey(epochID)) + if err != nil { + return nil, err + } + return bz, nil +} + +// ReadMinSelfDelegation() string // 读取验证人最少抵押token数量 +// return string +func (s *DPoSStakeRuntime) ReadMinSelfDelegation( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // get data + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyMinSelfDelegation)) + if err != nil { + return nil, err + } + return bz, nil +} + +// 更新验证人最少抵押token数量,当提高最少抵押门槛时,原先的 validator 状态不会更新,validator 需要尽块增加抵押 +// UpdateMinSelfDelegation() string +// @params["min_self_delegation"] +// return string +func (s *DPoSStakeRuntime) UpdateMinSelfDelegation( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramMinSelfDelegation) + if err != nil { + return nil, err + } + + minSelfDelegation := string(params[paramMinSelfDelegation]) + if !assertStringAmountPositive(minSelfDelegation) { + s.log.Errorf("minSelfDelegation less than 0") + return nil, fmt.Errorf("minSelfDelegation less than 0") + } + + // check sender and owner + err = s.checkSenderAndOwner(context) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + + // check minSelfDelegation over range + isOverRange, allowSelfDelegation, err := s.checkMinSelfDelegationOverRange(context, minSelfDelegation) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + if isOverRange { + return []byte(allowSelfDelegation), fmt.Errorf( + "min self delegation change over range, biggest self delegation is: [%s]", allowSelfDelegation) + } + // put data + err = context.Put( + syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyMinSelfDelegation), []byte(minSelfDelegation)) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + return []byte(minSelfDelegation), nil +} + +// ReadEpochValidatorNumber() string // 读取每个世代验证人数量 +// return string +func (s *DPoSStakeRuntime) ReadEpochValidatorNumber( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // get data + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochValidatorNumber)) + if err != nil { + return nil, err + } + amount := decodeUint64FromBigEndian(bz) + return []byte(strconv.Itoa(int(amount))), nil +} + +// 更新每个世代验证人数量,不能大于当前所有验证人数量 +// UpdateEpochValidatorNumber() string +// @params["epoch_validator_number"] +// return string +func (s *DPoSStakeRuntime) UpdateEpochValidatorNumber( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramEpochValidatorNumber) + if err != nil { + return nil, err + } + + epochValidatorNumber := string(params[paramEpochValidatorNumber]) + if !assertStringAmountPositive(epochValidatorNumber) { + s.log.Errorf("epochValidatorNumber less than 0") + return nil, fmt.Errorf("epochValidatorNumber less than 0") + } + + // check sender and owner + err = s.checkSenderAndOwner(context) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + // convert int string to int + amount, err := strconv.Atoi(epochValidatorNumber) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + // check all validator candidates number + err = s.checkNewValidatorNumberOverRange(context, amount) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + // big endian encode + bigEndianAmount := encodeUint64ToBigEndian(uint64(amount)) + // put data + err = context.Put(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochValidatorNumber), bigEndianAmount) + if err != nil { + return nil, err + } + return []byte(epochValidatorNumber), nil +} + +// ReadEpochBlockNumber() string // 读取世代的出块数量 +// return string +func (s *DPoSStakeRuntime) ReadEpochBlockNumber( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // get data + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochBlockNumber)) + if err != nil { + return nil, err + } + amount := decodeUint64FromBigEndian(bz) + return []byte(strconv.Itoa(int(amount))), nil +} + +// ReadSystemContractAddr() string // 读取stake系统合约的地址 +// return string +func (s *DPoSStakeRuntime) ReadSystemContractAddr( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // get data + addr := StakeContractAddr() + return []byte(addr), nil +} + +// ReadEpochBlockNumber() string // 读取世代的出块数量 +// return string +func (s *DPoSStakeRuntime) ReadCompleteUnBoundingEpochNumber( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // get data + num, err := getUnbondingEpochNumber(context) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf("%d", num)), nil +} + +// UpdateEpochBlockNumber() bool // 更新世代的出块数量 +// @params["epoch_block_number"] +// return nil +func (s *DPoSStakeRuntime) UpdateEpochBlockNumber( + context protocol.TxSimContext, params map[string][]byte) ([]byte, error) { + // check params + err := checkParams(params, paramEpochBlockNumber) + if err != nil { + return nil, err + } + + epochBlockNumber := string(params[paramEpochBlockNumber]) + if !assertStringAmountOverZero(epochBlockNumber) { + s.log.Errorf("epochBlockNumber less than or equal to 0") + return nil, fmt.Errorf("epochBlockNumber less than or equal to 0") + } + + // check sender and owner + err = s.checkSenderAndOwner(context) + if err != nil { + s.log.Errorf(err.Error()) + return nil, err + } + + // convert int string to int + amount, err := strconv.Atoi(epochBlockNumber) + if err != nil { + return nil, err + } + // big endian encode + bigEndianAmount := encodeUint64ToBigEndian(uint64(amount)) + // put data + err = context.Put(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyEpochBlockNumber), bigEndianAmount) + if err != nil { + return nil, err + } + + return []byte(epochBlockNumber), nil +} + +// 获取或创建 validator +func getOrCreateValidator( + context protocol.TxSimContext, delegatorAddress, validatorAddress string) (*syscontract.Validator, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), ToValidatorKey(validatorAddress)) + if err != nil { + return nil, err + } + v := &syscontract.Validator{} + if len(bz) > 0 { + err := proto.Unmarshal(bz, v) + if err != nil { + return nil, err + } + if delegatorAddress == validatorAddress { + return v, nil + } + if v.Status != syscontract.BondStatus_BONDED || v.Jailed { + return nil, fmt.Errorf("validator in wrong status, jailed: %v, status: %s", v.Jailed, v.Status) + } + return v, nil + } + // 新建 validator 判断 + if delegatorAddress != validatorAddress { + // 如果是新建 validator, 抵押人被抵押人必须是同一个人 + return nil, fmt.Errorf("no such validator: %s", validatorAddress) + } + key := ToNodeIDKey(validatorAddress) + if bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), key); err != nil || len(bz) == 0 { + return nil, fmt.Errorf("not set validator nodeID, you should first set nodeID with validator") + } + v = newValidator(validatorAddress) + return v, nil +} + +// 返回 validator 字节数据 +func getValidatorBytes(context protocol.TxSimContext, validatorAddress string) ([]byte, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), ToValidatorKey(validatorAddress)) + if err != nil { + return nil, err + } + if len(bz) <= 0 { + return nil, fmt.Errorf("no such validator as address: %s", validatorAddress) + } + return bz, nil +} + +// 返回 validator 对象 +func getValidator(context protocol.TxSimContext, validatorAddress string) (*syscontract.Validator, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), ToValidatorKey(validatorAddress)) + if err != nil { + return nil, err + } + if len(bz) <= 0 { + return nil, fmt.Errorf("no susch validator as address: %s", validatorAddress) + } + v := &syscontract.Validator{} + err = proto.Unmarshal(bz, v) + if err != nil { + return nil, err + } + return v, nil +} + +// 更新 validator shares 字段 +func updateValidatorShares(validator *syscontract.Validator, shares *big.Int) error { + validatorSharesValue, err := stringToBigInt(validator.DelegatorShares) + if err != nil { + return err + } + total := &big.Int{} + total.Add(shares, validatorSharesValue) + if total.Cmp(big.NewInt(0)) == -1 { + return fmt.Errorf("share update result less than 0") + } + validator.DelegatorShares = total.String() + return nil +} + +// 更新 validator tokens 字段 +func updateValidatorTokens(validator *syscontract.Validator, amount string) error { + tokensValue, err := stringToBigInt(validator.Tokens) + if err != nil { + return err + } + amountValue, err := stringToBigInt(amount) + if err != nil { + return err + } + + total := &big.Int{} + total.Add(amountValue, tokensValue) + if total.Cmp(big.NewInt(0)) == -1 { + return fmt.Errorf("token update result less than 0") + } + validator.Tokens = total.String() + return nil +} + +// 更新 validator selfDelegation 字段 +func updateValidatorSelfDelegate(validator *syscontract.Validator, amount string) error { + selfDelegationValue, err := stringToBigInt(validator.SelfDelegation) + if err != nil { + return err + } + amountValue, err := stringToBigInt(amount) + if err != nil { + return err + } + + total := &big.Int{} + total.Add(amountValue, selfDelegationValue) + if total.Cmp(big.NewInt(0)) == -1 { + return fmt.Errorf("self delegation update result less than 0") + } + validator.SelfDelegation = total.String() + return nil +} + +// 更新 valudator status 字段 +func updateValidatorStatus(validator *syscontract.Validator, status syscontract.BondStatus) { + validator.Status = status +} + +func (s *DPoSStakeRuntime) updateValidatorAndDelegationByUndelegate( + context protocol.TxSimContext, sender, undelegateValidatorAddress, amount string, shares *big.Int, +) (*syscontract.Validator, *syscontract.Delegation, error) { + v, err := getValidator(context, undelegateValidatorAddress) + if err != nil { + s.log.Errorf("get validator [%s] error: ", undelegateValidatorAddress, err.Error()) + return nil, nil, err + } + negShare := &big.Int{} + negShare.Mul(shares, big.NewInt(-1)) + err = updateValidatorShares(v, negShare) + if err != nil { + s.log.Errorf("update validator [%s] share error: ", undelegateValidatorAddress, err.Error()) + return nil, nil, err + } + err = updateValidatorTokens(v, "-"+amount) + if err != nil { + s.log.Errorf("update validator [%s] tokens error: ", undelegateValidatorAddress, err.Error()) + return nil, nil, err + } + // 如果是 验证人自身 解除抵押 + var cmp int + if sender == undelegateValidatorAddress { + err = updateValidatorSelfDelegate(v, "-"+amount) + if err != nil { + s.log.Errorf( + "update validator [%s] self delegation error: ", undelegateValidatorAddress, err.Error()) + return nil, nil, err + } + // compare self delegation + cmp, err = compareMinSelfDelegation(context, v.SelfDelegation) + if err != nil { + s.log.Errorf("compare min self delegation error: ", err.Error()) + return nil, nil, err + } + if cmp == -1 { + // 检查当前网络情况下,节点是否能退出 + if err = s.canDelete(context, undelegateValidatorAddress); err != nil { + return nil, nil, err + } + + if v.SelfDelegation == "0" { + updateValidatorStatus(v, syscontract.BondStatus_UNBONDED) + } else { + updateValidatorStatus(v, syscontract.BondStatus_UNBONDING) + } + } + } + + // update delegation + d, err := getDelegation(context, sender, undelegateValidatorAddress) + if err != nil { + s.log.Errorf("get delegation error: ", err.Error()) + return nil, nil, err + } + err = updateDelegateShares(d, negShare) + if err != nil { + s.log.Errorf("update delegate shares error: ", err.Error()) + return nil, nil, err + } + return v, d, nil +} + +// 根据 amount 计算 share +func calcShareByAmount(tokens string, shares string, amount string) (*big.Int, error) { + // 将 amount 转换成 int + var err error + tokensValue, err := stringToBigInt(tokens) + if err != nil { + return nil, err + } + sharesValue, err := stringToBigInt(shares) + if err != nil { + return nil, err + } + amountValue, err := stringToBigInt(amount) + if err != nil { + return nil, err + } + + // 计算 amount 对应的 share 数量 + newShare := &big.Int{} + if tokensValue.Cmp(big.NewInt(0)) == 0 && sharesValue.Cmp(big.NewInt(0)) == 0 { + newShare = amountValue + } else if tokensValue.Cmp(big.NewInt(0)) == 1 { + // 计算 shares 的数量, new_shares = shares * amount / tokens + x := newShare.Mul(sharesValue, amountValue) + newShare = x.Div(x, tokensValue) + //percentage := decimal.NewFromBigInt(amountValue, 0).Div(decimal.NewFromBigInt(tokensValue, 0)) + //newShare = percentage.Mul(decimal.NewFromBigInt(sharesValue, 0)).BigInt() + } else if tokensValue.Cmp(big.NewInt(0)) == -1 { + return nil, fmt.Errorf("validator's token amount is less than 0, token amount: %s", tokensValue.String()) + } + return newShare, nil +} + +//// 根据 share 计算 amount +//func calcAmountByShare(tokens string, shares string, share string) (*big.Int, error) { +// // 将 amount 转换成 int +// var err error +// tokensValue, err := stringToBigInt(tokens) +// if err != nil { +// return nil, err +// } +// sharesValue, err := stringToBigInt(shares) +// if err != nil { +// return nil, err +// } +// shareValue, err := stringToBigInt(share) +// if err != nil { +// return nil, err +// } +// +// // 计算 share 对应的 amount 数量 +// newAmount := &big.Int{} +// if sharesValue.Cmp(big.NewInt(0)) < 1 { +// return nil, fmt.Errorf("shares less or equal to 0") +// } +// // 计算 amount 的数量, amount = share / shares * tokens +// y := newAmount.Mul(sharesValue, tokensValue) +// newAmount = y.Div(shareValue, y) +// return newAmount, nil +//} + +// 获取或创建 delegation +func getOrCreateDelegation( + context protocol.TxSimContext, delegatorAddress, validatorAddress string) (*syscontract.Delegation, error) { + bz, err := context.Get( + syscontract.SystemContract_DPOS_STAKE.String(), ToDelegationKey(delegatorAddress, validatorAddress)) + if err != nil { + return nil, err + } + d := &syscontract.Delegation{} + if len(bz) > 0 { + err = proto.Unmarshal(bz, d) + if err != nil { + return nil, err + } + } else { + d = newDelegation(delegatorAddress, validatorAddress, "0") + } + return d, nil +} + +// 获取或创建 delegation +func getDelegationsByAddress( + context protocol.TxSimContext, delegatorAddress string) (*syscontract.DelegationInfo, error) { + // 获取地址所有抵押数据 + start, limit := bytehelper.BytesPrefix(ToDelegationPrefix(delegatorAddress)) + // TODO search scope has no memory data + iter, err := context.Select(syscontract.SystemContract_DPOS_STAKE.String(), start, limit) + if err != nil { + return nil, err + } + defer iter.Release() + + delegationVector := make([]*syscontract.Delegation, 0) + for iter.Next() { + kv, err := iter.Value() + if err != nil { + return nil, err + } + d := &syscontract.Delegation{} + err = proto.Unmarshal(kv.GetValue(), d) + if err != nil { + return nil, err + } + delegationVector = append(delegationVector, d) + } + + if len(delegationVector) == 0 { + return nil, fmt.Errorf("address: [%s] has no delegation", delegatorAddress) + } + + di := &syscontract.DelegationInfo{} + di.Infos = delegationVector + + return di, nil +} + +// 返回 delegation 信息 +func getDelegation( + context protocol.TxSimContext, delegatorAddress, validatorAddress string) (*syscontract.Delegation, error) { + bz, err := context.Get( + syscontract.SystemContract_DPOS_STAKE.String(), ToDelegationKey(delegatorAddress, validatorAddress)) + if err != nil { + return nil, err + } + d := &syscontract.Delegation{} + if len(bz) > 0 { + err = proto.Unmarshal(bz, d) + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf( + "no such delegation, delegatorAddress: [%s], validatorAddress: [%s]", delegatorAddress, validatorAddress) + } + return d, nil +} + +// 返回 delegation 字节数据 +func getDelegationBytes(context protocol.TxSimContext, delegatorAddress, validatorAddress string) ([]byte, error) { + bz, err := context.Get( + syscontract.SystemContract_DPOS_STAKE.String(), ToDelegationKey(delegatorAddress, validatorAddress)) + if err != nil { + return nil, err + } + if len(bz) <= 0 { + return nil, fmt.Errorf( + "no delegation as delegator: %s, validdator: %s", delegatorAddress, validatorAddress) + } + return bz, nil +} + +// 更新 delegate share 字段 +func updateDelegateShares(delegate *syscontract.Delegation, shares *big.Int) error { + sharesValue, err := stringToBigInt(delegate.Shares) + if err != nil { + return err + } + total := &big.Int{} + total.Add(shares, sharesValue) + if total.Cmp(big.NewInt(0)) == -1 { + return fmt.Errorf("delegate share update result less than 0") + } + delegate.Shares = total.String() + return nil +} + +// 获取或创建 unbonding delegation +func getOrCreateUnbondingDelegation( + context protocol.TxSimContext, epochID uint64, delegatorAddress, validatorAddress string, +) (*syscontract.UnbondingDelegation, error) { + bz, err := context.Get( + syscontract.SystemContract_DPOS_STAKE.String(), + ToUnbondingDelegationKey(epochID, delegatorAddress, validatorAddress)) + if err != nil { + return nil, err + } + ud := &syscontract.UnbondingDelegation{} + if len(bz) > 0 { + err = proto.Unmarshal(bz, ud) + if err != nil { + return nil, err + } + } else { + ud = newUnbondingDelegation(epochID, delegatorAddress, validatorAddress) + } + return ud, nil +} + +//// 获取 unbonding delegation +//func getUnbondingDelegation( +// context protocol.TxSimContext, epochID uint64, delegatorAddress, validatorAddress string, +// ) (*syscontract.UnbondingDelegation, error) { +// bz, err := context.Get( +// syscontract.SystemContract_DPOS_STAKE.String(), +// ToUnbondingDelegationKey(epochID, delegatorAddress, validatorAddress)) +// if err != nil { +// return nil, err +// } +// ud := &syscontract.UnbondingDelegation{} +// if len(bz) > 0 { +// err = proto.Unmarshal(bz, ud) +// if err != nil { +// return nil, err +// } +// } else { +// return nil, fmt.Errorf( +// "no such unbonding delegation, epochID: [%d], delegatorAddress: [%s],validatorAddress: [%s]", +// epochID, delegatorAddress, validatorAddress) +// } +// return ud, nil +//} + +// 检查 当前 epoch 总的 undelegation 数量 +func (s *DPoSStakeRuntime) checkEpochUnDelegateAmount( + context protocol.TxSimContext, delegatorAddress string, validatorAddress string, amount string) (*big.Int, error) { + // get delegate + d, err := getDelegation(context, delegatorAddress, validatorAddress) + if err != nil { + s.log.Errorf( + "get delegation error, delegationAddress: [%s], validatorAddress: [%s]", + delegatorAddress, validatorAddress) + return nil, err + } + // get validator + v, err := getValidator(context, validatorAddress) + if err != nil { + s.log.Errorf("get validator error, validatorAddress: [%s]", validatorAddress) + return nil, err + } + // calc share by amount + shareAmount, err := calcShareByAmount(v.Tokens, v.DelegatorShares, amount) + if err != nil { + s.log.Errorf("calculate share by amount error: ", err) + return nil, err + } + // convert share string to big int + delegateShareValue, err := stringToBigInt(d.Shares) + if err != nil { + s.log.Errorf("convert delegate share string to big int error: ", err) + return nil, err + } + if delegateShareValue.Cmp(shareAmount) == -1 { + return nil, fmt.Errorf("delegate less than undelegate amount") + } + return shareAmount, nil +} + +// 获取 erc20 合约的所有人 +func (s *DPoSStakeRuntime) getERC20ContractOwner(context protocol.TxSimContext) (string, error) { + // 跨合约转账 + // 获取 runtime 对象 + erc20RunTime := NewDPoSRuntime(s.log) + + bz, err := erc20RunTime.Owner(context, nil) + if err != nil { + s.log.Errorf("cross call contract ERC20, method owner error: ", err.Error()) + return "", err + } + return string(bz), nil +} + +// 检查消息发送人和erc20token的权限拥有者是否一致 +func (s *DPoSStakeRuntime) checkSenderAndOwner(context protocol.TxSimContext) error { + // get message sender + sender, err := loadSenderAddress(context) // Use ERC20 parse method + if err != nil { + s.log.Errorf("get sender address error: ", err.Error()) + return err + } + owner, err := s.getERC20ContractOwner(context) + if err != nil { + s.log.Errorf("get erc20 owner address error: ", err.Error()) + return err + } + if sender != owner { + s.log.Errorf("only erc20 contract owner is access to this method, sender: [%s], owner: [%s]", sender, owner) + return fmt.Errorf("only erc20 contract owner is access to this method, sender: [%s], owner: [%s]", sender, owner) + } + return nil +} + +func (s *DPoSStakeRuntime) checkMinSelfDelegationOverRange( + context protocol.TxSimContext, amount string) (bool, string, error) { + // convert int string to big int + amountValue, err := stringToBigInt(amount) + if err != nil { + return false, "", err + } + + // get all validator + vc, err := getAllValidatorByPrefix(context, ToValidatorPrefix()) + if err != nil { + return false, "", nil + } + + // 按照 SelfDelegation 排序 + c := make(Collections, 0) + for _, v := range vc { + if v == nil { + s.log.Errorf("validator is nil", v) + continue + } + c = append(c, v.SelfDelegation) + } + sort.Sort(c) + + // read epoch validator number + numBytes, err := s.ReadEpochValidatorNumber(context, nil) + if err != nil { + return false, "", err + } + n, err := strconv.Atoi(string(numBytes)) + if err != nil { + return false, "", err + } + if n <= 0 { + return false, "", fmt.Errorf("validator number is 0") + } + + // 顺位验证人个数的 self delegate 数量 + value, err := stringToBigInt(c[n-1]) + if err != nil { + return false, "", err + } + if amountValue.Cmp(value) <= 0 { + return false, value.String(), nil + } + return true, value.String(), nil +} + +func (s *DPoSStakeRuntime) checkNewValidatorNumberOverRange(context protocol.TxSimContext, amount int) error { + // get all candidates + bz, err := s.GetAllCandidates(context, nil) + if err != nil { + return err + } + // unmarshal + vc := &syscontract.ValidatorVector{} + err = proto.Unmarshal(bz, vc) + if err != nil { + return err + } + if amount > len(vc.Vector) { + return fmt.Errorf("new validator amount is over range, current all candidates number is: [%d]", len(vc.Vector)) + } + return nil +} + +func (s *DPoSStakeRuntime) readEpoch(context protocol.TxSimContext) (*syscontract.Epoch, error) { + bz, err := s.ReadLatestEpoch(context, nil) + if err != nil { + s.log.Errorf("undelegate read latest epoch error") + return nil, err + } + // read epoch + epoch := &syscontract.Epoch{} + err = proto.Unmarshal(bz, epoch) + if err != nil { + s.log.Errorf("undelegate unmarshal latest epoch error") + return nil, err + } + return epoch, nil +} + +// 返回所有验证人 +func getAllValidatorByPrefix(context protocol.TxSimContext, prefix []byte) ([]*syscontract.Validator, error) { + // 获取所有验证人数据 + start, limit := bytehelper.BytesPrefix(prefix) + iter, err := context.Select(syscontract.SystemContract_DPOS_STAKE.String(), start, limit) + if err != nil { + return nil, err + } + defer iter.Release() + validatorVector := make([]*syscontract.Validator, 0) + for iter.Next() { + kv, err := iter.Value() + if err != nil { + return nil, err + } + v := &syscontract.Validator{} + err = proto.Unmarshal(kv.GetValue(), v) + if err != nil { + return nil, err + } + validatorVector = append(validatorVector, v) + } + + return validatorVector, nil +} + +// 返回 unstake 完成需要的 epoch 数 +func getUnbondingEpochNumber(context protocol.TxSimContext) (uint64, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyCompletionUnbondingEpochNumber)) + if err != nil { + return 0, err + } + return binary.BigEndian.Uint64(bz), nil +} + +// 获得最少抵押数量的基础配置 +func getMinSelfDelegation(context protocol.TxSimContext) (*big.Int, error) { + bz, err := context.Get(syscontract.SystemContract_DPOS_STAKE.String(), []byte(KeyMinSelfDelegation)) + if err != nil { + return nil, err + } + m, ok := big.NewInt(0).SetString(string(bz), 10) + if !ok { + return nil, fmt.Errorf("invalid minSelfDelegation in stakeContract config") + } + return m, nil +} + +// 保存 message 对象 +func save(context protocol.TxSimContext, key []byte, m proto.Message) error { + bz, err := proto.Marshal(m) + if err != nil { + return err + } + err = context.Put(syscontract.SystemContract_DPOS_STAKE.String(), key, bz) + if err != nil { + return err + } + return nil +} + +// 删除 key +func del(context protocol.TxSimContext, key []byte) error { + err := context.Del(syscontract.SystemContract_DPOS_STAKE.String(), key) + if err != nil { + return err + } + return nil +} + +// 将 数字字符串 转换为 big.Int +func stringToBigInt(amount string) (*big.Int, error) { + v := &big.Int{} + v, ok := v.SetString(amount, 10) // only support 10 count base number + if !ok { + return nil, fmt.Errorf("convert amount to big int error: %s", amount) + } + return v, nil +} + +// 检查入参 +func checkParams(params map[string][]byte, keys ...string) error { + if params == nil { + return fmt.Errorf("params is nil") + } + for _, key := range keys { + if _, ok := params[key]; !ok { + return fmt.Errorf("params has no such key: [%s]", key) + } + } + return nil +} + +// selfDelegation > minSelfDelegation : 1 +// selfDelegation == minSelfDelegation : 0 +// selfDelegation < minSelfDelegation : -1 +func compareMinSelfDelegation(context protocol.TxSimContext, selfDelegation string) (int, error) { + minSelfDelegation, err := getMinSelfDelegation(context) + if err != nil { + return 0, err + } + selfDelegationValue, err := stringToBigInt(selfDelegation) + if err != nil { + return 0, err + } + return selfDelegationValue.Cmp(minSelfDelegation), nil +} + +// check amount params +// amount >= 0 return true else false +func assertStringAmountPositive(amount string) bool { + amountValue, err := stringToBigInt(amount) + if err != nil { + return false + } + return amountValue.Cmp(big.NewInt(0)) >= 0 +} + +// amount > 0 return true else false +func assertStringAmountOverZero(amount string) bool { + amountValue, err := stringToBigInt(amount) + if err != nil { + return false + } + return amountValue.Cmp(big.NewInt(0)) > 0 +} + +func encodeUint64ToBigEndian(amount uint64) []byte { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, amount) + return bz +} + +func decodeUint64FromBigEndian(bz []byte) uint64 { + return binary.BigEndian.Uint64(bz) +} + +// SelfDelegation array for sort +type Collections []string + +func (s Collections) Len() int { + return len(s) +} + +func (s Collections) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Collections) Less(i, j int) bool { + x, _ := stringToBigInt(s[i]) + y, _ := stringToBigInt(s[j]) + val := x.Cmp(y) + return val > 0 +} diff --git a/v210/multisign/multi_sign_contract.go b/v210/multisign/multi_sign_contract.go new file mode 100644 index 0000000000000000000000000000000000000000..72f008f90be3a61524f26805e4b56fb4808eb295 --- /dev/null +++ b/v210/multisign/multi_sign_contract.go @@ -0,0 +1,293 @@ +/* + * Copyright (C) BABEC. All rights reserved. + * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package multisign210 + +import ( + "errors" + "fmt" + + commonPb "chainmaker.org/chainmaker/pb-go/v2/common" + "chainmaker.org/chainmaker/pb-go/v2/syscontract" + "chainmaker.org/chainmaker/protocol/v2" + "chainmaker.org/chainmaker/utils/v2" + "chainmaker.org/chainmaker/vm-native/v2/common" + common210 "chainmaker.org/chainmaker/vm-native/v2/v210/common" + "github.com/gogo/protobuf/proto" +) + +var ( + contractName = syscontract.SystemContract_MULTI_SIGN.String() +) + +type MultiSignContract struct { + methods map[string]common.ContractFunc + log protocol.Logger +} + +func NewMultiSignContract(log protocol.Logger) *MultiSignContract { + return &MultiSignContract{ + log: log, + methods: InitMultiContractMethods(log), + } +} +func (c *MultiSignContract) GetMethod(methodName string) common.ContractFunc { + return c.methods[methodName] +} + +func InitMultiContractMethods(log protocol.Logger) map[string]common.ContractFunc { + methodMap := make(map[string]common.ContractFunc, 64) + runtime := &MultiSignRuntime{log: log} + methodMap[syscontract.MultiSignFunction_REQ.String()] = common210.WrapResultFunc(runtime.Req) + methodMap[syscontract.MultiSignFunction_VOTE.String()] = common210.WrapResultFunc(runtime.Vote) + methodMap[syscontract.MultiSignFunction_QUERY.String()] = common210.WrapResultFunc(runtime.Query) + return methodMap +} + +type MultiSignRuntime struct { + log protocol.Logger +} + +// Req request to multi sign +func (r *MultiSignRuntime) Req(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + result []byte, err error) { + // 1、校验并获取参数 + sysContractName := parameters[syscontract.MultiReq_SYS_CONTRACT_NAME.String()] + sysMethod := parameters[syscontract.MultiReq_SYS_METHOD.String()] + r.log.Infof("multi sign req start. ContractName[%s] Method[%s]", sysContractName, sysMethod) + if utils.IsAnyBlank(sysContractName, sysMethod) { + err = fmt.Errorf("multi req params verify fail. sysContractName/sysMethod cannot be empty") + return nil, err + } + + // 构建多签对象并记录 + tx := txSimContext.GetTx() + multiSignInfo := &syscontract.MultiSignInfo{ + Payload: tx.Payload, + ContractName: string(sysContractName), + Method: string(sysMethod), + Status: syscontract.MultiSignStatus_PROCESSING, + VoteInfos: nil, + } + + for _, endorser := range tx.Endorsers { + multiSignInfo.VoteInfos = append(multiSignInfo.VoteInfos, &syscontract.MultiSignVoteInfo{ + Vote: syscontract.VoteStatus_AGREE, + Endorsement: endorser, // 签名在接收交易时已被验证 + }) + } + + multiSignInfoBytes, _ := multiSignInfo.Marshal() + err = txSimContext.Put(contractName, []byte(tx.Payload.TxId), multiSignInfoBytes) + if err != nil { + r.log.Warn(err) + return nil, err + } + + r.log.Infof("multi sign req end") + return []byte(tx.Payload.TxId), nil +} + +func (r *MultiSignRuntime) Vote(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + result []byte, err error) { + // 1、检查参数 + // 2、获取历史投票记录 + // 3、判断是否继续可以对该多签交易投票 + // 4、根据传入参数的状态修改多签结果 + // 5、根据结果调用accessControl校验是否认证成功 + voteInfoBytes := parameters[syscontract.MultiVote_VOTE_INFO.String()] + txId := parameters[syscontract.MultiVote_TX_ID.String()] + r.log.Infof("multi sign vote start. MultiVote_TX_ID[%s]", txId) + if utils.IsAnyBlank(voteInfoBytes, txId) { + err = fmt.Errorf("multi vote params verify fail. voteInfo/txId cannot be empty") + r.log.Warn(err) + return nil, err + } + multiSignInfoBytes, err := txSimContext.Get(contractName, txId) + if err != nil { + r.log.Warn(err) + return nil, err + } + if multiSignInfoBytes == nil { + return nil, fmt.Errorf("not found tx id from db %s", txId) + } + + multiSignInfo := &syscontract.MultiSignInfo{} + err = proto.Unmarshal(multiSignInfoBytes, multiSignInfo) + if err != nil { + r.log.Warn(err) + return nil, err + } + // 校验:该多签是否已完成投票 + reqVoteInfo := &syscontract.MultiSignVoteInfo{} + err = proto.Unmarshal(voteInfoBytes, reqVoteInfo) + if err != nil { + r.log.Warn(err) + return nil, err + } + + ac, err := txSimContext.GetAccessControl() + if err != nil { + r.log.Warn(err) + return nil, err + } + // 校验:该用户是否已投票 + err = r.verifyMemberVote(ac, reqVoteInfo, multiSignInfo, txId) + if err != nil { + r.log.Warn(err) + return nil, err + } + + mPayloadByte, _ := multiSignInfo.Payload.Marshal() + resourceName := multiSignInfo.ContractName + "-" + multiSignInfo.Method + // 校验当前签名 + principal, err := ac.CreatePrincipal(resourceName, []*commonPb.EndorsementEntry{reqVoteInfo.Endorsement}, + mPayloadByte) + if err != nil { + r.log.Warn(err) + return nil, err + } + endorsement, err := ac.GetValidEndorsements(principal) + if err != nil { + r.log.Warn(err) + return nil, err + } + if len(endorsement) == 0 { + err = fmt.Errorf("the multi sign vote signature[org:%s] is err, error:%s", + reqVoteInfo.Endorsement.Signer.OrgId, err) + r.log.Error(err) + return nil, err + } + multiSignInfo.VoteInfos = append(multiSignInfo.VoteInfos, reqVoteInfo) + var ( + contractResultBytes []byte + contractErr error + ) + // 校验多签签名 + endorsers := make([]*commonPb.EndorsementEntry, 0) + for _, info := range multiSignInfo.VoteInfos { + endorsers = append(endorsers, info.Endorsement) + } + principal1, err := ac.CreatePrincipal(resourceName, endorsers, mPayloadByte) + if err != nil { + r.log.Warn(err) + return nil, err + } + endorsement1, err := ac.GetValidEndorsements(principal1) //problem + if err != nil { + r.log.Warn(err) + return nil, err + } + if len(endorsement1) == 0 { + err = fmt.Errorf("the multi vote is err, error: %s", err.Error()) + r.log.Warn(err) + return nil, err + } + multiSignVerify, err := ac.VerifyPrincipal(principal1) + if err != nil { + r.log.Warn("multi sign vote verify fail.", err) + } + + if multiSignVerify { + r.log.Info("multi sign vote verify success.") + contractResultBytes, contractErr = r.invokeContract(txSimContext, multiSignInfo) + } + + // 7、记录状态 + multiSignInfoBytes, err = multiSignInfo.Marshal() + if err != nil { + r.log.Error(err) + return nil, err + } + err = txSimContext.Put(contractName, txId, multiSignInfoBytes) + if err != nil { + r.log.Error(err) + return nil, err + } + // return must not nil + if len(contractResultBytes) == 0 { + contractResultBytes = []byte("vote success") + } + r.log.Infof("multi sign vote[%s] end", txId) + return contractResultBytes, contractErr +} + +func (r *MultiSignRuntime) verifyMemberVote(ac protocol.AccessControlProvider, + reqVoteInfo *syscontract.MultiSignVoteInfo, multiSignInfo *syscontract.MultiSignInfo, txId []byte) error { + if multiSignInfo.Status != syscontract.MultiSignStatus_PROCESSING { + err := fmt.Errorf("the multi sign[%s] has been completed", txId) + r.log.Warn(err) + return err + } + signer, err := ac.NewMember(reqVoteInfo.Endorsement.Signer) + if err != nil { + r.log.Warn(err) + return err + } + signerUid := signer.GetUid() + for _, info := range multiSignInfo.VoteInfos { + signed, _ := ac.NewMember(info.Endorsement.Signer) + if signerUid == signed.GetUid() { + err = fmt.Errorf("the signer[org:%s] is voted", signed.GetUid()) + r.log.Warn(err) + return err + } + } + return nil +} + +func (r *MultiSignRuntime) invokeContract(txSimContext protocol.TxSimContext, + multiSignInfo *syscontract.MultiSignInfo) (contractResultBytes []byte, contractErr error) { + txId := txSimContext.GetTx().Payload.TxId + contract := &commonPb.Contract{ + Name: multiSignInfo.ContractName, + RuntimeType: commonPb.RuntimeType_NATIVE, // multi sign only support native contract + Status: commonPb.ContractStatus_NORMAL, + Creator: nil, + } + + initParam := make(map[string][]byte) + for _, parameter := range multiSignInfo.Payload.Parameters { + // is sysContractName or sysMethod continue + if parameter.Key == syscontract.MultiReq_SYS_CONTRACT_NAME.String() || + parameter.Key == syscontract.MultiReq_SYS_METHOD.String() { + continue + } + initParam[parameter.Key] = parameter.Value + } + byteCode := initParam[syscontract.InitContract_CONTRACT_BYTECODE.String()] + contractResult, _, statusCode := txSimContext.CallContract(contract, multiSignInfo.Method, byteCode, + initParam, 0, commonPb.TxType_INVOKE_CONTRACT) + if statusCode == commonPb.TxStatusCode_SUCCESS { + contractResultBytes = contractResult.Result + multiSignInfo.Status = syscontract.MultiSignStatus_ADOPTED + r.log.Infof("multi sign vote[%s] finished, result: %s", txId, contractResultBytes) + } else { + contractErr = errors.New(contractResult.Message) + multiSignInfo.Status = syscontract.MultiSignStatus_FAILED + r.log.Warnf("multi sign vote[%s] failed, msg: %s", txId, contractErr) + } + return contractResultBytes, contractErr +} + +func (r *MultiSignRuntime) Query(txSimContext protocol.TxSimContext, parameters map[string][]byte) ( + result []byte, err error) { + // 1、校验并获取参数 + txId := parameters[syscontract.MultiVote_TX_ID.String()] + if utils.IsAnyBlank(txId) { + err = fmt.Errorf("multi sign query params verify fail. txId cannot be empty") + return nil, err + } + + multiSignInfoDB, err := txSimContext.Get(contractName, txId) + if err != nil { + r.log.Error(err) + return nil, err + } + + return multiSignInfoDB, nil +}