github.com/aswedchain/aswed@v1.0.1/consensus/congress/congress_govern.go (about) 1 package congress 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "github.com/aswedchain/aswed/accounts" 8 "github.com/aswedchain/aswed/common" 9 "github.com/aswedchain/aswed/common/hexutil" 10 "github.com/aswedchain/aswed/consensus" 11 "github.com/aswedchain/aswed/consensus/congress/systemcontract" 12 "github.com/aswedchain/aswed/consensus/congress/vmcaller" 13 "github.com/aswedchain/aswed/core/state" 14 "github.com/aswedchain/aswed/core/types" 15 "github.com/aswedchain/aswed/log" 16 "github.com/aswedchain/aswed/rlp" 17 "math" 18 "math/big" 19 ) 20 21 // Proposal is the system governance proposal info. 22 type Proposal struct { 23 Id *big.Int 24 Action *big.Int 25 From common.Address 26 To common.Address 27 Value *big.Int 28 Data []byte 29 } 30 31 func (c *Congress) getPassedProposalCount(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB) (uint32, error) { 32 33 method := "getPassedProposalCount" 34 data, err := c.abi[systemcontract.SysGovContractName].Pack(method) 35 if err != nil { 36 log.Error("Can't pack data for getPassedProposalCount", "error", err) 37 return 0, err 38 } 39 40 msg := types.NewMessage(header.Coinbase, &systemcontract.SysGovContractAddr, 0, new(big.Int), math.MaxUint64, new(big.Int), data, false) 41 42 // use parent 43 result, err := vmcaller.ExecuteMsg(msg, state, header, newChainContext(chain, c), c.chainConfig) 44 if err != nil { 45 return 0, err 46 } 47 48 // unpack data 49 ret, err := c.abi[systemcontract.SysGovContractName].Unpack(method, result) 50 if err != nil { 51 return 0, err 52 } 53 if len(ret) != 1 { 54 return 0, errors.New("invalid output length") 55 } 56 count, ok := ret[0].(uint32) 57 if !ok { 58 return 0, errors.New("invalid count format") 59 } 60 61 return count, nil 62 } 63 64 func (c *Congress) getPassedProposalByIndex(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, idx uint32) (*Proposal, error) { 65 66 method := "getPassedProposalByIndex" 67 data, err := c.abi[systemcontract.SysGovContractName].Pack(method, idx) 68 if err != nil { 69 log.Error("Can't pack data for getPassedProposalByIndex", "error", err) 70 return nil, err 71 } 72 73 msg := types.NewMessage(header.Coinbase, &systemcontract.SysGovContractAddr, 0, new(big.Int), math.MaxUint64, new(big.Int), data, false) 74 75 // use parent 76 result, err := vmcaller.ExecuteMsg(msg, state, header, newChainContext(chain, c), c.chainConfig) 77 if err != nil { 78 return nil, err 79 } 80 81 // unpack data 82 prop := &Proposal{} 83 err = c.abi[systemcontract.SysGovContractName].UnpackIntoInterface(prop, method, result) 84 if err != nil { 85 return nil, err 86 } 87 88 return prop, nil 89 } 90 91 //finishProposalById 92 func (c *Congress) finishProposalById(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, id *big.Int) error { 93 method := "finishProposalById" 94 data, err := c.abi[systemcontract.SysGovContractName].Pack(method, id) 95 if err != nil { 96 log.Error("Can't pack data for getPassedProposalByIndex", "error", err) 97 return err 98 } 99 100 msg := types.NewMessage(header.Coinbase, &systemcontract.SysGovContractAddr, 0, new(big.Int), math.MaxUint64, new(big.Int), data, false) 101 102 // execute message without a transaction 103 state.Prepare(common.Hash{}, header.Hash(), 0) 104 _, err = vmcaller.ExecuteMsg(msg, state, header, newChainContext(chain, c), c.chainConfig) 105 if err != nil { 106 return err 107 } 108 109 return nil 110 } 111 112 func (c *Congress) executeProposal(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, prop *Proposal, totalTxIndex int) (*types.Transaction, *types.Receipt, error) { 113 // Even if the miner is not `running`, it's still working, 114 // the 'miner.worker' will try to FinalizeAndAssemble a block, 115 // in this case, the signTxFn is not set. A `non-miner node` can't execute system governance proposal. 116 if c.signTxFn == nil { 117 return nil, nil, errors.New("signTxFn not set") 118 } 119 120 propRLP, err := rlp.EncodeToBytes(prop) 121 if err != nil { 122 return nil, nil, err 123 } 124 //make system governance transaction 125 nonce := state.GetNonce(c.validator) 126 tx := types.NewTransaction(nonce, systemcontract.SysGovToAddr, prop.Value, header.GasLimit, new(big.Int), propRLP) 127 tx, err = c.signTxFn(accounts.Account{Address: c.validator}, tx, chain.Config().ChainID) 128 if err != nil { 129 return nil, nil, err 130 } 131 //add nonce for validator 132 state.SetNonce(c.validator, nonce+1) 133 receipt := c.executeProposalMsg(chain, header, state, prop, totalTxIndex, tx.Hash(), common.Hash{}) 134 135 return tx, receipt, nil 136 } 137 138 func (c *Congress) replayProposal(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, prop *Proposal, totalTxIndex int, tx *types.Transaction) (*types.Receipt, error) { 139 sender, err := types.Sender(c.signer, tx) 140 if err != nil { 141 return nil, err 142 } 143 if sender != header.Coinbase { 144 return nil, errors.New("invalid sender for system governance transaction") 145 } 146 propRLP, err := rlp.EncodeToBytes(prop) 147 if err != nil { 148 return nil, err 149 } 150 if !bytes.Equal(propRLP, tx.Data()) { 151 return nil, fmt.Errorf("data missmatch, proposalID: %s, rlp: %s, txHash:%s, txData:%s", prop.Id.String(), hexutil.Encode(propRLP), tx.Hash().String(), hexutil.Encode(tx.Data())) 152 } 153 //make system governance transaction 154 nonce := state.GetNonce(sender) 155 //add nonce for validator 156 state.SetNonce(sender, nonce+1) 157 receipt := c.executeProposalMsg(chain, header, state, prop, totalTxIndex, tx.Hash(), header.Hash()) 158 159 return receipt, nil 160 } 161 162 func (c *Congress) executeProposalMsg(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, prop *Proposal, totalTxIndex int, txHash, bHash common.Hash) *types.Receipt { 163 var receipt *types.Receipt 164 action := prop.Action.Uint64() 165 switch action { 166 case 0: 167 // evm action. 168 receipt = c.executeEvmCallProposal(chain, header, state, prop, totalTxIndex, txHash, bHash) 169 case 1: 170 // delete code action 171 ok := state.Erase(prop.To) 172 receipt = types.NewReceipt([]byte{}, ok != true, header.GasUsed) 173 log.Info("executeProposalMsg", "action", "erase", "id", prop.Id.String(), "to", prop.To, "txHash", txHash.String(), "success", ok) 174 default: 175 receipt = types.NewReceipt([]byte{}, true, header.GasUsed) 176 log.Warn("executeProposalMsg failed, unsupported action", "action", action, "id", prop.Id.String(), "from", prop.From, "to", prop.To, "value", prop.Value.String(), "data", hexutil.Encode(prop.Data), "txHash", txHash.String()) 177 } 178 179 receipt.TxHash = txHash 180 receipt.BlockHash = state.BlockHash() 181 receipt.BlockNumber = header.Number 182 receipt.TransactionIndex = uint(state.TxIndex()) 183 184 return receipt 185 } 186 187 // the returned value should not nil. 188 func (c *Congress) executeEvmCallProposal(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, prop *Proposal, totalTxIndex int, txHash, bHash common.Hash) *types.Receipt { 189 // actually run the governance message 190 msg := types.NewMessage(prop.From, &prop.To, 0, prop.Value, header.GasLimit, new(big.Int), prop.Data, false) 191 state.Prepare(txHash, bHash, totalTxIndex) 192 _, err := vmcaller.ExecuteMsg(msg, state, header, newChainContext(chain, c), c.chainConfig) 193 state.Finalise(true) 194 195 // governance message will not actually consumes gas 196 receipt := types.NewReceipt([]byte{}, err != nil, header.GasUsed) 197 // Set the receipt logs and create a bloom for filtering 198 receipt.Logs = state.GetLogs(txHash) 199 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 200 201 log.Info("executeProposalMsg", "action", "evmCall", "id", prop.Id.String(), "from", prop.From, "to", prop.To, "value", prop.Value.String(), "data", hexutil.Encode(prop.Data), "txHash", txHash.String(), "err", err) 202 203 return receipt 204 }