Skip to content

Commit

Permalink
make get balance query atomic (#1130)
Browse files Browse the repository at this point in the history
  • Loading branch information
laizy authored Nov 21, 2019
1 parent 9c26f63 commit f34884e
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 33 deletions.
4 changes: 4 additions & 0 deletions core/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ func (self *Ledger) PreExecuteContract(tx *types.Transaction) (*cstate.PreExecRe
return self.ldgStore.PreExecuteContract(tx)
}

func (self *Ledger) PreExecuteContractBatch(txes []*types.Transaction, atomic bool) ([]*cstate.PreExecResult, uint32, error) {
return self.ldgStore.PreExecuteContractBatch(txes, atomic)
}

func (self *Ledger) GetEventNotifyByTx(tx common.Uint256) (*event.ExecuteNotify, error) {
return self.ldgStore.GetEventNotifyByTx(tx)
}
Expand Down
24 changes: 22 additions & 2 deletions core/store/ledgerstore/ledger_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,10 +821,10 @@ func (this *LedgerStoreImp) submitBlock(block *types.Block, result store.Execute
//saveBlock do the job of execution samrt contract and commit block to store.
func (this *LedgerStoreImp) saveBlock(block *types.Block, stateMerkleRoot common.Uint256) error {
blockHeight := block.Header.Height
if this.tryGetSavingBlockLock() {
//hash already saved or is saving
if blockHeight > 0 && blockHeight <= this.GetCurrentBlockHeight() {
return nil
}
this.getSavingBlockLock()
defer this.releaseSavingBlockLock()
if this.closing {
return errors.NewErr("save block error: ledger is closing")
Expand Down Expand Up @@ -1004,6 +1004,26 @@ func (this *LedgerStoreImp) GetEventNotifyByBlock(height uint32) ([]*event.Execu
return this.eventStore.GetEventNotifyByBlock(height)
}

//PreExecuteContract return the result of smart contract execution without commit to store
func (this *LedgerStoreImp) PreExecuteContractBatch(txes []*types.Transaction, atomic bool) ([]*sstate.PreExecResult, uint32, error) {
if atomic {
this.getSavingBlockLock()
defer this.releaseSavingBlockLock()
}
height := this.GetCurrentBlockHeight()
results := make([]*sstate.PreExecResult, 0, len(txes))
for _, tx := range txes {
res, err := this.PreExecuteContract(tx)
if err != nil {
return nil, height, err
}

results = append(results, res)
}

return results, height, nil
}

//PreExecuteContract return the result of smart contract execution without commit to store
func (this *LedgerStoreImp) PreExecuteContract(tx *types.Transaction) (*sstate.PreExecResult, error) {
height := this.GetCurrentBlockHeight()
Expand Down
1 change: 1 addition & 0 deletions core/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type LedgerStore interface {
GetBookkeeperState() (*states.BookkeeperState, error)
GetStorageItem(key *states.StorageKey) (*states.StorageItem, error)
PreExecuteContract(tx *types.Transaction) (*cstates.PreExecResult, error)
PreExecuteContractBatch(txes []*types.Transaction, atomic bool) ([]*cstates.PreExecResult, uint32, error)
GetEventNotifyByTx(tx common.Uint256) (*event.ExecuteNotify, error)
GetEventNotifyByBlock(height uint32) ([]*event.ExecuteNotify, error)
}
4 changes: 4 additions & 0 deletions http/base/actor/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ func PreExecuteContract(tx *types.Transaction) (*cstate.PreExecResult, error) {
return ledger.DefLedger.PreExecuteContract(tx)
}

func PreExecuteContractBatch(tx []*types.Transaction, atomic bool) ([]*cstate.PreExecResult, uint32, error) {
return ledger.DefLedger.PreExecuteContractBatch(tx, atomic)
}

//GetEventNotifyByTxHash from ledger
func GetEventNotifyByTxHash(txHash common.Uint256) (*event.ExecuteNotify, error) {
return ledger.DefLedger.GetEventNotifyByTx(txHash)
Expand Down
67 changes: 38 additions & 29 deletions http/base/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ const MAX_SEARCH_HEIGHT uint32 = 100
const MAX_REQUEST_BODY_SIZE = 1 << 20

type BalanceOfRsp struct {
Ont string `json:"ont"`
Ong string `json:"ong"`
Ont string `json:"ont"`
Ong string `json:"ong"`
Height string `json:"height"`
}

type MerkleProof struct {
Expand Down Expand Up @@ -279,17 +280,14 @@ func GetBlockInfo(block *types.Block) BlockInfo {
}

func GetBalance(address common.Address) (*BalanceOfRsp, error) {
ont, err := GetContractBalance(0, utils.OntContractAddress, address)
if err != nil {
return nil, fmt.Errorf("get ont balance error:%s", err)
}
ong, err := GetContractBalance(0, utils.OngContractAddress, address)
balances, height, err := GetContractBalance(0, []common.Address{utils.OntContractAddress, utils.OngContractAddress}, address, true)
if err != nil {
return nil, fmt.Errorf("get ont balance error:%s", err)
}
return &BalanceOfRsp{
Ont: fmt.Sprintf("%d", ont),
Ong: fmt.Sprintf("%d", ong),
Ont: fmt.Sprintf("%d", balances[0]),
Ong: fmt.Sprintf("%d", balances[1]),
Height: fmt.Sprintf("%d", height),
}, nil
}

Expand All @@ -304,11 +302,11 @@ func GetGrantOng(addr common.Address) (string, error) {
if eof {
return fmt.Sprintf("%v", 0), io.ErrUnexpectedEOF
}
ont, err := GetContractBalance(0, utils.OntContractAddress, addr)
onts, _, err := GetContractBalance(0, []common.Address{utils.OntContractAddress}, addr, false)
if err != nil {
return fmt.Sprintf("%v", 0), err
}
boundong := utils.CalcUnbindOng(ont, v, uint32(time.Now().Unix())-constants.GENESIS_BLOCK_TIMESTAMP)
boundong := utils.CalcUnbindOng(onts[0], v, uint32(time.Now().Unix())-constants.GENESIS_BLOCK_TIMESTAMP)
return fmt.Sprintf("%v", boundong), nil
}

Expand All @@ -329,29 +327,40 @@ func GetAllowance(asset string, from, to common.Address) (string, error) {
return fmt.Sprintf("%v", allowance), nil
}

func GetContractBalance(cVersion byte, contractAddr, accAddr common.Address) (uint64, error) {
mutable, err := NewNativeInvokeTransaction(0, 0, contractAddr, cVersion, "balanceOf", []interface{}{accAddr[:]})
if err != nil {
return 0, fmt.Errorf("NewNativeInvokeTransaction error:%s", err)
}
tx, err := mutable.IntoImmutable()
if err != nil {
return 0, err
func GetContractBalance(cVersion byte, contractAddres []common.Address, accAddr common.Address, atomic bool) ([]uint64, uint32, error) {
txes := make([]*types.Transaction, 0, len(contractAddres))
for _, contractAddr := range contractAddres {
mutable, err := NewNativeInvokeTransaction(0, 0, contractAddr, cVersion, "balanceOf", []interface{}{accAddr[:]})
if err != nil {
return nil, 0, fmt.Errorf("NewNativeInvokeTransaction error:%s", err)
}
tx, err := mutable.IntoImmutable()
if err != nil {
return nil, 0, err
}

txes = append(txes, tx)
}
result, err := bactor.PreExecuteContract(tx)

results, height, err := bactor.PreExecuteContractBatch(txes, atomic)
if err != nil {
return 0, fmt.Errorf("PrepareInvokeContract error:%s", err)
}
if result.State == 0 {
return 0, fmt.Errorf("prepare invoke failed")
return nil, 0, fmt.Errorf("PrepareInvokeContract error:%s", err)
}
data, err := hex.DecodeString(result.Result.(string))
if err != nil {
return 0, fmt.Errorf("hex.DecodeString error:%s", err)
balances := make([]uint64, 0, len(contractAddres))
for _, result := range results {
if result.State == 0 {
return nil, 0, fmt.Errorf("prepare invoke failed")
}
data, err := hex.DecodeString(result.Result.(string))
if err != nil {
return nil, 0, fmt.Errorf("hex.DecodeString error:%s", err)
}

balance := common.BigIntFromNeoBytes(data)
balances = append(balances, balance.Uint64())
}

balance := common.BigIntFromNeoBytes(data)
return balance.Uint64(), nil
return balances, height, nil
}

func GetContractAllowance(cVersion byte, contractAddr, fromAddr, toAddr common.Address) (uint64, error) {
Expand Down
4 changes: 2 additions & 2 deletions txnpool/proc/txnpool_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ func NewVerifyRspActor(s *TXPoolServer) *VerifyRspActor {

// isBalanceEnough checks if the tranactor has enough to cover gas cost
func isBalanceEnough(address common.Address, gas uint64) bool {
balance, err := hComm.GetContractBalance(0, utils.OngContractAddress, address)
balance, _, err := hComm.GetContractBalance(0, []common.Address{utils.OngContractAddress}, address, false)
if err != nil {
log.Debugf("failed to get contract balance %s err %v",
address.ToHexString(), err)
return false
}
return balance >= gas
return balance[0] >= gas
}

func replyTxResult(txResultCh chan *tc.TxResult, hash common.Uint256,
Expand Down

0 comments on commit f34884e

Please sign in to comment.