mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Merge branch 'master' into les-test
This commit is contained in:
commit
0158889e7d
12 changed files with 278 additions and 67 deletions
|
|
@ -39,7 +39,7 @@ directory.
|
|||
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI Wiki page](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options) for command line options. |
|
||||
| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) wiki page for details. |
|
||||
| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. |
|
||||
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
|
||||
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). |
|
||||
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
|
||||
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
|
||||
| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. |
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ type RetestethEthAPI interface {
|
|||
SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error)
|
||||
BlockNumber(ctx context.Context) (uint64, error)
|
||||
GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error)
|
||||
GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error)
|
||||
GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error)
|
||||
GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error)
|
||||
GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error)
|
||||
|
|
@ -618,6 +619,20 @@ func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexO
|
|||
return nil, fmt.Errorf("block %d not found", blockNr)
|
||||
}
|
||||
|
||||
func (api *RetestethAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||
block := api.blockchain.GetBlockByHash(blockHash)
|
||||
if block != nil {
|
||||
response, err := RPCMarshalBlock(block, true, fullTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response["author"] = response["miner"]
|
||||
response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), block.Number().Uint64()))
|
||||
return response, err
|
||||
}
|
||||
return nil, fmt.Errorf("block 0x%x not found", blockHash)
|
||||
}
|
||||
|
||||
func (api *RetestethAPI) AccountRange(ctx context.Context,
|
||||
blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
|
||||
addressHash *math.HexOrDecimal256, maxResults uint64,
|
||||
|
|
|
|||
|
|
@ -31,44 +31,93 @@ func Now() AbsTime {
|
|||
return AbsTime(monotime.Now())
|
||||
}
|
||||
|
||||
// Add returns t + d.
|
||||
// Add returns t + d as absolute time.
|
||||
func (t AbsTime) Add(d time.Duration) AbsTime {
|
||||
return t + AbsTime(d)
|
||||
}
|
||||
|
||||
// Sub returns t - t2 as a duration.
|
||||
func (t AbsTime) Sub(t2 AbsTime) time.Duration {
|
||||
return time.Duration(t - t2)
|
||||
}
|
||||
|
||||
// The Clock interface makes it possible to replace the monotonic system clock with
|
||||
// a simulated clock.
|
||||
type Clock interface {
|
||||
Now() AbsTime
|
||||
Sleep(time.Duration)
|
||||
After(time.Duration) <-chan time.Time
|
||||
NewTimer(time.Duration) ChanTimer
|
||||
After(time.Duration) <-chan AbsTime
|
||||
AfterFunc(d time.Duration, f func()) Timer
|
||||
}
|
||||
|
||||
// Timer represents a cancellable event returned by AfterFunc
|
||||
// Timer is a cancellable event created by AfterFunc.
|
||||
type Timer interface {
|
||||
// Stop cancels the timer. It returns false if the timer has already
|
||||
// expired or been stopped.
|
||||
Stop() bool
|
||||
}
|
||||
|
||||
// ChanTimer is a cancellable event created by NewTimer.
|
||||
type ChanTimer interface {
|
||||
Timer
|
||||
|
||||
// The channel returned by C receives a value when the timer expires.
|
||||
C() <-chan AbsTime
|
||||
// Reset reschedules the timer with a new timeout.
|
||||
// It should be invoked only on stopped or expired timers with drained channels.
|
||||
Reset(time.Duration)
|
||||
}
|
||||
|
||||
// System implements Clock using the system clock.
|
||||
type System struct{}
|
||||
|
||||
// Now returns the current monotonic time.
|
||||
func (System) Now() AbsTime {
|
||||
func (c System) Now() AbsTime {
|
||||
return AbsTime(monotime.Now())
|
||||
}
|
||||
|
||||
// Sleep blocks for the given duration.
|
||||
func (System) Sleep(d time.Duration) {
|
||||
func (c System) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
// NewTimer creates a timer which can be rescheduled.
|
||||
func (c System) NewTimer(d time.Duration) ChanTimer {
|
||||
ch := make(chan AbsTime, 1)
|
||||
t := time.AfterFunc(d, func() {
|
||||
// This send is non-blocking because that's how time.Timer
|
||||
// behaves. It doesn't matter in the happy case, but does
|
||||
// when Reset is misused.
|
||||
select {
|
||||
case ch <- c.Now():
|
||||
default:
|
||||
}
|
||||
})
|
||||
return &systemTimer{t, ch}
|
||||
}
|
||||
|
||||
// After returns a channel which receives the current time after d has elapsed.
|
||||
func (System) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
func (c System) After(d time.Duration) <-chan AbsTime {
|
||||
ch := make(chan AbsTime, 1)
|
||||
time.AfterFunc(d, func() { ch <- c.Now() })
|
||||
return ch
|
||||
}
|
||||
|
||||
// AfterFunc runs f on a new goroutine after the duration has elapsed.
|
||||
func (System) AfterFunc(d time.Duration, f func()) Timer {
|
||||
func (c System) AfterFunc(d time.Duration, f func()) Timer {
|
||||
return time.AfterFunc(d, f)
|
||||
}
|
||||
|
||||
type systemTimer struct {
|
||||
*time.Timer
|
||||
ch <-chan AbsTime
|
||||
}
|
||||
|
||||
func (st *systemTimer) Reset(d time.Duration) {
|
||||
st.Timer.Reset(d)
|
||||
}
|
||||
|
||||
func (st *systemTimer) C() <-chan AbsTime {
|
||||
return st.ch
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package mclock
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -32,18 +33,24 @@ import (
|
|||
// the timeout using a channel or semaphore.
|
||||
type Simulated struct {
|
||||
now AbsTime
|
||||
scheduled []*simTimer
|
||||
scheduled simTimerHeap
|
||||
mu sync.RWMutex
|
||||
cond *sync.Cond
|
||||
lastId uint64
|
||||
}
|
||||
|
||||
// simTimer implements Timer on the virtual clock.
|
||||
// simTimer implements ChanTimer on the virtual clock.
|
||||
type simTimer struct {
|
||||
do func()
|
||||
at AbsTime
|
||||
id uint64
|
||||
index int // position in s.scheduled
|
||||
s *Simulated
|
||||
do func()
|
||||
ch <-chan AbsTime
|
||||
}
|
||||
|
||||
func (s *Simulated) init() {
|
||||
if s.cond == nil {
|
||||
s.cond = sync.NewCond(&s.mu)
|
||||
}
|
||||
}
|
||||
|
||||
// Run moves the clock by the given duration, executing all timers before that duration.
|
||||
|
|
@ -53,14 +60,9 @@ func (s *Simulated) Run(d time.Duration) {
|
|||
|
||||
end := s.now + AbsTime(d)
|
||||
var do []func()
|
||||
for len(s.scheduled) > 0 {
|
||||
ev := s.scheduled[0]
|
||||
if ev.at > end {
|
||||
break
|
||||
}
|
||||
s.now = ev.at
|
||||
for len(s.scheduled) > 0 && s.scheduled[0].at <= end {
|
||||
ev := heap.Pop(&s.scheduled).(*simTimer)
|
||||
do = append(do, ev.do)
|
||||
s.scheduled = s.scheduled[1:]
|
||||
}
|
||||
s.now = end
|
||||
s.mu.Unlock()
|
||||
|
|
@ -102,14 +104,22 @@ func (s *Simulated) Sleep(d time.Duration) {
|
|||
<-s.After(d)
|
||||
}
|
||||
|
||||
// NewTimer creates a timer which fires when the clock has advanced by d.
|
||||
func (s *Simulated) NewTimer(d time.Duration) ChanTimer {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
ch := make(chan AbsTime, 1)
|
||||
var timer *simTimer
|
||||
timer = s.schedule(d, func() { ch <- timer.at })
|
||||
timer.ch = ch
|
||||
return timer
|
||||
}
|
||||
|
||||
// After returns a channel which receives the current time after the clock
|
||||
// has advanced by d.
|
||||
func (s *Simulated) After(d time.Duration) <-chan time.Time {
|
||||
after := make(chan time.Time, 1)
|
||||
s.AfterFunc(d, func() {
|
||||
after <- (time.Time{}).Add(time.Duration(s.now))
|
||||
})
|
||||
return after
|
||||
func (s *Simulated) After(d time.Duration) <-chan AbsTime {
|
||||
return s.NewTimer(d).C()
|
||||
}
|
||||
|
||||
// AfterFunc runs fn after the clock has advanced by d. Unlike with the system
|
||||
|
|
@ -117,46 +127,83 @@ func (s *Simulated) After(d time.Duration) <-chan time.Time {
|
|||
func (s *Simulated) AfterFunc(d time.Duration, fn func()) Timer {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return s.schedule(d, fn)
|
||||
}
|
||||
|
||||
func (s *Simulated) schedule(d time.Duration, fn func()) *simTimer {
|
||||
s.init()
|
||||
|
||||
at := s.now + AbsTime(d)
|
||||
s.lastId++
|
||||
id := s.lastId
|
||||
l, h := 0, len(s.scheduled)
|
||||
ll := h
|
||||
for l != h {
|
||||
m := (l + h) / 2
|
||||
if (at < s.scheduled[m].at) || ((at == s.scheduled[m].at) && (id < s.scheduled[m].id)) {
|
||||
h = m
|
||||
} else {
|
||||
l = m + 1
|
||||
}
|
||||
}
|
||||
ev := &simTimer{do: fn, at: at, s: s}
|
||||
s.scheduled = append(s.scheduled, nil)
|
||||
copy(s.scheduled[l+1:], s.scheduled[l:ll])
|
||||
s.scheduled[l] = ev
|
||||
heap.Push(&s.scheduled, ev)
|
||||
s.cond.Broadcast()
|
||||
return ev
|
||||
}
|
||||
|
||||
func (ev *simTimer) Stop() bool {
|
||||
s := ev.s
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
ev.s.mu.Lock()
|
||||
defer ev.s.mu.Unlock()
|
||||
|
||||
for i := 0; i < len(s.scheduled); i++ {
|
||||
if s.scheduled[i] == ev {
|
||||
s.scheduled = append(s.scheduled[:i], s.scheduled[i+1:]...)
|
||||
s.cond.Broadcast()
|
||||
return true
|
||||
}
|
||||
}
|
||||
if ev.index < 0 {
|
||||
return false
|
||||
}
|
||||
heap.Remove(&ev.s.scheduled, ev.index)
|
||||
ev.s.cond.Broadcast()
|
||||
ev.index = -1
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Simulated) init() {
|
||||
if s.cond == nil {
|
||||
s.cond = sync.NewCond(&s.mu)
|
||||
func (ev *simTimer) Reset(d time.Duration) {
|
||||
if ev.ch == nil {
|
||||
panic("mclock: Reset() on timer created by AfterFunc")
|
||||
}
|
||||
|
||||
ev.s.mu.Lock()
|
||||
defer ev.s.mu.Unlock()
|
||||
ev.at = ev.s.now.Add(d)
|
||||
if ev.index < 0 {
|
||||
heap.Push(&ev.s.scheduled, ev) // already expired
|
||||
} else {
|
||||
heap.Fix(&ev.s.scheduled, ev.index) // hasn't fired yet, reschedule
|
||||
}
|
||||
ev.s.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (ev *simTimer) C() <-chan AbsTime {
|
||||
if ev.ch == nil {
|
||||
panic("mclock: C() on timer created by AfterFunc")
|
||||
}
|
||||
return ev.ch
|
||||
}
|
||||
|
||||
type simTimerHeap []*simTimer
|
||||
|
||||
func (h *simTimerHeap) Len() int {
|
||||
return len(*h)
|
||||
}
|
||||
|
||||
func (h *simTimerHeap) Less(i, j int) bool {
|
||||
return (*h)[i].at < (*h)[j].at
|
||||
}
|
||||
|
||||
func (h *simTimerHeap) Swap(i, j int) {
|
||||
(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
|
||||
(*h)[i].index = i
|
||||
(*h)[j].index = j
|
||||
}
|
||||
|
||||
func (h *simTimerHeap) Push(x interface{}) {
|
||||
t := x.(*simTimer)
|
||||
t.index = len(*h)
|
||||
*h = append(*h, t)
|
||||
}
|
||||
|
||||
func (h *simTimerHeap) Pop() interface{} {
|
||||
end := len(*h) - 1
|
||||
t := (*h)[end]
|
||||
t.index = -1
|
||||
(*h)[end] = nil
|
||||
*h = (*h)[:end]
|
||||
return t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,16 @@ var _ Clock = System{}
|
|||
var _ Clock = new(Simulated)
|
||||
|
||||
func TestSimulatedAfter(t *testing.T) {
|
||||
const timeout = 30 * time.Minute
|
||||
const adv = time.Minute
|
||||
|
||||
var (
|
||||
timeout = 30 * time.Minute
|
||||
offset = 99 * time.Hour
|
||||
adv = 11 * time.Minute
|
||||
c Simulated
|
||||
end = c.Now().Add(timeout)
|
||||
ch = c.After(timeout)
|
||||
)
|
||||
c.Run(offset)
|
||||
|
||||
end := c.Now().Add(timeout)
|
||||
ch := c.After(timeout)
|
||||
for c.Now() < end.Add(-adv) {
|
||||
c.Run(adv)
|
||||
select {
|
||||
|
|
@ -45,8 +47,8 @@ func TestSimulatedAfter(t *testing.T) {
|
|||
c.Run(adv)
|
||||
select {
|
||||
case stamp := <-ch:
|
||||
want := time.Time{}.Add(timeout)
|
||||
if !stamp.Equal(want) {
|
||||
want := AbsTime(0).Add(offset).Add(timeout)
|
||||
if stamp != want {
|
||||
t.Errorf("Wrong time sent on timer channel: got %v, want %v", stamp, want)
|
||||
}
|
||||
default:
|
||||
|
|
@ -113,3 +115,48 @@ func TestSimulatedSleep(t *testing.T) {
|
|||
t.Fatal("Sleep didn't return in time")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulatedTimerReset(t *testing.T) {
|
||||
var (
|
||||
c Simulated
|
||||
timeout = 1 * time.Hour
|
||||
)
|
||||
timer := c.NewTimer(timeout)
|
||||
c.Run(2 * timeout)
|
||||
select {
|
||||
case ftime := <-timer.C():
|
||||
if ftime != AbsTime(timeout) {
|
||||
t.Fatalf("wrong time %v sent on timer channel, want %v", ftime, AbsTime(timeout))
|
||||
}
|
||||
default:
|
||||
t.Fatal("timer didn't fire")
|
||||
}
|
||||
|
||||
timer.Reset(timeout)
|
||||
c.Run(2 * timeout)
|
||||
select {
|
||||
case ftime := <-timer.C():
|
||||
if ftime != AbsTime(3*timeout) {
|
||||
t.Fatalf("wrong time %v sent on timer channel, want %v", ftime, AbsTime(3*timeout))
|
||||
}
|
||||
default:
|
||||
t.Fatal("timer didn't fire again")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulatedTimerStop(t *testing.T) {
|
||||
var (
|
||||
c Simulated
|
||||
timeout = 1 * time.Hour
|
||||
)
|
||||
timer := c.NewTimer(timeout)
|
||||
c.Run(2 * timeout)
|
||||
if timer.Stop() {
|
||||
t.Errorf("Stop returned true for fired timer")
|
||||
}
|
||||
select {
|
||||
case <-timer.C():
|
||||
default:
|
||||
t.Fatal("timer didn't fire")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,6 +314,33 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
|
|||
return &ret, nil
|
||||
}
|
||||
|
||||
func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) {
|
||||
tx, err := t.resolve(ctx)
|
||||
if err != nil || tx == nil {
|
||||
return hexutil.Big{}, err
|
||||
}
|
||||
_, r, _ := tx.RawSignatureValues()
|
||||
return hexutil.Big(*r), nil
|
||||
}
|
||||
|
||||
func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) {
|
||||
tx, err := t.resolve(ctx)
|
||||
if err != nil || tx == nil {
|
||||
return hexutil.Big{}, err
|
||||
}
|
||||
_, _, s := tx.RawSignatureValues()
|
||||
return hexutil.Big(*s), nil
|
||||
}
|
||||
|
||||
func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) {
|
||||
tx, err := t.resolve(ctx)
|
||||
if err != nil || tx == nil {
|
||||
return hexutil.Big{}, err
|
||||
}
|
||||
v, _, _ := tx.RawSignatureValues()
|
||||
return hexutil.Big(*v), nil
|
||||
}
|
||||
|
||||
type BlockType int
|
||||
|
||||
// Block represents an Ethereum block.
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ const schema string = `
|
|||
# Logs is a list of log entries emitted by this transaction. If the
|
||||
# transaction has not yet been mined, this field will be null.
|
||||
logs: [Log!]
|
||||
r: BigInt!
|
||||
s: BigInt!
|
||||
v: BigInt!
|
||||
}
|
||||
|
||||
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B
|
|||
response, err := s.rpcMarshalBlock(block, true, fullTx)
|
||||
if err == nil && number == rpc.PendingBlockNumber {
|
||||
// Pending blocks need to nil out a few fields
|
||||
for _, field := range []string{"hash", "nonce", "miner", "number"} {
|
||||
for _, field := range []string{"hash", "nonce", "miner"} {
|
||||
response[field] = nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ func (h *serverHandler) handle(p *peer) error {
|
|||
}
|
||||
// Reject light clients if server is not synced.
|
||||
if !h.synced() {
|
||||
p.Log().Debug("Light server not synced, rejecting peer")
|
||||
return p2p.DiscRequested
|
||||
}
|
||||
defer p.fcClient.Disconnect()
|
||||
|
|
|
|||
|
|
@ -276,6 +276,9 @@ func (c *Client) Call(result interface{}, method string, args ...interface{}) er
|
|||
// The result must be a pointer so that package json can unmarshal into it. You
|
||||
// can also pass nil, in which case the result is ignored.
|
||||
func (c *Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
|
||||
if result != nil && reflect.TypeOf(result).Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("call result parameter must be pointer or nil interface: %v", result)
|
||||
}
|
||||
msg, err := c.newMessage(method, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -49,6 +49,23 @@ func TestClientRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestClientResponseType(t *testing.T) {
|
||||
server := newTestServer()
|
||||
defer server.Stop()
|
||||
client := DialInProc(server)
|
||||
defer client.Close()
|
||||
|
||||
if err := client.Call(nil, "test_echo", "hello", 10, &echoArgs{"world"}); err != nil {
|
||||
t.Errorf("Passing nil as result should be fine, but got an error: %v", err)
|
||||
}
|
||||
var resultVar echoResult
|
||||
// Note: passing the var, not a ref
|
||||
err := client.Call(resultVar, "test_echo", "hello", 10, &echoArgs{"world"})
|
||||
if err == nil {
|
||||
t.Error("Passing a var as result should be an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientBatchRequest(t *testing.T) {
|
||||
server := newTestServer()
|
||||
defer server.Stop()
|
||||
|
|
|
|||
|
|
@ -923,7 +923,9 @@ func isPrimitiveTypeValid(primitiveType string) bool {
|
|||
primitiveType == "bytes30" ||
|
||||
primitiveType == "bytes30[]" ||
|
||||
primitiveType == "bytes31" ||
|
||||
primitiveType == "bytes31[]" {
|
||||
primitiveType == "bytes31[]" ||
|
||||
primitiveType == "bytes32" ||
|
||||
primitiveType == "bytes32[]" {
|
||||
return true
|
||||
}
|
||||
if primitiveType == "int" ||
|
||||
|
|
|
|||
Loading…
Reference in a new issue