github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/core/vm/candidate_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 ) 16 17 var ( 18 ErrOwnerNotOnly = errors.New("Node ID cannot bind multiple owners") 19 ErrPermissionDenied = errors.New("Transaction from address permission denied") 20 ErrFeeIllegal = errors.New("The fee is illegal") 21 ErrDepositEmpty = errors.New("Deposit balance not zero") 22 ErrWithdrawEmpty = errors.New("No withdrawal amount") 23 ErrCandidatePoolEmpty = errors.New("Candidate Pool is null") 24 ErrCandidateNotExist = errors.New("The candidate is not exist") 25 ErrCandidateAlreadyExist = errors.New("The candidate is already exist") 26 ) 27 28 const ( 29 CandidateDepositEvent = "CandidateDepositEvent" 30 CandidateApplyWithdrawEvent = "CandidateApplyWithdrawEvent" 31 CandidateWithdrawEvent = "CandidateWithdrawEvent" 32 SetCandidateExtraEvent = "SetCandidateExtraEvent" 33 ) 34 35 type candidatePoolContext interface { 36 SetCandidate(state StateDB, nodeId discover.NodeID, can *types.Candidate) error 37 GetCandidate(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) *types.Candidate 38 GetCandidateArr(state StateDB, blockNumber *big.Int, nodeIds ...discover.NodeID) types.CandidateQueue 39 WithdrawCandidate(state StateDB, nodeId discover.NodeID, price, blockNumber *big.Int) error 40 GetChosens(state StateDB, flag int, blockNumber *big.Int) types.KindCanQueue 41 GetChairpersons(state StateDB, blockNumber *big.Int) types.CandidateQueue 42 GetDefeat(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) types.RefundQueue 43 IsDefeat(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) bool 44 IsChosens(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) bool 45 RefundBalance(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) error 46 GetOwner(state StateDB, nodeId discover.NodeID, blockNumber *big.Int) common.Address 47 SetCandidateExtra(state StateDB, nodeId discover.NodeID, extra string) error 48 GetRefundInterval(blockNumber *big.Int) uint32 49 MaxCount() uint32 50 MaxChair() uint32 51 } 52 53 type CandidateContract struct { 54 Contract *Contract 55 Evm *EVM 56 } 57 58 func (c *CandidateContract) RequiredGas(input []byte) uint64 { 59 return params.EcrecoverGas 60 } 61 62 func (c *CandidateContract) Run(input []byte) ([]byte, error) { 63 if nil == c.Evm.CandidatePoolContext { 64 log.Error("Failed to CandidateContract Run", "ErrCandidatePoolEmpty: ", ErrCandidatePoolEmpty.Error()) 65 return nil, ErrCandidatePoolEmpty 66 } 67 var command = map[string]interface{}{ 68 "CandidateDeposit": c.CandidateDeposit, 69 "CandidateApplyWithdraw": c.CandidateApplyWithdraw, 70 "CandidateWithdraw": c.CandidateWithdraw, 71 "SetCandidateExtra": c.SetCandidateExtra, 72 "GetCandidateWithdrawInfos": c.GetCandidateWithdrawInfos, 73 "GetCandidateDetails": c.GetCandidateDetails, 74 "GetCandidateList": c.GetCandidateList, 75 "GetVerifiersList": c.GetVerifiersList, 76 } 77 return execute(input, command) 78 } 79 80 // Candidate Application && Increase Quality Deposit 81 func (c *CandidateContract) CandidateDeposit(nodeId discover.NodeID, owner common.Address, fee uint32, host, port, extra string) ([]byte, error) { 82 deposit := c.Contract.value 83 txHash := c.Evm.StateDB.TxHash() 84 txIdx := c.Evm.StateDB.TxIdx() 85 height := c.Evm.Context.BlockNumber 86 //from := c.Contract.caller.Address() 87 log.Info("Input to CandidateDeposit", "blockNumber", height.String(), "nodeId: ", nodeId.String(), " owner: ", owner.Hex(), " deposit: ", deposit, 88 " fee: ", fee, " txhash: ", txHash.Hex(), " txIdx: ", txIdx, " height: ", height, " host: ", host, " port: ", port, " extra: ", extra) 89 if fee > 10000 { 90 log.Error("Failed to CandidateDeposit", "blockNumber", height.String(), "ErrFeeIllegal: ", ErrFeeIllegal.Error()) 91 return nil, ErrFeeIllegal 92 } 93 if deposit.Cmp(big.NewInt(0)) < 1 { 94 log.Error("Failed to CandidateDeposit", "blockNumber", height.String(), "ErrDepositEmpty: ", ErrDepositEmpty.Error()) 95 return nil, ErrDepositEmpty 96 } 97 addr := c.Evm.CandidatePoolContext.GetOwner(c.Evm.StateDB, nodeId, height) 98 if common.ZeroAddr != addr { 99 if ok := bytes.Equal(addr.Bytes(), owner.Bytes()); !ok { 100 log.Error("Failed to CandidateDeposit==> ", "blockNumber", height.String(), "old owner", addr.Hex(), "new owner", owner, "ErrOwnerNotOnly: ", ErrOwnerNotOnly.Error()) 101 return nil, ErrOwnerNotOnly 102 } 103 } 104 //var alldeposit *big.Int 105 var txhash common.Hash 106 var towner common.Address 107 can := c.Evm.CandidatePoolContext.GetCandidate(c.Evm.StateDB, nodeId, height) 108 if nil != can { 109 log.Error("Failed to CandidateDeposit, the candidate is already exist", "blockNumber", height.String(), "nodeId", nodeId.String()) 110 return nil, ErrCandidateAlreadyExist 111 } 112 //if nil != can { 113 // alldeposit = new(big.Int).Add(can.Deposit, deposit) 114 // txhash = can.TxHash 115 // towner = can.TOwner 116 // log.Info("CandidateDeposit==> ", "alldeposit: ", alldeposit, " can.Deposit: ", can.Deposit, " deposit: ", deposit) 117 //} else { 118 // alldeposit = deposit 119 //} 120 canDeposit := types.Candidate{ 121 //alldeposit, 122 deposit, 123 height, 124 txIdx, 125 nodeId, 126 host, 127 port, 128 owner, 129 extra, 130 fee, 131 txhash, 132 towner, 133 } 134 log.Info("CandidateDeposit", "blockNumber", height.String(), "canDeposit: ", canDeposit) 135 if err := c.Evm.CandidatePoolContext.SetCandidate(c.Evm.StateDB, nodeId, &canDeposit); nil != err { 136 log.Error("Failed to CandidateDeposit", "blockNumber", height.String(), "SetCandidate return err: ", err.Error()) 137 return nil, err 138 } 139 r := ResultCommon{true, "", "success"} 140 event, _ := json.Marshal(r) 141 c.addLog(CandidateDepositEvent, string(event)) 142 log.Info("Result of CandidateDeposit", "blockNumber", height.String(), "json: ", string(event)) 143 return nil, nil 144 } 145 146 // Apply for a refund of the deposit 147 func (c *CandidateContract) CandidateApplyWithdraw(nodeId discover.NodeID, withdraw *big.Int) ([]byte, error) { 148 txHash := c.Evm.StateDB.TxHash() 149 from := c.Contract.caller.Address() 150 height := c.Evm.Context.BlockNumber 151 log.Info("Input to CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "nodeId: ", nodeId.String(), " from: ", from.Hex(), " txHash: ", txHash.Hex(), " withdraw: ", withdraw, " height: ", height) 152 can := c.Evm.CandidatePoolContext.GetCandidate(c.Evm.StateDB, nodeId, height) 153 154 if nil == can { 155 log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "ErrCandidateNotExist: ", ErrCandidateNotExist.Error()) 156 return nil, ErrCandidateNotExist 157 } 158 if can.Deposit.Cmp(big.NewInt(0)) < 1 { 159 log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "ErrWithdrawEmpty: ", ErrWithdrawEmpty.Error()) 160 return nil, ErrWithdrawEmpty 161 } 162 if ok := bytes.Equal(can.Owner.Bytes(), from.Bytes()); !ok { 163 log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "ErrPermissionDenied: ", ErrPermissionDenied.Error()) 164 return nil, ErrPermissionDenied 165 } 166 if withdraw.Cmp(can.Deposit) > 0 { 167 withdraw = can.Deposit 168 } 169 if err := c.Evm.CandidatePoolContext.WithdrawCandidate(c.Evm.StateDB, nodeId, withdraw, height); nil != err { 170 log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "WithdrawCandidate return err: ", err.Error()) 171 return nil, err 172 } 173 r := ResultCommon{true, "", "success"} 174 event, _ := json.Marshal(r) 175 c.addLog(CandidateApplyWithdrawEvent, string(event)) 176 log.Info("Result of CandidateApplyWithdraw on WithdrawCandidate", "blockNumber", height.String(), "json: ", string(event)) 177 return nil, nil 178 } 179 180 // Deposit withdrawal 181 func (c *CandidateContract) CandidateWithdraw(nodeId discover.NodeID) ([]byte, error) { 182 txHash := c.Evm.StateDB.TxHash() 183 height := c.Evm.Context.BlockNumber 184 log.Info("Input to CandidateWithdraw to RefundBalance", "nodeId: ", nodeId.String(), " height: ", height, " txHash: ", txHash.Hex()) 185 if err := c.Evm.CandidatePoolContext.RefundBalance(c.Evm.StateDB, nodeId, height); nil != err { 186 log.Error("Failed to CandidateWithdraw to RefundBalance", "blockNumber", height.String(), "RefundBalance return err: ", err.Error()) 187 return nil, err 188 } 189 r := ResultCommon{true, "", "success"} 190 event, _ := json.Marshal(r) 191 c.addLog(CandidateWithdrawEvent, string(event)) 192 log.Info("Result of CandidateWithdraw to RefundBalance", "blockNumber", height.String(), "json: ", string(event)) 193 return nil, nil 194 } 195 196 // Set up additional information 197 func (c *CandidateContract) SetCandidateExtra(nodeId discover.NodeID, extra string) ([]byte, error) { 198 txHash := c.Evm.StateDB.TxHash() 199 from := c.Contract.caller.Address() 200 height := c.Evm.Context.BlockNumber 201 log.Info("Input to SetCandidateExtra", "blockNumber", height.String(), "nodeId: ", nodeId.String(), " extra: ", extra, " from: ", from.Hex(), " txHash: ", txHash.Hex()) 202 owner := c.Evm.CandidatePoolContext.GetOwner(c.Evm.StateDB, nodeId, height) 203 if ok := bytes.Equal(owner.Bytes(), from.Bytes()); !ok { 204 log.Error("Failed to SetCandidateExtra", "blockNumber", height.String(), "ErrPermissionDenied: ", ErrPermissionDenied.Error()) 205 return nil, ErrPermissionDenied 206 } 207 if err := c.Evm.CandidatePoolContext.SetCandidateExtra(c.Evm.StateDB, nodeId, extra); nil != err { 208 log.Error("Failed to SetCandidateExtra", "blockNumber", height.String(), "SetCandidateExtra return err: ", err.Error()) 209 return nil, err 210 } 211 r := ResultCommon{true, "", "success"} 212 event, _ := json.Marshal(r) 213 c.addLog(SetCandidateExtraEvent, string(event)) 214 log.Info("Result of SetCandidateExtra", "blockNumber", height.String(), "json: ", string(event)) 215 return nil, nil 216 } 217 218 // Get the refund history you have applied for 219 func (c *CandidateContract) GetCandidateWithdrawInfos(nodeId discover.NodeID) ([]byte, error) { 220 height := c.Evm.Context.BlockNumber 221 log.Info("Input to CandidateWithdrawInfos", "blockNumber", height.String(), "nodeId: ", nodeId.String()) 222 223 refunds := c.Evm.CandidatePoolContext.GetDefeat(c.Evm.StateDB, nodeId, height) 224 type WithdrawInfo struct { 225 Balance *big.Int 226 LockNumber *big.Int 227 LockBlockCycle uint32 228 } 229 r := make([]WithdrawInfo, len(refunds)) 230 for i, v := range refunds { 231 refundBlockNumber := c.Evm.CandidatePoolContext.GetRefundInterval(height) 232 log.Debug("Call CandidateWithdrawInfos", "Deposit", v.Deposit, "BlockNumber", v.BlockNumber.String(), "RefundBlockNumber", refundBlockNumber) 233 r[i] = WithdrawInfo{v.Deposit, v.BlockNumber, refundBlockNumber} 234 } 235 data, _ := json.Marshal(r) 236 sdata := DecodeResultStr(string(data)) 237 log.Info("Result of CandidateWithdrawInfos", "blockNumber", height.String(), "json: ", string(data)) 238 return sdata, nil 239 } 240 241 // GetCandidateDetails returns the batch of candidate info. 242 func (c *CandidateContract) GetCandidateDetails(nodeIds []discover.NodeID) ([]byte, error) { 243 244 height := c.Evm.Context.BlockNumber 245 input, _ := json.Marshal(nodeIds) 246 log.Info("Input to GetCandidateDetails", "blockNumber", height.String(), "length: ", len(nodeIds), " nodeIds: ", string(input)) 247 candidates := c.Evm.CandidatePoolContext.GetCandidateArr(c.Evm.StateDB, height, nodeIds...) 248 data, _ := json.Marshal(candidates) 249 sdata := DecodeResultStr(string(data)) 250 log.Info("Result of GetCandidateDetails", "blockNumber", height.String(), "len(candidates): ", len(candidates), "json: ", string(data)) 251 return sdata, nil 252 } 253 254 // Get the current block candidate list 255 func (c *CandidateContract) GetCandidateList() ([]byte, error) { 256 257 height := c.Evm.Context.BlockNumber 258 candidates := c.Evm.CandidatePoolContext.GetChosens(c.Evm.StateDB, 0, height) 259 data, _ := json.Marshal(candidates) 260 sdata := DecodeResultStr(string(data)) 261 log.Info("Result of GetCandidateList", "blockNumber", height.String(), "len(candidates): ", len(candidates[0])+len(candidates[1]), "json: ", string(data)) 262 return sdata, nil 263 } 264 265 // Get the current block round certifier list 266 func (c *CandidateContract) GetVerifiersList() ([]byte, error) { 267 height := c.Evm.Context.BlockNumber 268 verifiers := c.Evm.CandidatePoolContext.GetChairpersons(c.Evm.StateDB, height) 269 data, _ := json.Marshal(verifiers) 270 sdata := DecodeResultStr(string(data)) 271 log.Info("Result of GetVerifiersList", "blockNumber", height.String(), "len(verifiers): ", len(verifiers), "json: ", string(data)) 272 return sdata, nil 273 } 274 275 // addLog let the result add to event. 276 func (c *CandidateContract) addLog(event, data string) { 277 var logdata [][]byte 278 logdata = make([][]byte, 0) 279 logdata = append(logdata, []byte(data)) 280 buf := new(bytes.Buffer) 281 if err := rlp.Encode(buf, logdata); nil != err { 282 log.Error("Failed to CandidateContract addlog", "rlp encode fail: ", err.Error()) 283 } 284 c.Evm.StateDB.AddLog(&types.Log{ 285 Address: common.CandidatePoolAddr, 286 Topics: []common.Hash{common.BytesToHash(crypto.Keccak256([]byte(event)))}, 287 Data: buf.Bytes(), 288 BlockNumber: c.Evm.Context.BlockNumber.Uint64(), 289 }) 290 }