Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Optimize judge for address (fix#378) #392

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions bcs/contract/evm/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,14 @@ func EVMAddressToContractAccountWithoutPrefixAndSuffix(evmAddr crypto.Address) (
return contractNameStrWithPrefix[4:], nil
}

// determine whether it is a contract account
func DetermineContractAccount(account string) bool {
if utils.IsAccount(account) != 1 {
return false
}
return strings.Index(account, "@") != -1
// IsContractAccount returns true for a contract account
func IsContractAccount(account string) bool {
zhugelianglongming marked this conversation as resolved.
Show resolved Hide resolved
return utils.IsAccount(account) && strings.Contains(account, "@")
}

// determine whether it is a contract name
func DetermineContractName(contractName string) error {
return contract.ValidContractName(contractName)
// IsContractName determine whether it is a contract name
func IsContractName(contractName string) bool {
return contract.ValidContractName(contractName) == nil
}

// determine whether it is a contract name
Expand Down Expand Up @@ -162,10 +159,10 @@ func DetermineXchainAddress(xAddr string) (string, string, error) {
var addr crypto.Address
var addrType string
var err error
if DetermineContractAccount(xAddr) {
if IsContractAccount(xAddr) {
addr, err = ContractAccountToEVMAddress(xAddr)
addrType = contractAccountType
} else if DetermineContractName(xAddr) == nil {
} else if IsContractName(xAddr) {
addr, err = ContractNameToEVMAddress(xAddr)
addrType = contractNameType
} else {
Expand Down
8 changes: 4 additions & 4 deletions bcs/contract/evm/creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type evmCreator struct {
vm *evm.EVM
}

func newEvmCreator(config *bridge.InstanceCreatorConfig) (bridge.InstanceCreator, error) {
func newEvmCreator(_ *bridge.InstanceCreatorConfig) (bridge.InstanceCreator, error) {
opt := evm.Options{}
vm := evm.New(opt)
return &evmCreator{
Expand All @@ -53,7 +53,7 @@ func (e *evmCreator) CreateInstance(ctx *bridge.Context, cp bridge.ContractCodeP
}, nil
}

func (e *evmCreator) RemoveCache(name string) {
func (e *evmCreator) RemoveCache(_ string) {
}

type evmInstance struct {
Expand Down Expand Up @@ -102,7 +102,7 @@ func (e *evmInstance) Exec() error {
}

var caller crypto.Address
if DetermineContractAccount(e.state.ctx.Initiator) {
if IsContractAccount(e.state.ctx.Initiator) {
caller, err = ContractAccountToEVMAddress(e.state.ctx.Initiator)
} else {
caller, err = XchainToEVMAddress(e.state.ctx.Initiator)
Expand Down Expand Up @@ -242,7 +242,7 @@ func unpackEventFromAbi(abiByte []byte, contractName string, log *exec.LogEvent)
func (e *evmInstance) deployContract() error {
var caller crypto.Address
var err error
if DetermineContractAccount(e.state.ctx.Initiator) {
if IsContractAccount(e.state.ctx.Initiator) {
caller, err = ContractAccountToEVMAddress(e.state.ctx.Initiator)
} else {
caller, err = XchainToEVMAddress(e.state.ctx.Initiator)
Expand Down
32 changes: 17 additions & 15 deletions bcs/ledger/xledger/state/tx_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,20 @@ func (t *State) verifySignatures(tx *pb.Transaction, digestHash []byte) (bool, m
}

// verify initiator
akType := aclu.IsAccount(tx.Initiator)
if akType == 0 {
akType, isValid := aclu.ParseAddressType(tx.Initiator)
if !isValid {
t.log.Warn("verifySignatures failed, invalid address", "address", tx.Initiator)
return false, nil, ErrInvalidSignature
}
if akType == aclu.AddressAK {
// check initiator address signature
ok, err := aclu.IdentifyAK(tx.Initiator, tx.InitiatorSigns[0], digestHash)
if err != nil || !ok {
t.log.Warn("verifySignatures failed", "address", tx.Initiator, "error", err)
return false, nil, err
}
verifiedAddr[tx.Initiator] = true
} else if akType == 1 {
} else if akType == aclu.AddressAccount {
initiatorAddr := make([]string, 0)
// check initiator account signatures
for _, sign := range tx.InitiatorSigns {
Expand Down Expand Up @@ -264,9 +268,6 @@ func (t *State) verifySignatures(tx *pb.Transaction, digestHash []byte) (bool, m
"account", tx.Initiator, "error", err)
return false, nil, err
}
} else {
t.log.Warn("verifySignatures failed, invalid address", "address", tx.Initiator)
return false, nil, ErrInvalidSignature
}

// verify authRequire
Expand Down Expand Up @@ -353,9 +354,9 @@ func (t *State) verifyUTXOPermission(tx *pb.Transaction, verifiedID map[string]b
for _, txInput := range tx.TxInputs {
// if transfer from contract
addr := txInput.GetFromAddr()
txid := txInput.GetRefTxid()
txID := txInput.GetRefTxid()
offset := txInput.GetRefOffset()
utxoKey := utxo.GenUtxoKey(addr, txid, offset)
utxoKey := utxo.GenUtxoKey(addr, txID, offset)
if conUtxoInputsMap[utxoKey] {
// this utxo transfer from contract, will verify in rwset verify
continue
Expand All @@ -366,8 +367,12 @@ func (t *State) verifyUTXOPermission(tx *pb.Transaction, verifiedID map[string]b
// this ID(either AK or Account) is verified before
continue
}
akType := aclu.IsAccount(name)
if akType == 1 {
akType, isValid := aclu.ParseAddressType(name)
if !isValid {
t.log.Warn("verifyUTXOPermission error, Invalid account/address name", "name", name)
return false, ErrInvalidAccount
}
if akType == aclu.AddressAccount {
// Identify account
acl, err := t.queryAccountACL(name)
if err != nil || acl == nil {
Expand All @@ -379,13 +384,10 @@ func (t *State) verifyUTXOPermission(tx *pb.Transaction, verifiedID map[string]b
t.log.Warn("verifyUTXOPermission error, failed to IdentifyAccount", "error", err)
return false, ErrACLNotEnough
}
} else if akType == 0 {
} else if akType == aclu.AddressAK {
// Identify address failed, if address not in verifiedID then it must have no signature
t.log.Warn("verifyUTXOPermission error, address has no signature", "address", name)
return false, ErrInvalidSignature
} else {
t.log.Warn("verifyUTXOPermission error, Invalid account/address name", "name", name)
return false, ErrInvalidAccount
}
verifiedID[name] = true
}
Expand Down Expand Up @@ -830,7 +832,7 @@ func (t *State) checkRelyOnMarkedTxid(reftxid []byte, blockid []byte) (bool, boo
func (t *State) removeDuplicateUser(initiator string, authRequire []string) []string {
dupCheck := make(map[string]bool)
finalUsers := make([]string, 0)
if aclu.IsAccount(initiator) == 0 {
if aclu.IsAK(initiator) {
finalUsers = append(finalUsers, initiator)
dupCheck[initiator] = true
}
Expand Down
4 changes: 2 additions & 2 deletions bcs/ledger/xledger/state/utxo/utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ func (uv *UtxoVM) SetModifyBlockAddr(addr string) {
// GetAccountContracts get account contracts, return a slice of contract names
func (uv *UtxoVM) GetAccountContracts(account string) ([]string, error) {
contracts := []string{}
if aclu.IsAccount(account) != 1 {
if !aclu.IsAccount(account) {
uv.log.Warn("GetAccountContracts valid account name error", "error", "account name is not valid")
return nil, errors.New("account name is not valid")
}
Expand Down Expand Up @@ -698,7 +698,7 @@ func (uv *UtxoVM) QueryUtxoRecord(accountName string, displayCount int64) (*pb.U

func (uv *UtxoVM) QueryAccountContainAK(address string) ([]string, error) {
accounts := []string{}
if aclu.IsAccount(address) != 0 {
if !aclu.IsAK(address) {
return accounts, errors.New("address is not valid")
}
prefixKey := pb.ExtUtxoTablePrefix + aclu.GetAK2AccountBucket() + "/" + address
Expand Down
35 changes: 18 additions & 17 deletions kernel/contract/bridge/xbridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ func New(cfg *XBridgeConfig) (*XBridge, error) {
return xbridge, nil
}

func (v *XBridge) initVM() error {
func (b *XBridge) initVM() error {
types := []ContractType{TypeWasm, TypeNative, TypeEvm, TypeKernel}
for _, tp := range types {
vmconfig, ok := v.vmconfigs[tp]
vmconfig, ok := b.vmconfigs[tp]
if !ok {
// log.Error("config for contract type not found", "type", tp)
continue
Expand All @@ -76,24 +76,24 @@ func (v *XBridge) initVM() error {
continue
}
creatorConfig := &InstanceCreatorConfig{
Basedir: filepath.Join(v.basedir, vmconfig.DriverName()),
SyscallService: v.syscallService,
Basedir: filepath.Join(b.basedir, vmconfig.DriverName()),
SyscallService: b.syscallService,
VMConfig: vmconfig,
}
creator, err := Open(tp, vmconfig.DriverName(), creatorConfig)
if err != nil {
return err
}
v.creators[tp] = creator
b.creators[tp] = creator
}
return nil
}

func (v *XBridge) getCreator(tp ContractType) InstanceCreator {
return v.creators[tp]
func (b *XBridge) getCreator(tp ContractType) InstanceCreator {
return b.creators[tp]
}

func (v *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context, error) {
func (b *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context, error) {
var desc *protos.WasmCodeDesc
var err error

Expand All @@ -112,13 +112,13 @@ func (v *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context,
if err != nil {
return nil, err
}
vm := v.getCreator(tp)
vm := b.getCreator(tp)
if vm == nil {
return nil, fmt.Errorf("vm for contract type %s not supported", tp)
}
var cp ContractCodeProvider

ctx := v.ctxmgr.MakeContext()
ctx := b.ctxmgr.MakeContext()

// 1. 如果当前在部署合约,合约代码从sandbox中获取
// 2. 合约调用的情况则从model中拿取合约代码,避免交易中包含合约代码的引用
Expand All @@ -129,10 +129,10 @@ func (v *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context,
ctx.ReadFromCache = false
cp = newCodeProviderWithCache(ctxCfg.State)
} else {
cp = newDescProvider(v.codeProvider, desc)
cp = newDescProvider(b.codeProvider, desc)
}
ctx.State = ctxCfg.State
ctx.Core = v.core
ctx.Core = b.core
ctx.Module = ctxCfg.Module
ctx.ContractName = ctxCfg.ContractName
ctx.Initiator = ctxCfg.Initiator
Expand All @@ -148,10 +148,11 @@ func (v *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context,
}
// lifecycle of debug logger driver is coincident with bridge
// while ctx.Logger's coincident with context
if v.debugLogger != nil {
ctx.Logger = v.debugLogger
if b.debugLogger != nil {
ctx.Logger = b.debugLogger
} else {
// use contract Name for convience of filter log from specific contract using grep or other logging processing stack
// use contract name for convenience of filter specific contract from logs
// by grep or other logging processing stack
ctx.Logger, err = logs.NewLogger(fmt.Sprintf("%016d", ctx.ID), "contract")
}
ctx.ChainName = ctxCfg.ChainName
Expand All @@ -160,11 +161,11 @@ func (v *XBridge) NewContext(ctxCfg *contract.ContextConfig) (contract.Context,
return nil, err
}
release := func() {
v.ctxmgr.DestroyContext(ctx)
b.ctxmgr.DestroyContext(ctx)
}
instance, err := vm.CreateInstance(ctx, cp)
if err != nil {
v.ctxmgr.DestroyContext(ctx)
b.ctxmgr.DestroyContext(ctx)
return nil, err
}
ctx.Instance = instance
Expand Down
19 changes: 10 additions & 9 deletions kernel/contract/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ const (
)

// ValidContractName return error when contractName is not a valid contract name.
func ValidContractName(contractName string) error {
// param absence check
// contract naming rule check
contractSize := len(contractName)
contractMaxSize := contractNameMaxSize
contractMinSize := contractNameMinSize
if contractSize > contractMaxSize || contractSize < contractMinSize {
return fmt.Errorf("contract name length expect [%d~%d], actual: %d", contractMinSize, contractMaxSize, contractSize)
func ValidContractName(name string) error {

// check name size
nameSize := len(name)
if nameSize > contractNameMaxSize || nameSize < contractNameMinSize {
return fmt.Errorf("contract name length expect [%d~%d], actual: %d",
contractNameMinSize, contractNameMaxSize, nameSize)
}
if !contractNameRegex.MatchString(contractName) {

// check name pattern
if !contractNameRegex.MatchString(name) {
return fmt.Errorf("contract name does not fit the rule of contract name")
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion kernel/permission/acl/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (t *KernMethod) NewAccount(ctx contract.KContext) (*contract.Response, erro
return nil, fmt.Errorf("Invoke NewAccount failed, warn: account name is empty")
}
accountStr := string(accountName)
if validErr := utils.ValidRawAccount(accountStr); validErr != nil {
if validErr := utils.ValidAccountNumber(accountStr); validErr != nil {
return nil, validErr
}

Expand Down
76 changes: 76 additions & 0 deletions kernel/permission/acl/utils/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package utils

import (
"fmt"
"strings"
)

type AddressType int

const (
AddressAK AddressType = iota
AddressAccount
)

// ParseAddressType returns address type when address is valid
// A valid address is not empty which is AK or Account.
// A valid Account pattern is `<AccountPrefix><AccountNumber>[@<BlockChainName>]`
func ParseAddressType(address string) (addressType AddressType, isValid bool) {
if address == "" {
// invalid address
return
}
isValid = true
addressType = AddressAK

// check if address matches account
// check account prefix
if !strings.HasPrefix(address, GetAccountPrefix()) {
return
}
// check account number
number := strings.Split(address, GetAccountBcNameSep())[0]
number = number[len(GetAccountPrefix()):]
if err := ValidAccountNumber(number); err != nil {
return
}

addressType = AddressAccount
return
}

// IsAccount returns true for a valid account
func IsAccount(address string) bool {
t, isValid := ParseAddressType(address)
return isValid && t == AddressAccount
}

// IsAK returns true for a valid AK
func IsAK(address string) bool {
t, isValid := ParseAddressType(address)
return isValid && t == AddressAK
}

// ValidAccountNumber validate account number
// a valid account number pattern is `[0-9]{16}`
func ValidAccountNumber(number string) error {
// param absence check
if number == "" {
return fmt.Errorf("invoke NewAccount failed, account number is empty")
}

// check number size
if len(number) != GetAccountNumberSize() {
return fmt.Errorf("invoke NewAccount failed, account number length expect %d, actual: %d",
GetAccountNumberSize(), len(number))
}

// check number's digit
for _, digit := range number {
if digit < '0' || digit > '9' {
return fmt.Errorf("invoke NewAccount failed, account nubmer expect continuous %d digits",
GetAccountNumberSize())
}
}
return nil
}
Loading