mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 03:10:48 +00:00
add auction and abi binding
This commit is contained in:
parent
3cac28491c
commit
e3fd4af127
15 changed files with 881 additions and 108 deletions
603
core/TicketAllocator.go
Normal file
603
core/TicketAllocator.go
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
// TicketAllocatorMetaData contains all meta data concerning the TicketAllocator contract.
|
||||
var TicketAllocatorMetaData = &bind.MetaData{
|
||||
ABI: "[{\"inputs\":[],\"name\":\"InvalidBlockNumber\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughTickets\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSystemContract\",\"type\":\"error\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"GetBalance\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint16[]\",\"name\":\"\",\"type\":\"uint16[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"numTickets\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"bidPerTicket\",\"type\":\"uint256\"}],\"name\":\"RequestTickets\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TIMEOUT\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TOTAL_TICKETS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balance\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"head\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"pendingBids\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"requestor\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"amount\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"bidPerTicket\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"queue\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"amount\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"bidPerTicket\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"requestor\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"senders\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
|
||||
}
|
||||
|
||||
// TicketAllocatorABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use TicketAllocatorMetaData.ABI instead.
|
||||
var TicketAllocatorABI = TicketAllocatorMetaData.ABI
|
||||
|
||||
// TicketAllocator is an auto generated Go binding around an Ethereum contract.
|
||||
type TicketAllocator struct {
|
||||
TicketAllocatorCaller // Read-only binding to the contract
|
||||
TicketAllocatorTransactor // Write-only binding to the contract
|
||||
TicketAllocatorFilterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// TicketAllocatorCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type TicketAllocatorCaller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// TicketAllocatorTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type TicketAllocatorTransactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// TicketAllocatorFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type TicketAllocatorFilterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// TicketAllocatorSession is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type TicketAllocatorSession struct {
|
||||
Contract *TicketAllocator // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// TicketAllocatorCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type TicketAllocatorCallerSession struct {
|
||||
Contract *TicketAllocatorCaller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// TicketAllocatorTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type TicketAllocatorTransactorSession struct {
|
||||
Contract *TicketAllocatorTransactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// TicketAllocatorRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type TicketAllocatorRaw struct {
|
||||
Contract *TicketAllocator // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// TicketAllocatorCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type TicketAllocatorCallerRaw struct {
|
||||
Contract *TicketAllocatorCaller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// TicketAllocatorTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type TicketAllocatorTransactorRaw struct {
|
||||
Contract *TicketAllocatorTransactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// NewTicketAllocator creates a new instance of TicketAllocator, bound to a specific deployed contract.
|
||||
func NewTicketAllocator(address common.Address, backend bind.ContractBackend) (*TicketAllocator, error) {
|
||||
contract, err := bindTicketAllocator(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TicketAllocator{TicketAllocatorCaller: TicketAllocatorCaller{contract: contract}, TicketAllocatorTransactor: TicketAllocatorTransactor{contract: contract}, TicketAllocatorFilterer: TicketAllocatorFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// NewTicketAllocatorCaller creates a new read-only instance of TicketAllocator, bound to a specific deployed contract.
|
||||
func NewTicketAllocatorCaller(address common.Address, caller bind.ContractCaller) (*TicketAllocatorCaller, error) {
|
||||
contract, err := bindTicketAllocator(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TicketAllocatorCaller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewTicketAllocatorTransactor creates a new write-only instance of TicketAllocator, bound to a specific deployed contract.
|
||||
func NewTicketAllocatorTransactor(address common.Address, transactor bind.ContractTransactor) (*TicketAllocatorTransactor, error) {
|
||||
contract, err := bindTicketAllocator(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TicketAllocatorTransactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewTicketAllocatorFilterer creates a new log filterer instance of TicketAllocator, bound to a specific deployed contract.
|
||||
func NewTicketAllocatorFilterer(address common.Address, filterer bind.ContractFilterer) (*TicketAllocatorFilterer, error) {
|
||||
contract, err := bindTicketAllocator(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TicketAllocatorFilterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bindTicketAllocator binds a generic wrapper to an already deployed contract.
|
||||
func bindTicketAllocator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := TicketAllocatorMetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_TicketAllocator *TicketAllocatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _TicketAllocator.Contract.TicketAllocatorCaller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_TicketAllocator *TicketAllocatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.TicketAllocatorTransactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_TicketAllocator *TicketAllocatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.TicketAllocatorTransactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_TicketAllocator *TicketAllocatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _TicketAllocator.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_TicketAllocator *TicketAllocatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_TicketAllocator *TicketAllocatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// GetBalance is a free data retrieval call binding the contract method 0xf8f8a912.
|
||||
//
|
||||
// Solidity: function GetBalance() view returns(address[], uint16[])
|
||||
func (_TicketAllocator *TicketAllocatorCaller) GetBalance(opts *bind.CallOpts) ([]common.Address, []uint16, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "GetBalance")
|
||||
|
||||
if err != nil {
|
||||
return *new([]common.Address), *new([]uint16), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
|
||||
out1 := *abi.ConvertType(out[1], new([]uint16)).(*[]uint16)
|
||||
|
||||
return out0, out1, err
|
||||
|
||||
}
|
||||
|
||||
// GetBalance is a free data retrieval call binding the contract method 0xf8f8a912.
|
||||
//
|
||||
// Solidity: function GetBalance() view returns(address[], uint16[])
|
||||
func (_TicketAllocator *TicketAllocatorSession) GetBalance() ([]common.Address, []uint16, error) {
|
||||
return _TicketAllocator.Contract.GetBalance(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// GetBalance is a free data retrieval call binding the contract method 0xf8f8a912.
|
||||
//
|
||||
// Solidity: function GetBalance() view returns(address[], uint16[])
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) GetBalance() ([]common.Address, []uint16, error) {
|
||||
return _TicketAllocator.Contract.GetBalance(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// TIMEOUT is a free data retrieval call binding the contract method 0xf56f48f2.
|
||||
//
|
||||
// Solidity: function TIMEOUT() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) TIMEOUT(opts *bind.CallOpts) (uint16, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "TIMEOUT")
|
||||
|
||||
if err != nil {
|
||||
return *new(uint16), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// TIMEOUT is a free data retrieval call binding the contract method 0xf56f48f2.
|
||||
//
|
||||
// Solidity: function TIMEOUT() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorSession) TIMEOUT() (uint16, error) {
|
||||
return _TicketAllocator.Contract.TIMEOUT(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// TIMEOUT is a free data retrieval call binding the contract method 0xf56f48f2.
|
||||
//
|
||||
// Solidity: function TIMEOUT() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) TIMEOUT() (uint16, error) {
|
||||
return _TicketAllocator.Contract.TIMEOUT(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// TOTALTICKETS is a free data retrieval call binding the contract method 0xafbd1782.
|
||||
//
|
||||
// Solidity: function TOTAL_TICKETS() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) TOTALTICKETS(opts *bind.CallOpts) (uint16, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "TOTAL_TICKETS")
|
||||
|
||||
if err != nil {
|
||||
return *new(uint16), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// TOTALTICKETS is a free data retrieval call binding the contract method 0xafbd1782.
|
||||
//
|
||||
// Solidity: function TOTAL_TICKETS() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorSession) TOTALTICKETS() (uint16, error) {
|
||||
return _TicketAllocator.Contract.TOTALTICKETS(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// TOTALTICKETS is a free data retrieval call binding the contract method 0xafbd1782.
|
||||
//
|
||||
// Solidity: function TOTAL_TICKETS() view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) TOTALTICKETS() (uint16, error) {
|
||||
return _TicketAllocator.Contract.TOTALTICKETS(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// Balance is a free data retrieval call binding the contract method 0xe3d670d7.
|
||||
//
|
||||
// Solidity: function balance(address ) view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) Balance(opts *bind.CallOpts, arg0 common.Address) (uint16, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "balance", arg0)
|
||||
|
||||
if err != nil {
|
||||
return *new(uint16), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// Balance is a free data retrieval call binding the contract method 0xe3d670d7.
|
||||
//
|
||||
// Solidity: function balance(address ) view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorSession) Balance(arg0 common.Address) (uint16, error) {
|
||||
return _TicketAllocator.Contract.Balance(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Balance is a free data retrieval call binding the contract method 0xe3d670d7.
|
||||
//
|
||||
// Solidity: function balance(address ) view returns(uint16)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) Balance(arg0 common.Address) (uint16, error) {
|
||||
return _TicketAllocator.Contract.Balance(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Head is a free data retrieval call binding the contract method 0xbda4fec5.
|
||||
//
|
||||
// Solidity: function head(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) Head(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "head", arg0)
|
||||
|
||||
if err != nil {
|
||||
return *new(*big.Int), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// Head is a free data retrieval call binding the contract method 0xbda4fec5.
|
||||
//
|
||||
// Solidity: function head(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorSession) Head(arg0 common.Address) (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.Head(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Head is a free data retrieval call binding the contract method 0xbda4fec5.
|
||||
//
|
||||
// Solidity: function head(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) Head(arg0 common.Address) (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.Head(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// PendingBids is a free data retrieval call binding the contract method 0xcf8589b9.
|
||||
//
|
||||
// Solidity: function pendingBids(uint256 ) view returns(address sender, address requestor, uint16 amount, uint256 bidPerTicket)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) PendingBids(opts *bind.CallOpts, arg0 *big.Int) (struct {
|
||||
Sender common.Address
|
||||
Requestor common.Address
|
||||
Amount uint16
|
||||
BidPerTicket *big.Int
|
||||
}, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "pendingBids", arg0)
|
||||
|
||||
outstruct := new(struct {
|
||||
Sender common.Address
|
||||
Requestor common.Address
|
||||
Amount uint16
|
||||
BidPerTicket *big.Int
|
||||
})
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
|
||||
outstruct.Sender = *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||
outstruct.Requestor = *abi.ConvertType(out[1], new(common.Address)).(*common.Address)
|
||||
outstruct.Amount = *abi.ConvertType(out[2], new(uint16)).(*uint16)
|
||||
outstruct.BidPerTicket = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int)
|
||||
|
||||
return *outstruct, err
|
||||
|
||||
}
|
||||
|
||||
// PendingBids is a free data retrieval call binding the contract method 0xcf8589b9.
|
||||
//
|
||||
// Solidity: function pendingBids(uint256 ) view returns(address sender, address requestor, uint16 amount, uint256 bidPerTicket)
|
||||
func (_TicketAllocator *TicketAllocatorSession) PendingBids(arg0 *big.Int) (struct {
|
||||
Sender common.Address
|
||||
Requestor common.Address
|
||||
Amount uint16
|
||||
BidPerTicket *big.Int
|
||||
}, error) {
|
||||
return _TicketAllocator.Contract.PendingBids(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// PendingBids is a free data retrieval call binding the contract method 0xcf8589b9.
|
||||
//
|
||||
// Solidity: function pendingBids(uint256 ) view returns(address sender, address requestor, uint16 amount, uint256 bidPerTicket)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) PendingBids(arg0 *big.Int) (struct {
|
||||
Sender common.Address
|
||||
Requestor common.Address
|
||||
Amount uint16
|
||||
BidPerTicket *big.Int
|
||||
}, error) {
|
||||
return _TicketAllocator.Contract.PendingBids(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// PendingBlock is a free data retrieval call binding the contract method 0xd33d9969.
|
||||
//
|
||||
// Solidity: function pendingBlock() view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) PendingBlock(opts *bind.CallOpts) (*big.Int, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "pendingBlock")
|
||||
|
||||
if err != nil {
|
||||
return *new(*big.Int), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// PendingBlock is a free data retrieval call binding the contract method 0xd33d9969.
|
||||
//
|
||||
// Solidity: function pendingBlock() view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorSession) PendingBlock() (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.PendingBlock(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// PendingBlock is a free data retrieval call binding the contract method 0xd33d9969.
|
||||
//
|
||||
// Solidity: function pendingBlock() view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) PendingBlock() (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.PendingBlock(&_TicketAllocator.CallOpts)
|
||||
}
|
||||
|
||||
// Queue is a free data retrieval call binding the contract method 0x44287113.
|
||||
//
|
||||
// Solidity: function queue(address , uint256 ) view returns(uint16 amount, uint256 blockNumber, uint256 bidPerTicket, address requestor)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) Queue(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (struct {
|
||||
Amount uint16
|
||||
BlockNumber *big.Int
|
||||
BidPerTicket *big.Int
|
||||
Requestor common.Address
|
||||
}, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "queue", arg0, arg1)
|
||||
|
||||
outstruct := new(struct {
|
||||
Amount uint16
|
||||
BlockNumber *big.Int
|
||||
BidPerTicket *big.Int
|
||||
Requestor common.Address
|
||||
})
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
|
||||
outstruct.Amount = *abi.ConvertType(out[0], new(uint16)).(*uint16)
|
||||
outstruct.BlockNumber = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
|
||||
outstruct.BidPerTicket = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int)
|
||||
outstruct.Requestor = *abi.ConvertType(out[3], new(common.Address)).(*common.Address)
|
||||
|
||||
return *outstruct, err
|
||||
|
||||
}
|
||||
|
||||
// Queue is a free data retrieval call binding the contract method 0x44287113.
|
||||
//
|
||||
// Solidity: function queue(address , uint256 ) view returns(uint16 amount, uint256 blockNumber, uint256 bidPerTicket, address requestor)
|
||||
func (_TicketAllocator *TicketAllocatorSession) Queue(arg0 common.Address, arg1 *big.Int) (struct {
|
||||
Amount uint16
|
||||
BlockNumber *big.Int
|
||||
BidPerTicket *big.Int
|
||||
Requestor common.Address
|
||||
}, error) {
|
||||
return _TicketAllocator.Contract.Queue(&_TicketAllocator.CallOpts, arg0, arg1)
|
||||
}
|
||||
|
||||
// Queue is a free data retrieval call binding the contract method 0x44287113.
|
||||
//
|
||||
// Solidity: function queue(address , uint256 ) view returns(uint16 amount, uint256 blockNumber, uint256 bidPerTicket, address requestor)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) Queue(arg0 common.Address, arg1 *big.Int) (struct {
|
||||
Amount uint16
|
||||
BlockNumber *big.Int
|
||||
BidPerTicket *big.Int
|
||||
Requestor common.Address
|
||||
}, error) {
|
||||
return _TicketAllocator.Contract.Queue(&_TicketAllocator.CallOpts, arg0, arg1)
|
||||
}
|
||||
|
||||
// Senders is a free data retrieval call binding the contract method 0x9977c78a.
|
||||
//
|
||||
// Solidity: function senders(uint256 ) view returns(address)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) Senders(opts *bind.CallOpts, arg0 *big.Int) (common.Address, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "senders", arg0)
|
||||
|
||||
if err != nil {
|
||||
return *new(common.Address), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// Senders is a free data retrieval call binding the contract method 0x9977c78a.
|
||||
//
|
||||
// Solidity: function senders(uint256 ) view returns(address)
|
||||
func (_TicketAllocator *TicketAllocatorSession) Senders(arg0 *big.Int) (common.Address, error) {
|
||||
return _TicketAllocator.Contract.Senders(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Senders is a free data retrieval call binding the contract method 0x9977c78a.
|
||||
//
|
||||
// Solidity: function senders(uint256 ) view returns(address)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) Senders(arg0 *big.Int) (common.Address, error) {
|
||||
return _TicketAllocator.Contract.Senders(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Withdrawable is a free data retrieval call binding the contract method 0xce513b6f.
|
||||
//
|
||||
// Solidity: function withdrawable(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCaller) Withdrawable(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) {
|
||||
var out []interface{}
|
||||
err := _TicketAllocator.contract.Call(opts, &out, "withdrawable", arg0)
|
||||
|
||||
if err != nil {
|
||||
return *new(*big.Int), err
|
||||
}
|
||||
|
||||
out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
|
||||
|
||||
return out0, err
|
||||
|
||||
}
|
||||
|
||||
// Withdrawable is a free data retrieval call binding the contract method 0xce513b6f.
|
||||
//
|
||||
// Solidity: function withdrawable(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorSession) Withdrawable(arg0 common.Address) (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.Withdrawable(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// Withdrawable is a free data retrieval call binding the contract method 0xce513b6f.
|
||||
//
|
||||
// Solidity: function withdrawable(address ) view returns(uint256)
|
||||
func (_TicketAllocator *TicketAllocatorCallerSession) Withdrawable(arg0 common.Address) (*big.Int, error) {
|
||||
return _TicketAllocator.Contract.Withdrawable(&_TicketAllocator.CallOpts, arg0)
|
||||
}
|
||||
|
||||
// RequestTickets is a paid mutator transaction binding the contract method 0x91ef4c9d.
|
||||
//
|
||||
// Solidity: function RequestTickets(address sender, uint16 numTickets, uint256 bidPerTicket) payable returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactor) RequestTickets(opts *bind.TransactOpts, sender common.Address, numTickets uint16, bidPerTicket *big.Int) (*types.Transaction, error) {
|
||||
return _TicketAllocator.contract.Transact(opts, "RequestTickets", sender, numTickets, bidPerTicket)
|
||||
}
|
||||
|
||||
// RequestTickets is a paid mutator transaction binding the contract method 0x91ef4c9d.
|
||||
//
|
||||
// Solidity: function RequestTickets(address sender, uint16 numTickets, uint256 bidPerTicket) payable returns()
|
||||
func (_TicketAllocator *TicketAllocatorSession) RequestTickets(sender common.Address, numTickets uint16, bidPerTicket *big.Int) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.RequestTickets(&_TicketAllocator.TransactOpts, sender, numTickets, bidPerTicket)
|
||||
}
|
||||
|
||||
// RequestTickets is a paid mutator transaction binding the contract method 0x91ef4c9d.
|
||||
//
|
||||
// Solidity: function RequestTickets(address sender, uint16 numTickets, uint256 bidPerTicket) payable returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactorSession) RequestTickets(sender common.Address, numTickets uint16, bidPerTicket *big.Int) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.RequestTickets(&_TicketAllocator.TransactOpts, sender, numTickets, bidPerTicket)
|
||||
}
|
||||
|
||||
// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b.
|
||||
//
|
||||
// Solidity: function withdraw() returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactor) Withdraw(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _TicketAllocator.contract.Transact(opts, "withdraw")
|
||||
}
|
||||
|
||||
// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b.
|
||||
//
|
||||
// Solidity: function withdraw() returns()
|
||||
func (_TicketAllocator *TicketAllocatorSession) Withdraw() (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.Withdraw(&_TicketAllocator.TransactOpts)
|
||||
}
|
||||
|
||||
// Withdraw is a paid mutator transaction binding the contract method 0x3ccfd60b.
|
||||
//
|
||||
// Solidity: function withdraw() returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactorSession) Withdraw() (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.Withdraw(&_TicketAllocator.TransactOpts)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: fallback() returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||
return _TicketAllocator.contract.RawTransact(opts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: fallback() returns()
|
||||
func (_TicketAllocator *TicketAllocatorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.Fallback(&_TicketAllocator.TransactOpts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: fallback() returns()
|
||||
func (_TicketAllocator *TicketAllocatorTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _TicketAllocator.Contract.Fallback(&_TicketAllocator.TransactOpts, calldata)
|
||||
}
|
||||
|
|
@ -6,67 +6,168 @@ contract TicketAllocator {
|
|||
|
||||
error NotEnoughTickets();
|
||||
error NotSystemContract();
|
||||
error InvalidPayment();
|
||||
|
||||
struct Ticket {
|
||||
uint16 amount;
|
||||
uint256 blockNumber;
|
||||
uint256 bidPerTicket;
|
||||
address requestor; // address that requested the tickets
|
||||
}
|
||||
|
||||
struct PendingBid {
|
||||
address sender;
|
||||
address requestor; // address that called RequestTickets
|
||||
uint16 amount;
|
||||
uint256 bidPerTicket;
|
||||
}
|
||||
|
||||
mapping(address => Ticket[]) public queue;
|
||||
mapping(address => uint256) public head;
|
||||
mapping(address => uint16) public balance;
|
||||
mapping(address => uint256) public withdrawable; // amount available for withdrawal
|
||||
|
||||
address[] public senders; // list of senders with >0 balance
|
||||
|
||||
uint16 public constant TOTAL_TICKETS = 21;
|
||||
uint16 public constant TIMEOUT = 2;
|
||||
|
||||
uint256 private leftTickets;
|
||||
uint256 private lastRequestBlock;
|
||||
|
||||
function requestTickets(address sender, uint16 numTickets) external {
|
||||
uint256 currentBlock = block.number;
|
||||
PendingBid[] public pendingBids;
|
||||
uint256 public pendingBlock;
|
||||
|
||||
if (currentBlock != lastRequestBlock) {
|
||||
leftTickets = TOTAL_TICKETS;
|
||||
lastRequestBlock = currentBlock;
|
||||
function GetBalance() public view returns (address[] memory, uint16[] memory){
|
||||
uint16[] memory res;
|
||||
res = new uint16[](senders.length);
|
||||
for (uint256 i = 0; i < senders.length; i++) {
|
||||
res[i] = balance[senders[i]];
|
||||
}
|
||||
return (senders, res);
|
||||
}
|
||||
|
||||
function _addModified(
|
||||
address sender,
|
||||
address[] memory modified,
|
||||
uint256 modifiedCount
|
||||
) private pure returns (uint256) {
|
||||
for (uint256 i = 0; i < modifiedCount; i++) {
|
||||
if (modified[i] == sender) {
|
||||
return modifiedCount;
|
||||
}
|
||||
}
|
||||
modified[modifiedCount] = sender;
|
||||
return modifiedCount + 1;
|
||||
}
|
||||
|
||||
function RequestTickets(address sender, uint16 numTickets, uint256 bidPerTicket) external payable {
|
||||
// Check payment matches the declared bid
|
||||
if (msg.value != uint256(numTickets) * bidPerTicket) {
|
||||
revert InvalidPayment();
|
||||
}
|
||||
|
||||
if (numTickets > leftTickets) {
|
||||
revert NotEnoughTickets();
|
||||
// Reset pending bids if we moved to a new block
|
||||
if (block.number != pendingBlock) {
|
||||
delete pendingBids;
|
||||
pendingBlock = block.number;
|
||||
}
|
||||
|
||||
if (balance[sender] == 0) {
|
||||
senders.push(sender);
|
||||
}
|
||||
|
||||
queue[sender].push(Ticket({
|
||||
pendingBids.push(PendingBid({
|
||||
sender: sender,
|
||||
requestor: msg.sender,
|
||||
amount: numTickets,
|
||||
blockNumber: currentBlock
|
||||
bidPerTicket: bidPerTicket
|
||||
}));
|
||||
|
||||
balance[sender] += numTickets;
|
||||
leftTickets -= numTickets;
|
||||
}
|
||||
|
||||
function checkBalance(address sender) public view returns(uint) {
|
||||
return balance[sender];
|
||||
function withdraw() external {
|
||||
uint256 amount = withdrawable[msg.sender];
|
||||
if (amount == 0) {
|
||||
return;
|
||||
}
|
||||
withdrawable[msg.sender] = 0;
|
||||
(bool success, ) = payable(msg.sender).call{value: amount}("");
|
||||
require(success, "withdrawal failed");
|
||||
}
|
||||
|
||||
|
||||
// System call:
|
||||
// 1. remove expired and used tickets
|
||||
// - for used tickets, the oldest ticket is removed first
|
||||
// 3. return the overall sender balances
|
||||
// 1. allocate tickets for this block based on bids
|
||||
// 2. process used and expired tickets, refunding bids for used tickets
|
||||
// 3. return modified addresses and their balances
|
||||
fallback(bytes calldata input) external returns (bytes memory) {
|
||||
if (msg.sender != SYSTEM_ADDRESS) revert NotSystemContract();
|
||||
|
||||
address[] memory usedSenders;
|
||||
uint16[] memory usedAmounts;
|
||||
|
||||
|
||||
if (input.length > 0) {
|
||||
(usedSenders, usedAmounts) = abi.decode(input, (address[], uint16[]));
|
||||
}
|
||||
|
||||
// Track modified addresses for this system call
|
||||
address[] memory modified = new address[](senders.length + pendingBids.length);
|
||||
uint256 modifiedCount = 0;
|
||||
|
||||
// Step 1: allocate tickets for this block based on bids
|
||||
if (pendingBlock == block.number && pendingBids.length > 0) {
|
||||
// Sort pending bids by bidPerTicket in descending order (bubble sort on storage)
|
||||
uint256 n = pendingBids.length;
|
||||
for (uint256 i = 0; i < n; i++) {
|
||||
for (uint256 j = i + 1; j < n; j++) {
|
||||
if (pendingBids[j].bidPerTicket > pendingBids[i].bidPerTicket) {
|
||||
PendingBid memory tmp = pendingBids[i];
|
||||
pendingBids[i] = pendingBids[j];
|
||||
pendingBids[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16 remaining = TOTAL_TICKETS;
|
||||
|
||||
for (uint256 i = 0; i < n; i++) {
|
||||
PendingBid storage bid = pendingBids[i];
|
||||
if (bid.amount == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16 alloc = bid.amount;
|
||||
if (alloc > remaining) {
|
||||
alloc = remaining;
|
||||
}
|
||||
|
||||
if (alloc > 0) {
|
||||
// Allocate tickets and keep the payment locked until used or expired
|
||||
if (balance[bid.sender] == 0) {
|
||||
senders.push(bid.sender);
|
||||
}
|
||||
queue[bid.sender].push(Ticket({
|
||||
amount: alloc,
|
||||
blockNumber: block.number,
|
||||
bidPerTicket: bid.bidPerTicket,
|
||||
requestor: bid.requestor
|
||||
}));
|
||||
balance[bid.sender] += alloc;
|
||||
remaining -= alloc;
|
||||
|
||||
// mark modified
|
||||
modifiedCount = _addModified(bid.sender, modified, modifiedCount);
|
||||
|
||||
// Add unallocated portion to withdrawal, if any
|
||||
if (bid.amount > alloc) {
|
||||
uint16 unfilled = bid.amount - alloc;
|
||||
uint256 refund = uint256(unfilled) * bid.bidPerTicket;
|
||||
withdrawable[bid.requestor] += refund;
|
||||
}
|
||||
} else {
|
||||
// No tickets left, full refund to withdrawal
|
||||
uint256 refundAll = uint256(bid.amount) * bid.bidPerTicket;
|
||||
withdrawable[bid.requestor] += refundAll;
|
||||
}
|
||||
}
|
||||
|
||||
delete pendingBids;
|
||||
pendingBlock = 0;
|
||||
}
|
||||
|
||||
// Step 2: process used and expired tickets, refunding bids for used tickets
|
||||
for (uint256 s = 0; s < senders.length; ) {
|
||||
address sender = senders[s];
|
||||
Ticket[] storage senderQueue = queue[sender];
|
||||
|
|
@ -89,23 +190,29 @@ contract TicketAllocator {
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Expired tickets: burn the funds paid for these tickets
|
||||
if (ticket.blockNumber + TIMEOUT < block.number) {
|
||||
// remove expired tickets (comsume used tickets if possible)
|
||||
balance[sender] -= ticket.amount;
|
||||
if (used > 0) {
|
||||
// used = max(0, used - t.amount)
|
||||
uint16 deduct = used > ticket.amount ? ticket.amount : used;
|
||||
used -= deduct;
|
||||
}
|
||||
ticket.amount = 0;
|
||||
senderHead++;
|
||||
|
||||
// Burn by sending to address(0)
|
||||
(bool success, ) = payable(address(0)).call{value: ticket.amount * ticket.bidPerTicket}("");
|
||||
require(success, "burn failed");
|
||||
|
||||
// mark modified
|
||||
modifiedCount = _addModified(sender, modified, modifiedCount);
|
||||
} else if (used > 0) {
|
||||
// remove used ticekts (for now we don't revert when the ticket amount is less than used tickets)
|
||||
// Used tickets: add refund to withdrawal for the requestor
|
||||
uint16 deduct = used > ticket.amount ? ticket.amount : used;
|
||||
ticket.amount -= uint16(deduct);
|
||||
ticket.amount -= deduct;
|
||||
balance[sender] -= deduct;
|
||||
used -= deduct;
|
||||
uint256 refund = uint256(deduct) * ticket.bidPerTicket;
|
||||
withdrawable[ticket.requestor] += refund;
|
||||
|
||||
// mark modified
|
||||
modifiedCount = _addModified(sender, modified, modifiedCount);
|
||||
|
||||
if (ticket.amount == 0) senderHead++;
|
||||
} else {
|
||||
|
|
@ -124,15 +231,13 @@ contract TicketAllocator {
|
|||
s++;
|
||||
}
|
||||
|
||||
// return the active senders and their balances
|
||||
address[] memory activeSenders = new address[](senders.length);
|
||||
uint16[] memory activeBalances = new uint16[](senders.length);
|
||||
|
||||
for (uint256 i = 0; i < senders.length; i++) {
|
||||
activeSenders[i] = senders[i];
|
||||
activeBalances[i] = balance[senders[i]];
|
||||
// Step 3: return modified addresses and their balances
|
||||
address[] memory modifiedAddress = new address[](modifiedCount);
|
||||
uint16[] memory modifiedTickets = new uint16[](modifiedCount);
|
||||
for (uint256 i = 0; i < modifiedCount; i++) {
|
||||
modifiedAddress[i] = modified[i];
|
||||
modifiedTickets[i] = balance[modified[i]];
|
||||
}
|
||||
|
||||
return abi.encode(activeSenders, activeBalances);
|
||||
return abi.encode(modifiedAddress, modifiedTickets);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2280,22 +2280,18 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
|||
}
|
||||
|
||||
// Add ticket balances of this block and remove the parent block data
|
||||
bc.tickets[block.Hash()] = res.Tickets
|
||||
if _, ok := bc.ticketBlocks[block.Number()]; !ok {
|
||||
bc.ticketBlocks[block.Number()] = make([]common.Hash, 0)
|
||||
}
|
||||
bc.ticketBlocks[block.Number()] = append(bc.ticketBlocks[block.Number()], block.Hash())
|
||||
|
||||
if _, ok := bc.tickets[block.ParentHash()]; ok {
|
||||
if parent, ok := bc.tickets[block.ParentHash()]; ok {
|
||||
delete(bc.tickets, block.ParentHash())
|
||||
if hashes := bc.ticketBlocks[block.Number().Sub(block.Number(), big.NewInt(1))]; len(hashes) != 0 {
|
||||
for i, hash := range hashes {
|
||||
if hash.Cmp(block.ParentHash()) == 0 {
|
||||
hashes[i] = hashes[len(hashes)-1]
|
||||
hashes = hashes[:len(hashes)-1]
|
||||
}
|
||||
bc.tickets[block.Hash()] = parent
|
||||
for addr, value := range res.Tickets {
|
||||
if value == 0 {
|
||||
delete(bc.tickets[block.Hash()], addr)
|
||||
}
|
||||
bc.tickets[block.Hash()][addr] = value
|
||||
}
|
||||
} else {
|
||||
res, _ := bc.GetTicketBalance(block.Header())
|
||||
bc.tickets[block.Hash()] = res
|
||||
}
|
||||
|
||||
// Report the collected witness statistics
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
|
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -354,33 +354,43 @@ func (bc *BlockChain) GetCanonicalTransaction(hash common.Hash) (*rawdb.LegacyTx
|
|||
return lookup, tx
|
||||
}
|
||||
|
||||
func (bc *BlockChain) GetTicketBalance(hash common.Hash, statedb *state.StateDB) map[common.Address]uint16 {
|
||||
if bc.tickets[hash] != nil {
|
||||
return bc.tickets[hash]
|
||||
func (bc *BlockChain) GetTicketBalance(header *types.Header) (map[common.Address]uint16, error) {
|
||||
if bc.tickets[header.Hash()] != nil {
|
||||
return bc.tickets[header.Hash()], nil
|
||||
}
|
||||
|
||||
ctx := NewEVMBlockContext(header, bc.HeaderChain(), nil)
|
||||
statedb, err := bc.StateAt(header.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
evm := vm.NewEVM(ctx, statedb, bc.chainConfig, bc.cfg.VmConfig)
|
||||
cc := contractCaller{addr: params.BlobTicketAllocationAddress, evm: evm}
|
||||
caller, err := NewTicketAllocatorCaller(params.BlobTicketAllocationAddress, cc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
senders, balances, err := caller.GetBalance(&bind.CallOpts{BlockNumber: header.Number})
|
||||
if err != nil {
|
||||
// when the contract is not deployed, return empty map
|
||||
if errors.Is(err, bind.ErrNoCode) {
|
||||
result := make(map[common.Address]uint16)
|
||||
bc.tickets[header.Hash()] = result
|
||||
return result, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[common.Address]uint16)
|
||||
|
||||
senders := statedb.GetState(params.BlobTicketAllocationAddress, common.BigToHash(params.BlobTicketSenderSlot)).Big().Int64()
|
||||
base := crypto.Keccak256Hash(common.LeftPadBytes(params.BlobTicketSenderSlot.Bytes(), 32)).Big()
|
||||
|
||||
for i := range senders {
|
||||
key := common.BigToHash(base.Add(base, big.NewInt(i)))
|
||||
sender := common.BytesToAddress(statedb.GetState(params.BlobTicketAllocationAddress, key).Bytes())
|
||||
|
||||
key = crypto.Keccak256Hash(
|
||||
append(
|
||||
common.LeftPadBytes(sender.Bytes(), 32),
|
||||
common.LeftPadBytes(params.BlobTicketBalanceSlot.Bytes(), 32)...,
|
||||
),
|
||||
)
|
||||
|
||||
balance := statedb.GetState(params.BlobTicketAllocationAddress, key).Big().Uint64()
|
||||
|
||||
result[sender] = uint16(balance)
|
||||
for i, sender := range senders {
|
||||
result[sender] = uint16(balances[i])
|
||||
}
|
||||
bc.tickets[header.Hash()] = result
|
||||
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TxIndexDone returns true if the transaction indexer has finished indexing.
|
||||
|
|
|
|||
|
|
@ -4211,11 +4211,12 @@ func TestBlobTickets(t *testing.T) {
|
|||
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 4, func(i int, bg *BlockGen) {
|
||||
switch i {
|
||||
case 0: // create ticket request
|
||||
selector := crypto.Keccak256([]byte("requestTickets(address,uint16)"))[:4]
|
||||
selector := crypto.Keccak256([]byte("RequestTickets(address,uint16,uint256)"))[:4]
|
||||
uint16Type, _ := abi.NewType("uint16", "", nil)
|
||||
addressType, _ := abi.NewType("address", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}}
|
||||
data, _ := args.Pack(addr1, ticketAmount)
|
||||
uint256Type, _ := abi.NewType("uint256", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}, {Type: uint256Type}}
|
||||
data, _ := args.Pack(addr1, ticketAmount, big.NewInt(1))
|
||||
|
||||
data = append(selector, data...)
|
||||
|
||||
|
|
@ -4227,6 +4228,7 @@ func TestBlobTickets(t *testing.T) {
|
|||
GasFeeCap: big.NewInt(875000000),
|
||||
GasTipCap: big.NewInt(1),
|
||||
Data: data,
|
||||
Value: big.NewInt(int64(ticketAmount)),
|
||||
}
|
||||
tx := types.MustSignNewTx(key1, signer, txdata)
|
||||
|
||||
|
|
@ -4297,15 +4299,13 @@ func TestBlobTickets(t *testing.T) {
|
|||
}
|
||||
|
||||
// previous block ticket balance
|
||||
state, _ := chain.StateAt(blocks[0].Root())
|
||||
balance = chain.GetTicketBalance(blocks[0].Hash(), state)
|
||||
balance, _ = chain.GetTicketBalance(blocks[0].Header())
|
||||
amount = balance[addr1]
|
||||
if amount != ticketAmount {
|
||||
t.Fatalf("wrong ticket amount: expected %d, got %d", ticketAmount, amount)
|
||||
}
|
||||
|
||||
state, _ = chain.StateAt(blocks[1].Root())
|
||||
balance = chain.GetTicketBalance(blocks[1].Hash(), state)
|
||||
balance, _ = chain.GetTicketBalance(blocks[1].Header())
|
||||
amount = balance[addr1]
|
||||
if amount != ticketAmount-1 {
|
||||
t.Fatalf("wrong ticket amount: expected %d, got %d", ticketAmount-1, amount)
|
||||
|
|
|
|||
45
core/contract_caller.go
Normal file
45
core/contract_caller.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type contractCaller struct {
|
||||
evm *vm.EVM
|
||||
addr common.Address
|
||||
}
|
||||
|
||||
func (c contractCaller) CodeAt(ctx context.Context, addr common.Address, blockNumber *big.Int) ([]byte, error) {
|
||||
return c.evm.StateDB.GetCode(addr), nil
|
||||
}
|
||||
|
||||
func (c contractCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
|
||||
value := new(uint256.Int)
|
||||
if call.Value != nil {
|
||||
value.SetFromBig(call.Value)
|
||||
}
|
||||
|
||||
from := call.From
|
||||
if from == (common.Address{}) {
|
||||
from = params.SystemAddress
|
||||
}
|
||||
|
||||
// when gas is set to zero, it should use nearly infinite gas,
|
||||
// according to the CallMsg definition
|
||||
gas := call.Gas
|
||||
if gas == 0 {
|
||||
gas = uint64(math.MaxUint64)
|
||||
}
|
||||
|
||||
res, _, err := c.evm.Call(from, c.addr, call.Data, gas, value)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -384,9 +385,17 @@ func ProcessTickets(usedAddress []common.Address, usedAmount []uint16, evm *vm.E
|
|||
}
|
||||
evm.SetTxContext(NewEVMTxContext(msg))
|
||||
|
||||
res, _, _ := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||
res, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||
|
||||
evm.StateDB.Finalise(true)
|
||||
if err != nil {
|
||||
log.Error("system call failed to execute", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return make(map[common.Address]uint16)
|
||||
}
|
||||
|
||||
arguments := abi.Arguments{
|
||||
{Type: addressType},
|
||||
|
|
|
|||
|
|
@ -419,7 +419,10 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reser
|
|||
p.head.Store(head)
|
||||
p.state = state
|
||||
|
||||
p.tickets = p.chain.GetTicketBalance(head.Hash(), state)
|
||||
p.tickets, err = p.chain.GetTicketBalance(head)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create new slotter for pre-Osaka blob configuration.
|
||||
slotter := newSlotter(params.BlobTxMaxBlobs)
|
||||
|
|
@ -862,8 +865,11 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
|||
p.head.Store(newHead)
|
||||
p.state = statedb
|
||||
|
||||
p.tickets = p.chain.GetTicketBalance(newHead.Hash(), p.state)
|
||||
|
||||
p.tickets, err = p.chain.GetTicketBalance(newHead)
|
||||
if err != nil {
|
||||
log.Error("Failed to get ticket balances", "err", err)
|
||||
return
|
||||
}
|
||||
// Run the reorg between the old and new head and figure out which accounts
|
||||
// need to be rechecked and which transactions need to be readded
|
||||
if reinject, inclusions := p.reorg(oldHead, newHead); reinject != nil {
|
||||
|
|
|
|||
|
|
@ -186,8 +186,8 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
|||
return bc.statedb, nil
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) GetTicketBalance(common.Hash, *state.StateDB) map[common.Address]uint16 {
|
||||
return bc.tickets
|
||||
func (bc *testBlockChain) GetTicketBalance(*types.Header) (map[common.Address]uint16, error) {
|
||||
return bc.tickets, nil
|
||||
}
|
||||
|
||||
// reserver is a utility struct to sanity check that accounts are
|
||||
|
|
|
|||
|
|
@ -42,5 +42,5 @@ type BlockChain interface {
|
|||
// StateAt returns a state database for a given root hash (generally the head).
|
||||
StateAt(root common.Hash) (*state.StateDB, error)
|
||||
|
||||
GetTicketBalance(hash common.Hash, statedb *state.StateDB) map[common.Address]uint16
|
||||
GetTicketBalance(header *types.Header) (map[common.Address]uint16, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1916,11 +1916,12 @@ func newGetBlobEnv(t testing.TB, version byte) (*node.Node, *ConsensusAPI) {
|
|||
{addr3, key3},
|
||||
}
|
||||
for _, signer := range signers {
|
||||
selector := crypto.Keccak256([]byte("requestTickets(address,uint16)"))[:4]
|
||||
selector := crypto.Keccak256([]byte("RequestTickets(address,uint16,uint256)"))[:4]
|
||||
uint16Type, _ := abi.NewType("uint16", "", nil)
|
||||
addressType, _ := abi.NewType("address", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}}
|
||||
data, _ := args.Pack(signer.addr, uint16(2))
|
||||
uint256Type, _ := abi.NewType("uint256", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}, {Type: uint256Type}}
|
||||
data, _ := args.Pack(signer.addr, uint16(2), big.NewInt(1))
|
||||
data = append(selector, data...)
|
||||
|
||||
txdata := &types.DynamicFeeTx{
|
||||
|
|
@ -1931,12 +1932,12 @@ func newGetBlobEnv(t testing.TB, version byte) (*node.Node, *ConsensusAPI) {
|
|||
GasFeeCap: big.NewInt(params.InitialBaseFee * 2),
|
||||
GasTipCap: big.NewInt(params.GWei),
|
||||
Data: data,
|
||||
Value: big.NewInt(2),
|
||||
}
|
||||
tx := types.MustSignNewTx(signer.key, types.LatestSigner(&config), txdata)
|
||||
b.AddTx(tx)
|
||||
}
|
||||
})
|
||||
|
||||
n, ethServ := startEthService(t, gspec, ticketBlocks)
|
||||
|
||||
// fill blob txs into the pool
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||
|
|
@ -74,8 +73,8 @@ type testChain struct {
|
|||
*core.BlockChain
|
||||
}
|
||||
|
||||
func (c *testChain) GetTicketBalance(hash common.Hash, statedb *state.StateDB) map[common.Address]uint16 {
|
||||
return map[common.Address]uint16{testAddr: 1000}
|
||||
func (c *testChain) GetTicketBalance(header *types.Header) (map[common.Address]uint16, error) {
|
||||
return map[common.Address]uint16{testAddr: 1000}, nil
|
||||
}
|
||||
|
||||
// newTestBackendWithGenerator creates a chain with a number of explicitly defined blocks and
|
||||
|
|
|
|||
|
|
@ -100,11 +100,12 @@ func allocateTickets(t *testing.T, key *ecdsa.PrivateKey, sim *Backend, nonce ui
|
|||
chainid, _ := client.ChainID(ctx)
|
||||
signer := types.LatestSignerForChainID(chainid)
|
||||
|
||||
selector := crypto.Keccak256([]byte("requestTickets(address,uint16)"))[:4]
|
||||
selector := crypto.Keccak256([]byte("RequestTickets(address,uint16,uint256)"))[:4]
|
||||
uint16Type, _ := abi.NewType("uint16", "", nil)
|
||||
addressType, _ := abi.NewType("address", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}}
|
||||
data, _ := args.Pack(addr, amount)
|
||||
uint256Type, _ := abi.NewType("uint256", "", nil)
|
||||
args := abi.Arguments{{Type: addressType}, {Type: uint16Type}, {Type: uint256Type}}
|
||||
data, _ := args.Pack(addr, amount, big.NewInt(1))
|
||||
data = append(selector, data...)
|
||||
|
||||
// Get current head
|
||||
|
|
@ -118,6 +119,7 @@ func allocateTickets(t *testing.T, key *ecdsa.PrivateKey, sim *Backend, nonce ui
|
|||
GasFeeCap: new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei)),
|
||||
GasTipCap: big.NewInt(params.GWei),
|
||||
Data: data,
|
||||
Value: big.NewInt(int64(amount)),
|
||||
}
|
||||
tx := types.MustSignNewTx(key, signer, txdata)
|
||||
|
||||
|
|
|
|||
|
|
@ -169,8 +169,8 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil {
|
||||
return &newPayloadResult{err: err}
|
||||
}
|
||||
core.ProcessTickets(work.usedAddress, work.usedAmount, work.evm)
|
||||
}
|
||||
core.ProcessTickets(work.usedAddress, work.usedAmount, work.evm)
|
||||
|
||||
if requests != nil {
|
||||
reqHash := types.CalcRequestsHash(requests)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue