good morning!!!!

Skip to content
Snippets Groups Projects
Commit b27215ef authored by Garet Halliday's avatar Garet Halliday
Browse files

crack

parent 06a4009c
No related branches found
No related tags found
No related merge requests found
Pipeline #22283 passed
Showing
with 775 additions and 174 deletions
......@@ -25,7 +25,7 @@ func (s *Impl) makeFunctionSignature(sig *sig.Entry) api.FunctionSignature {
return api.FunctionSignature{
ID: sig.Id,
CreatedAt: sig.CreatedAt.String(),
TextSignature: sig.Signature(),
TextSignature: sig.Signature,
HexSignature: "0x" + hex.EncodeToString(sig.Hash),
// TODO: do the weird encoding that he does lol
// maybe https://github.com/golang/go/issues/39137?
......@@ -37,7 +37,7 @@ func (s *Impl) makeEventSignature(sig *sig.Entry) api.EventSignature {
return api.EventSignature{
ID: sig.Id,
CreatedAt: sig.CreatedAt.String(),
TextSignature: sig.Signature(),
TextSignature: sig.Signature,
HexSignature: "0x" + hex.EncodeToString(sig.EventHash),
// TODO: do the weird encoding that he does lol
// maybe https://github.com/golang/go/issues/39137?
......
package sig
import (
"log"
"strings"
"time"
"gfx.cafe/open/4byte/common/util/hashpool"
......@@ -12,8 +10,7 @@ var hp = hashpool.NewKeccack()
type Entry struct {
Id int
Name string
Arguments []string
Signature string
Hash []byte
EventHash []byte
......@@ -21,41 +18,19 @@ type Entry struct {
CreatedAt time.Time
}
func NewEntry(name string, args ...string) *Entry {
valid := make([]string, 0, len(args))
for _, v := range args {
lv := strings.ToLower(v)
if strings.HasPrefix(lv, "byte[") {
lv = "bytes1[" + strings.TrimPrefix(lv, "byte[")
}
if lv == "byte" {
lv = "bytes1"
}
if validType(lv) {
valid = append(valid, lv)
}
}
e := &Entry{
Name: name,
Arguments: valid,
CreatedAt: time.Now(),
}
e.init()
return e
}
// FromText creates a signature from 's'. The input will be normalized. If the format is unknown, this function will return nil.
func FromText(s string) *Entry {
log.Println(s)
normalized, ok := Normalize(s)
if !ok {
return nil
}
func (e *Entry) Signature() string {
mid := ""
if len(e.Arguments) > 0 {
mid = strings.Join(e.Arguments, ",")
entry := &Entry{
Signature: normalized,
CreatedAt: time.Now(),
}
return e.Name + "(" + mid + ")"
entry.init()
return entry
}
func (e *Entry) init() {
......@@ -63,7 +38,7 @@ func (e *Entry) init() {
}
func (e *Entry) calculateEventHash() {
txt := e.Signature()
txt := e.Signature
k := hp.Get()
k.Write([]byte(txt))
out := make([]byte, 32)
......
package sig
import (
"gfx.cafe/open/4byte/common/sig/parser"
"gfx.cafe/open/4byte/common/sig/parser/parsers/v0"
)
func Normalize(str string) (string, bool) {
ctx := parser.MakeContext(str)
v, ok := parsers.Signature.Build(&ctx)
if !ok {
return "", false
}
return v.String(), true
}
Normalizes and parses signatures.
Uses the grammar in the ethereum/eth-abi package:
```
type = tuple_type / basic_type
tuple_type = components arrlist?
components = non_zero_tuple / zero_tuple
non_zero_tuple = "(" type next_type* ")"
next_type = "," type
zero_tuple = "()"
basic_type = base sub? arrlist?
base = alphas
sub = two_size / digits
two_size = (digits "x" digits)
arrlist = (const_arr / dynam_arr)+
const_arr = "[" digits "]"
dynam_arr = "[]"
alphas = ~"[A-Za-z]+"
digits = ~"[1-9][0-9]*"
```
\ No newline at end of file
package parser
import (
"fmt"
"strings"
)
type Array interface {
array()
fmt.Stringer
}
type ConstArray struct {
Length string
}
func (ConstArray) array() {}
func (T ConstArray) String() string {
var b strings.Builder
b.WriteRune('[')
b.WriteString(T.Length)
b.WriteRune(']')
return b.String()
}
type DynamicArray struct {
}
func (DynamicArray) array() {}
func (DynamicArray) String() string {
return "[]"
}
package parser
import (
"strings"
)
type BasicType struct {
Base string
Sub Sub
ArrayList []Array
}
func MakeBasicType(base string, sub Sub, arrayList []Array) BasicType {
if sub == nil {
switch base {
case "int":
sub = OneSize{
X: "256",
}
case "uint":
sub = OneSize{
X: "256",
}
case "fixed":
sub = TwoSize{
X: "128",
Y: "18",
}
case "ufixed":
sub = TwoSize{
X: "128",
Y: "18",
}
case "function":
base = "bytes"
sub = OneSize{
X: "24",
}
case "byte":
base = "bytes"
sub = OneSize{
X: "1",
}
}
}
return BasicType{
Base: base,
Sub: sub,
ArrayList: arrayList,
}
}
func (BasicType) typ() {}
func (T BasicType) String() string {
var b strings.Builder
b.WriteString(T.Base)
if T.Sub != nil {
b.WriteString(T.Sub.String())
}
for _, arr := range T.ArrayList {
b.WriteString(arr.String())
}
return b.String()
}
package parser
type Builder[T any] interface {
Build(*Context) (T, bool)
}
package parser
import (
"strings"
"unicode/utf8"
)
type Context struct {
value string
offset int
position int
}
func MakeContext(value string) Context {
return Context{
value: value,
}
}
func (T *Context) Digest() string {
return T.value[T.offset : T.offset+T.position]
}
func (T *Context) next() (rune, int, bool) {
r, size := utf8.DecodeRuneInString(T.value[T.offset+T.position:])
if r == utf8.RuneError {
return utf8.RuneError, 0, false
}
return r, size, true
}
func String(ctx *Context, str string) bool {
if strings.HasPrefix(ctx.value[ctx.offset+ctx.position:], str) {
ctx.position += len(str)
return true
}
return false
}
func SingleOf(ctx *Context, fn func(rune) bool) (rune, bool) {
r, size, ok := ctx.next()
if !ok {
return utf8.RuneError, false
}
if !fn(r) {
return utf8.RuneError, false
}
ctx.position += size
return r, true
}
func Single(ctx *Context, c rune) bool {
r, size, ok := ctx.next()
if !ok {
return false
}
if r != c {
return false
}
ctx.position += size
return true
}
func Try[T any](ctx *Context, builder Builder[T]) (T, bool) {
offset := ctx.offset
position := ctx.position
ctx.offset = offset + position
ctx.position = 0
v, ok := builder.Build(ctx)
ctx.offset = offset
if !ok {
// revert
ctx.position = position
return *new(T), false
}
ctx.position += position
return v, true
}
package parser
func Func[T any](fn func(ctx *Context) (T, bool)) Builder[T] {
return funcBuilder[T](fn)
}
type funcBuilder[T any] func(ctx *Context) (T, bool)
func (f funcBuilder[T]) Build(ctx *Context) (T, bool) {
return f(ctx)
}
package parsers
import (
"unicode"
p "gfx.cafe/open/4byte/common/sig/parser"
)
func whitespace(r rune) bool {
return unicode.IsSpace(r)
}
var Whitespaces = p.Func(
func(ctx *p.Context) (struct{}, bool) {
if _, ok := p.SingleOf(ctx, whitespace); !ok {
return struct{}{}, false
}
for {
if _, ok := p.SingleOf(ctx, whitespace); !ok {
break
}
}
return struct{}{}, true
},
)
func alpha(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
}
var Alphas = p.Func(
func(ctx *p.Context) (string, bool) {
if _, ok := p.SingleOf(ctx, alpha); !ok {
return "", false
}
for {
if _, ok := p.SingleOf(ctx, alpha); !ok {
break
}
}
return ctx.Digest(), true
},
)
var Digits = p.Func(
func(ctx *p.Context) (string, bool) {
if _, ok := p.SingleOf(ctx, func(r rune) bool {
return r >= '1' && r <= '9'
}); !ok {
return "", false
}
for {
if _, ok := p.SingleOf(ctx, func(r rune) bool {
return r >= '0' && r <= '9'
}); !ok {
break
}
}
return ctx.Digest(), true
},
)
var DynamicArray = p.Func(
func(ctx *p.Context) (p.DynamicArray, bool) {
if !p.Single(ctx, '[') {
return p.DynamicArray{}, false
}
if !p.Single(ctx, ']') {
return p.DynamicArray{}, false
}
return p.DynamicArray{}, true
},
)
var ConstArray = p.Func(
func(ctx *p.Context) (p.ConstArray, bool) {
if !p.Single(ctx, '[') {
return p.ConstArray{}, false
}
digits, ok := p.Try(ctx, Digits)
if !ok {
return p.ConstArray{}, false
}
if !p.Single(ctx, ']') {
return p.ConstArray{}, false
}
return p.ConstArray{
Length: digits,
}, true
},
)
var ArrayList = p.Func(
func(ctx *p.Context) ([]p.Array, bool) {
var arrays []p.Array
for {
if dynamic, ok := p.Try(ctx, DynamicArray); ok {
arrays = append(arrays, dynamic)
continue
}
if constant, ok := p.Try(ctx, ConstArray); ok {
arrays = append(arrays, constant)
continue
}
if len(arrays) == 0 {
return nil, false
}
return arrays, true
}
},
)
var OneSize = p.Func(
func(ctx *p.Context) (p.OneSize, bool) {
x, ok := p.Try(ctx, Digits)
if !ok {
return p.OneSize{}, false
}
return p.OneSize{
X: x,
}, true
},
)
var TwoSize = p.Func(
func(ctx *p.Context) (p.TwoSize, bool) {
x, ok := p.Try(ctx, Digits)
if !ok {
return p.TwoSize{}, false
}
if !p.Single(ctx, 'x') {
return p.TwoSize{}, false
}
y, ok := p.Try(ctx, Digits)
if !ok {
return p.TwoSize{}, false
}
return p.TwoSize{
X: x,
Y: y,
}, true
},
)
var Sub = p.Func(
func(ctx *p.Context) (p.Sub, bool) {
if two, ok := p.Try(ctx, TwoSize); ok {
return two, true
}
if one, ok := p.Try(ctx, OneSize); ok {
return one, true
}
return nil, false
},
)
var Base = p.Func(
func(ctx *p.Context) (string, bool) {
return p.Try(ctx, Alphas)
},
)
var BasicType = p.Func(
func(ctx *p.Context) (p.BasicType, bool) {
base, ok := p.Try(ctx, Base)
if !ok {
return p.BasicType{}, false
}
sub, _ := p.Try(ctx, Sub)
arrayList, _ := p.Try(ctx, ArrayList)
return p.MakeBasicType(base, sub, arrayList), true
},
)
var Tuple = p.Func(
func(ctx *p.Context) (p.Tuple, bool) {
if !p.Single(ctx, '(') {
return p.Tuple{}, false
}
var types []p.Type
for {
typ, ok := p.Try(ctx, Type)
if ok {
types = append(types, typ)
if p.Single(ctx, ',') {
continue
}
}
if p.Single(ctx, ')') {
break
}
return p.Tuple{}, false
}
return p.Tuple{
Types: types,
}, true
},
)
var TupleType = p.Func(
func(ctx *p.Context) (p.TupleType, bool) {
tuple, ok := p.Try(ctx, Tuple)
if !ok {
return p.TupleType{}, false
}
arrayList, _ := p.Try(ctx, ArrayList)
return p.TupleType{
Tuple: tuple,
ArrayList: arrayList,
}, true
},
)
var Type p.Builder[p.Type] = typ{}
type typ struct{}
func (typ) Build(ctx *p.Context) (p.Type, bool) {
if tuple, ok := p.Try(ctx, TupleType); ok {
return tuple, true
}
if basic, ok := p.Try(ctx, BasicType); ok {
return basic, true
}
return nil, false
}
var Identifier = p.Func(
func(ctx *p.Context) (string, bool) {
if _, ok := p.SingleOf(ctx, func(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '$' || r == '_'
}); !ok {
return "", false
}
for {
if _, ok := p.SingleOf(ctx, func(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '$' || r == '_'
}); !ok {
break
}
}
return ctx.Digest(), true
},
)
var Arguments = p.Func(
func(ctx *p.Context) ([]p.Type, bool) {
if !p.Single(ctx, '(') {
return nil, false
}
var types []p.Type
for {
p.Try(ctx, Whitespaces)
typ, ok := p.Try(ctx, Type)
if ok {
types = append(types, typ)
// optional name
p.Try(ctx, Whitespaces)
p.Try(ctx, Identifier)
p.Try(ctx, Whitespaces)
if p.Single(ctx, ',') {
continue
}
}
p.Try(ctx, Whitespaces)
if p.Single(ctx, ')') {
break
}
return nil, false
}
return types, true
},
)
var Signature = p.Func(
func(ctx *p.Context) (p.Signature, bool) {
// optional "function" at the beginning
p.String(ctx, "function")
p.Try(ctx, Whitespaces)
name, ok := p.Try(ctx, Identifier)
if !ok {
return p.Signature{}, false
}
p.Try(ctx, Whitespaces)
arguments, ok := p.Try(ctx, Arguments)
if !ok {
return p.Signature{}, false
}
return p.Signature{
Name: name,
Arguments: arguments,
}, true
},
)
package parsers
import (
"log"
"testing"
p "gfx.cafe/open/4byte/common/sig/parser"
)
func parse(v string) (p.Signature, bool) {
ctx := p.MakeContext(v)
return Signature.Build(&ctx)
}
func TestNormalizing(t *testing.T) {
const expected = "transfer(address,uint256)"
var cases = []string{
"function transfer(address _to, uint _value)",
"function transfer(address _to, uint256 _value)",
"transfer(address _to, uint256 _value)",
"transfer(address _to, uint _value)",
"transfer(address, uint)",
"transfer(address, uint256)",
"transfer ( address, uint256 )",
"transfer ( address, uint256 )",
}
for _, cas := range cases {
v, ok := parse(cas)
if !ok {
t.Errorf("failed to parse `%s`", cas)
continue
}
if v.String() != expected {
t.Errorf("mismatch. expected `%s` but got `%s`", expected, v.String())
continue
}
}
}
func TestParser(t *testing.T) {
v, ok := parse("setDeposit(address,bytes32,((address,address,address,address,address,address,address[],address[]),(uint256,uint256,uint256,uint256,uint256,uint256),(bool)))")
log.Println(v.String(), ok)
}
package parser
import "strings"
type Signature struct {
Name string
Arguments []Type
}
func (T Signature) String() string {
var b strings.Builder
b.WriteString(T.Name)
b.WriteRune('(')
for i, arg := range T.Arguments {
if i != 0 {
b.WriteRune(',')
}
b.WriteString(arg.String())
}
b.WriteRune(')')
return b.String()
}
package parser
import (
"fmt"
"strings"
)
type Sub interface {
sub()
fmt.Stringer
}
type OneSize struct {
X string
}
func (OneSize) sub() {}
func (T OneSize) String() string {
return T.X
}
type TwoSize struct {
X string
Y string
}
func (TwoSize) sub() {}
func (T TwoSize) String() string {
var b strings.Builder
b.WriteString(T.X)
b.WriteRune('x')
b.WriteString(T.Y)
return b.String()
}
package parser
import "strings"
type Tuple struct {
Types []Type
}
func (T Tuple) String() string {
var b strings.Builder
b.WriteRune('(')
for i, typ := range T.Types {
if i != 0 {
b.WriteRune(',')
}
b.WriteString(typ.String())
}
b.WriteRune(')')
return b.String()
}
type TupleType struct {
Tuple Tuple
ArrayList []Array
}
func (TupleType) typ() {}
func (T TupleType) String() string {
var b strings.Builder
b.WriteString(T.Tuple.String())
for _, arr := range T.ArrayList {
b.WriteString(arr.String())
}
return b.String()
}
package parser
import "fmt"
type Type interface {
typ()
fmt.Stringer
}
package sig
import (
"log"
"regexp"
"strings"
)
var sigRegex = regexp.MustCompile(
`[a-zA-Z0-9_]*\s*\(\s*(?:[a-zA-Z0-9_]*(?:(?:\s*,\s*[a-zA-Z0-9_]*\s*[a-zA-Z0-9_]*\s*)*)?(?:,)?)?\s*\)(?:\s*anonymous)?`,
)
func ExtractSigs(s string) []*Entry {
out := []*Entry{}
s = strings.ReplaceAll(s, "%20", " ")
tosee := sigRegex.FindAllString(s, -1)
log.Println(tosee)
for _, v := range tosee {
out = append(out, FromText(v))
}
return out
}
package sig
import (
"strings"
"gfx.cafe/open/4byte/common/sig/types"
)
func isValidArray(s string) bool {
inside := false
for _, r := range s {
if inside {
if r == ']' {
inside = false
} else {
if !IsDigit(r) {
return false
}
}
} else {
if r == '[' {
inside = true
} else {
return false
}
}
}
return true
}
func validType(s string) bool {
_, ok := types.ValidTypes[s]
if ok {
return true
}
// split by first [
spl := strings.SplitN(s, "[", 2)
if len(spl) < 2 {
return false
}
if _, ok := types.ValidTypes[spl[0]]; ok {
if isValidArray("[" + spl[1]) {
return true
}
}
return false
}
func IsValidType(s string) bool {
return validType(s)
}
func IsDigit(c rune) bool {
if c < '0' || c > '9' {
return false
}
return true
}
package types
import "strconv"
var ValidTypes = make(map[string]string, 256)
func addt(s string, v string) {
ValidTypes[s] = v
}
func init() {
addt("string", "string")
addt("bytes", "bytes")
addt("address", "address")
addt("bool", "bool")
addt("function", "function")
for i := 1; i <= 32; i++ {
v := "bytes" + strconv.Itoa(i)
addt(v, v)
}
for i := 1; i <= 32; i++ {
a := "int" + strconv.Itoa(i*8)
b := "uint" + strconv.Itoa(i*8)
addt(a, a)
addt(b, b)
}
for i := 1; i <= 32; i++ {
for j := 1; j <= 80; j++ {
a := "fixed" + strconv.Itoa(i*8) + "x" + strconv.Itoa(i*8)
b := "fixed" + strconv.Itoa(i*8) + "x" + strconv.Itoa(i*8)
addt(a, a)
addt(b, b)
}
}
}
......@@ -26,19 +26,18 @@ func NewStore() *Store {
}
func (T *Store) Put(_ context.Context, e *sig.Entry) (newEntry *sig.Entry, err error) {
if _, ok := T.bySignature[e.Signature()]; ok {
if _, ok := T.bySignature[e.Signature]; ok {
return nil, nil
}
newEntry = &sig.Entry{
Id: len(T.entries),
Name: e.Name,
Arguments: e.Arguments,
Signature: e.Signature,
Hash: e.Hash,
EventHash: e.EventHash,
CreatedAt: time.Now(),
}
T.byID[newEntry.Id] = newEntry
T.bySignature[newEntry.Signature()] = newEntry
T.bySignature[newEntry.Signature] = newEntry
T.entries = append(T.entries, newEntry)
return
}
......@@ -56,24 +55,24 @@ func (T *Store) matches(e *sig.Entry, condition store.SearchCondition) bool {
switch condition.Type {
case store.SearchConditionTextExact:
if condition.CaseSensitive {
return e.Signature() == condition.Needle
return e.Signature == condition.Needle
}
return strings.ToLower(e.Signature()) == strings.ToLower(condition.Needle)
return strings.ToLower(e.Signature) == strings.ToLower(condition.Needle)
case store.SearchConditionTextContains:
if condition.CaseSensitive {
return strings.Contains(e.Signature(), condition.Needle)
return strings.Contains(e.Signature, condition.Needle)
}
return strings.Contains(strings.ToLower(e.Signature()), strings.ToLower(condition.Needle))
return strings.Contains(strings.ToLower(e.Signature), strings.ToLower(condition.Needle))
case store.SearchConditionTextStartsWith:
if condition.CaseSensitive {
return strings.HasPrefix(e.Signature(), condition.Needle)
return strings.HasPrefix(e.Signature, condition.Needle)
}
return strings.HasPrefix(strings.ToLower(e.Signature()), strings.ToLower(condition.Needle))
return strings.HasPrefix(strings.ToLower(e.Signature), strings.ToLower(condition.Needle))
case store.SearchConditionTextEndsWith:
if condition.CaseSensitive {
return strings.HasSuffix(e.Signature(), condition.Needle)
return strings.HasSuffix(e.Signature, condition.Needle)
}
return strings.HasSuffix(strings.ToLower(e.Signature()), strings.ToLower(condition.Needle))
return strings.HasSuffix(strings.ToLower(e.Signature), strings.ToLower(condition.Needle))
case store.SearchConditionHashContains:
needle := strings.TrimPrefix(condition.Needle, "0x")
return strings.Contains(hex.EncodeToString(e.Hash), needle)
......@@ -99,11 +98,11 @@ func (T *Store) Search(_ context.Context, page int, pageSize int, ordering store
})
case store.OrderingTextSignatureAsc:
sort.Slice(results, func(i, j int) bool {
return results[i].Signature() < results[j].Signature()
return results[i].Signature < results[j].Signature
})
case store.OrderingTextSignatureDesc:
sort.Slice(results, func(i, j int) bool {
return results[i].Signature() > results[j].Signature()
return results[i].Signature > results[j].Signature
})
case store.OrderingBytesSignatureAsc:
sort.Slice(results, func(i, j int) bool {
......
......@@ -4,8 +4,7 @@ import "time"
type EntryNoID struct {
Id int `db:"-"`
Name string `db:"name"`
Arguments []string `db:"arguments"`
Signature string `db:"signature"`
Hash []byte `db:"hash"`
EventHash []byte `db:"event_hash"`
......@@ -15,8 +14,7 @@ type EntryNoID struct {
type Entry struct {
Id int `db:"id"`
Name string `db:"name"`
Arguments []string `db:"arguments"`
Signature string `db:"signature"`
Hash []byte `db:"hash"`
EventHash []byte `db:"event_hash"`
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment