github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/core/vm/ticket_pool.go (about) 1 package vm 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "github.com/PlatONnetwork/PlatON-Go/common" 8 "github.com/PlatONnetwork/PlatON-Go/core/types" 9 "github.com/PlatONnetwork/PlatON-Go/crypto" 10 "github.com/PlatONnetwork/PlatON-Go/log" 11 "github.com/PlatONnetwork/PlatON-Go/p2p/discover" 12 "github.com/PlatONnetwork/PlatON-Go/params" 13 "github.com/PlatONnetwork/PlatON-Go/rlp" 14 "math/big" 15 "strconv" 16 ) 17 18 var ( 19 ErrTicketPrice = errors.New("Ticket Price is illegal") 20 ErrIllegalDeposit = errors.New("Deposit balance not match or too low") 21 ErrTicketPoolEmpty = errors.New("Ticket Pool is null") 22 ) 23 24 const ( 25 VoteTicketEvent = "VoteTicketEvent" 26 ) 27 28 type ticketPoolContext interface { 29 VoteTicket(stateDB StateDB, owner common.Address, voteNumber uint32, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) (uint32, error) 30 GetCandidatesTicketCount(stateDB StateDB, nodeIds []discover.NodeID) map[discover.NodeID]uint32 31 GetBatchTicketRemaining(stateDB StateDB, ticketIds []common.Hash) map[common.Hash]uint32 32 GetCandidateEpoch(stateDB StateDB, nodeId discover.NodeID) uint64 33 GetPoolNumber(stateDB StateDB) uint32 34 GetTicketPrice(stateDB StateDB) *big.Int 35 } 36 37 type TicketContract struct { 38 Contract *Contract 39 Evm *EVM 40 } 41 42 func (t *TicketContract) RequiredGas(input []byte) uint64 { 43 return params.EcrecoverGas 44 } 45 46 func (t *TicketContract) Run(input []byte) ([]byte, error) { 47 if nil == t.Evm.TicketPoolContext { 48 log.Error("Failed to TicketContract Run", "ErrTicketPoolEmpty: ", ErrTicketPoolEmpty.Error()) 49 return nil, ErrTicketPoolEmpty 50 } 51 var command = map[string]interface{}{ 52 "VoteTicket": t.VoteTicket, 53 "GetCandidateTicketCount": t.GetCandidateTicketCount, 54 "GetTicketCountByTxHash": t.GetTicketCountByTxHash, 55 "GetCandidateEpoch": t.GetCandidateEpoch, 56 "GetPoolRemainder": t.GetPoolRemainder, 57 "GetTicketPrice": t.GetTicketPrice, 58 } 59 return execute(input, command) 60 } 61 62 // VoteTicket let a account buy tickets and vote to the chosen candidate. 63 func (t *TicketContract) VoteTicket(count uint32, price *big.Int, nodeId discover.NodeID) ([]byte, error) { 64 value := t.Contract.value 65 txHash := t.Evm.StateDB.TxHash() 66 txIdx := t.Evm.StateDB.TxIdx() 67 blockNumber := t.Evm.Context.BlockNumber 68 from := t.Contract.caller.Address() 69 log.Info("Input to VoteTicket", " nodeId: ", nodeId.String(), " owner: ", from.Hex(), " txhash: ", txHash.Hex(), 70 " txIdx: ", txIdx, " blockNumber: ", blockNumber, " value: ", value, " count: ", count, " price: ", price) 71 ticketPrice := t.Evm.TicketPoolContext.GetTicketPrice(t.Evm.StateDB) 72 var priceDiff *big.Int 73 if price.Cmp(ticketPrice) < 0 { 74 log.Error("Failed to VoteTicket", "ErrTicketPrice: ", ErrTicketPrice.Error()) 75 return nil, ErrTicketPrice 76 } else { 77 priceDiff = new(big.Int).Sub(price, ticketPrice) 78 } 79 totalPrice := new(big.Int).Mul(new(big.Int).SetUint64(uint64(count)), ticketPrice) 80 if value.Cmp(totalPrice) < 0 || totalPrice.Cmp(big.NewInt(0)) != 1 { 81 log.Error("Failed to VoteTicket", "ErrIllegalDeposit: ", ErrIllegalDeposit.Error()) 82 return nil, ErrIllegalDeposit 83 } 84 can := t.Evm.CandidatePoolContext.GetCandidate(t.Evm.StateDB, nodeId, blockNumber) 85 if nil == can { 86 log.Error("Failed to VoteTicket", "ErrCandidateNotExist: ", ErrCandidateNotExist.Error()) 87 return nil, ErrCandidateNotExist 88 } 89 successCount, err := t.Evm.TicketPoolContext.VoteTicket(t.Evm.StateDB, from, count, ticketPrice, nodeId, blockNumber) 90 if 0 == successCount { 91 log.Error("Failed to VoteTicket", "VoteTicket return err(0 == len(ticketIds)): ", err.Error()) 92 return nil, err 93 } 94 // return the balance of failed ticket 95 if successCount < count { 96 failCount := count - successCount 97 backBalance := new(big.Int).Mul(new(big.Int).SetUint64(uint64(failCount)), price) 98 t.Evm.StateDB.AddBalance(from, backBalance) 99 t.Evm.StateDB.SubBalance(common.TicketPoolAddr, backBalance) 100 } 101 // return the balance of different price 102 if priceDiff.Cmp(big.NewInt(0)) == 1 { 103 diffBalance := new(big.Int).Mul(new(big.Int).SetUint64(uint64(successCount)), priceDiff) 104 t.Evm.StateDB.AddBalance(from, diffBalance) 105 t.Evm.StateDB.SubBalance(common.TicketPoolAddr, diffBalance) 106 } 107 data := strconv.FormatUint(uint64(successCount), 10) + ":" + ticketPrice.String() 108 sdata := DecodeResultStr(data) 109 log.Info("Result of VoteTicket", "successCount: ", successCount, "dealTPrice: ", ticketPrice, "json: ", data) 110 if nil != err { 111 log.Warn("Failed to VoteTicket", "VoteTicket return err: ", err.Error()) 112 r := ResultCommon{true, data, err.Error()} 113 event, _ := json.Marshal(r) 114 t.addLog(VoteTicketEvent, string(event)) 115 return sdata, nil 116 } 117 r := ResultCommon{true, data, "success"} 118 event, _ := json.Marshal(r) 119 t.addLog(VoteTicketEvent, string(event)) 120 return sdata, nil 121 } 122 123 // GetCandidateTicketCount returns the number of candidate's ticket. 124 func (t *TicketContract) GetCandidateTicketCount(nodeIds []discover.NodeID) ([]byte, error) { 125 input, _ := json.Marshal(nodeIds) 126 log.Info("Input to GetCandidateTicketCount", "length: ", len(nodeIds), "nodeIds: ", string(input)) 127 candidatesTicketCount := t.Evm.TicketPoolContext.GetCandidatesTicketCount(t.Evm.StateDB, nodeIds) 128 data, _ := json.Marshal(candidatesTicketCount) 129 sdata := DecodeResultStr(string(data)) 130 log.Info("Result of GetCandidateTicketCount", "len(candidatesTicketCount): ", len(candidatesTicketCount), "json: ", string(data)) 131 return sdata, nil 132 } 133 134 // GetTicketCountByTxHash returns the number of transaction's ticket. 135 func (t *TicketContract) GetTicketCountByTxHash(ticketIds []common.Hash) ([]byte, error) { 136 input, _ := json.Marshal(ticketIds) 137 log.Info("Input to GetTicketCountByTxHash", "length: ", len(ticketIds), "ticketIds: ", string(input)) 138 ticketsRemaining := t.Evm.TicketPoolContext.GetBatchTicketRemaining(t.Evm.StateDB, ticketIds) 139 data, _ := json.Marshal(ticketsRemaining) 140 sdata := DecodeResultStr(string(data)) 141 log.Info("Result of GetTicketCountByTxHash", "len(ticketsRemaining): ", len(ticketsRemaining), "json: ", string(data)) 142 return sdata, nil 143 } 144 145 // GetCandidateEpoch returns the current ticket age for the candidate. 146 func (t *TicketContract) GetCandidateEpoch(nodeId discover.NodeID) ([]byte, error) { 147 log.Info("Input to GetCandidateEpoch", " nodeId: ", nodeId.String()) 148 epoch := t.Evm.TicketPoolContext.GetCandidateEpoch(t.Evm.StateDB, nodeId) 149 data, _ := json.Marshal(epoch) 150 sdata := DecodeResultStr(string(data)) 151 log.Info("Result of GetCandidateEpoch", "json: ", string(data)) 152 return sdata, nil 153 } 154 155 // GetPoolRemainder returns the amount of remaining tickets in the ticket pool. 156 func (t *TicketContract) GetPoolRemainder() ([]byte, error) { 157 remainder := t.Evm.TicketPoolContext.GetPoolNumber(t.Evm.StateDB) 158 data, _ := json.Marshal(remainder) 159 sdata := DecodeResultStr(string(data)) 160 log.Info("Result of GetPoolRemainder", "json: ", string(data)) 161 return sdata, nil 162 } 163 164 // GetTicketPrice returns the current ticket price for the ticket pool. 165 func (t *TicketContract) GetTicketPrice() ([]byte, error) { 166 price := t.Evm.TicketPoolContext.GetTicketPrice(t.Evm.StateDB) 167 data, _ := json.Marshal(price) 168 sdata := DecodeResultStr(string(data)) 169 log.Info("Result of GetTicketPrice", "json: ", string(data)) 170 return sdata, nil 171 } 172 173 // addLog let the result add to event. 174 func (t *TicketContract) addLog(event, data string) { 175 var logdata [][]byte 176 logdata = make([][]byte, 0) 177 logdata = append(logdata, []byte(data)) 178 buf := new(bytes.Buffer) 179 if err := rlp.Encode(buf, logdata); nil != err { 180 log.Error("Failed to addlog", "rlp encode fail: ", err.Error()) 181 } 182 t.Evm.StateDB.AddLog(&types.Log{ 183 Address: common.TicketPoolAddr, 184 Topics: []common.Hash{common.BytesToHash(crypto.Keccak256([]byte(event)))}, 185 Data: buf.Bytes(), 186 BlockNumber: t.Evm.Context.BlockNumber.Uint64(), 187 }) 188 }