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  }