Hello im trying to revert a custom error in YUL inline-assembly
function mint(uint256 amountToMint) external onlyOwner() {
assembly {
// check if exceed maxSupply
let maxSupplySlot := sload(maxSupply.slot)
let res := lt(add(amountToMint, mload(counter.slot)), add(maxSupplySlot, 1))
let ptrError := mload(0x40)
mstore(ptrError, 14)
mstore(add(ptrError, 0x20), 0x4d6178537570706c795265616368) // => "MaxSupplyReach"
if iszero(res) { revert(ptrError, 0x40) }
// populate mapping balanceOf
let ptr := mload(0x40)
mstore(ptr, caller())
mstore(add(ptr, 0x20), balanceOf.slot)
let slot := keccak256(ptr, 0x40)
sstore(slot, amountToMint)
// increment counter
let counterSlot := sload(counter.slot)
let resCounter := add(counterSlot, amountToMint)
sstore(counter.slot, resCounter)
}
}
dont know if i do it correctly my output is like that.
0x000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000004d6178537570706c795265616368
my foundry error when i revert with revert(0,0) it pass but dont pass with custom error
thank's for ur help :)
not sure if you have noticed, but your result is actually what you wanted. It is a hex string, which converted to ASCII yields:
0x000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000004d6178537570706c795265616368
14MaxSupplyReach
with 14 being the string length you stored.
Related
I'm trying to build a simple orm layer for golang.
Which would take a struct and generate the cols [] which can then be passed to sql function
rows.Scan(cols...) which takes pointers of fields in the struct corresponding to each of the columns it has found in the result set
Here is my example struct
type ExampleStruct struct {
ID int64 `sql:"id"`
aID string `sql:"a_id"`
UserID int64 `sql:"user_id"`
And this is my generic ORM function
func GetSqlColumnToFieldMap(model *ExampleStruct) map[string]interface{} {
typeOfModel := reflect.TypeOf(*model)
ValueOfModel := reflect.ValueOf(*model)
columnToDataPointerMap := make(map[string]interface{})
for i := 0; i < ValueOfModel.NumField(); i++ {
sql_column := typeOfModel.Field(i).Tag.Get("sql")
structValue := ValueOfModel.Field(i)
columnToDataPointerMap[sql_column] = structValue.Addr()
}
return columnToDataPointerMap
}
Once this method works fine i can use the map it generates to create an ordered list of sql pointers according to the column_names i get in rows() object
However i get below error on the .Addr() method call
panic: reflect.Value.Addr of unaddressable value [recovered]
panic: reflect.Value.Addr of unaddressable value
Is it not possible to do this ?
Also in an ideal scenario i would want the method to take an interface instead of *ExampleStruct so that it can be reused across different db models.
The error says the value whose address you want to get is unaddressable. This is because even though you pass a pointer to GetSqlColumnToFieldMap(), you immediately dereference it and work with a non-pointer value later on.
This value is wrapped in an interface{} when passed to reflect.ValueOf(), and values wrappped in interfaces are not addressable.
You must not dereference the pointer, but instead use Type.Elem() and Value.Elem() to get the element type and pointed value.
Something like this:
func GetSqlColumnToFieldMap(model *ExampleStruct) map[string]interface{} {
t := reflect.TypeOf(model).Elem()
v := reflect.ValueOf(model).Elem()
columnToDataPointerMap := make(map[string]interface{})
for i := 0; i < v.NumField(); i++ {
sql_column := t.Field(i).Tag.Get("sql")
structValue := v.Field(i)
columnToDataPointerMap[sql_column] = structValue.Addr()
}
return columnToDataPointerMap
}
With this simple change it works! And it doesn't depend on the parameter type, you may change it to interface{} and pass any struct pointers.
func GetSqlColumnToFieldMap(model interface{}) map[string]interface{} {
// ...
}
Testing it:
type ExampleStruct struct {
ID int64 `sql:"id"`
AID string `sql:"a_id"`
UserID int64 `sql:"user_id"`
}
type Point struct {
X int `sql:"x"`
Y int `sql:"y"`
}
func main() {
fmt.Println(GetSqlColumnToFieldMap(&ExampleStruct{}))
fmt.Println(GetSqlColumnToFieldMap(&Point{}))
}
Output (try it on the Go Playground):
map[a_id:<*string Value> id:<*int64 Value> user_id:<*int64 Value>]
map[x:<*int Value> y:<*int Value>]
Note that Value.Addr() returns the address wrapped in a reflect.Value. To "unwrap" the pointer, use Value.Interface():
func GetSqlColumnToFieldMap(model interface{}) map[string]interface{} {
t := reflect.TypeOf(model).Elem()
v := reflect.ValueOf(model).Elem()
m := make(map[string]interface{})
for i := 0; i < v.NumField(); i++ {
colName := t.Field(i).Tag.Get("sql")
field := v.Field(i)
m[colName] = field.Addr().Interface()
}
return m
}
This will output (try it on the Go Playground):
map[a_id:0xc00007e008 id:0xc00007e000 user_id:0xc00007e018]
map[x:0xc000018060 y:0xc000018068]
For an in-depth introduction to reflection, please read blog post: The Laws of Reflection
I'm creating an API that will receive an object in a specific route. In this route I can receive a single object or a bulk of it.
Example:
[{"foo":"bar"}]
{"foo":"bar"}
How can I know if the body request is a slice or a single object before de json.Unmarshal. Moreover, if this is not possible, what is the best way to accept this two types of body requests and convert them to a list of objects?
I expect something like this:
type Foo struct {
Foo string `json:"foo"`
}
func Bla() []Foo {
fakeBody := []byte(`[{"foo":"bar"}]`)
fakeBody2 := []byte(`{"foo":"bar"}`)
var foo []Foo
// If fakeBody contains a array of objects
// then parse it to the foo slice variable normally
// So, if the fakeBody2 is a single object then
// parse this single object to the foo slice that will contain only
// one element.
return foo
}
This is what I would consider doing in this situation, in this order:
You can read the body, and check the first non-space character to see if it is '[' or '{', and unmarshal based on that.
You can first unmarshal as an array, then if that fails, as a single object.
You can unmarshal to an interface{}, do a type assertion, and parse the contents yourself.
Check the first non-whitespace byte to determine if the JSON document is an array or object. Decode accordingly.
func decode(body []byte) ([]Foo, error) {
b = bytes.TrimLeft(body, " \t\n\r")
if len(b) > 0 && b[0] == '[' {
var v []Foo
err := json.Unmarshal(body, &v)
return v, err
}
var v [1]Foo
err := json.Unmarshal(body, &v[0])
return v[:], err
}
Why not just add the [ the and ] if it's not their, and then always treat it as an array?
body := []byte(`{"foo":"bar"}`)
body = bytes.TrimSpace(body)
if len(body) > 0 && body[0] != '[' {
tmp := make([]byte, len(body)+2, len(body)+2)
tmp[0] = '['
tmp[len(tmp)-1] = ']'
copy(tmp[1:len(tmp)-1], body)
body = tmp
}
https://play.golang.org/p/YfnLgN9q64F
Or, create the array first, and then based on the first character either marshal into the array or the first item:
f := make([]Foo, 1)
body := []byte(`{"foo":"bar"}`)
if len(body) > 0 && body[0] != '[' {
json.Unmarshal(body, &f[0])
} else {
json.Unmarshal(body, &f)
}
fmt.Println(f)
https://play.golang.org/p/1fxBKH3ZJyH
I am having problems getting the golang validator to work with SQL null types. Here's an example of what I tried:
package main
import (
"database/sql"
"database/sql/driver"
"log"
"gopkg.in/go-playground/validator.v9"
)
// NullInt64
type NullInt64 struct {
sql.NullInt64
Set bool
}
func MakeNullInt64(valid bool, val int64) NullInt64 {
n := NullInt64{}
n.Set = true
n.Valid = valid
if valid {
n.Int64 = val
}
return n
}
func (n *NullInt64) Value() (driver.Value, error) {
if !n.NullInt64.Valid {
return nil, nil
}
return n.NullInt64.Int64, nil
}
type Thing struct {
N2 NullInt64 `validate:"min=10"`
N3 int64 `validate:"min=10"`
N4 *int64 `validate:"min=10"`
}
func main() {
validate := validator.New()
n := int64(6)
number := MakeNullInt64(true, n)
thing := Thing{number, n, &n}
e := validate.Struct(thing)
log.Println(e)
}
When I run this code, I only get this output:
Key: 'Thing.N3' Error:Field validation for 'N3' failed on the 'min'
tag
Key: 'Thing.N4' Error:Field validation for 'N4' failed on the
'min' tag
The problem is that I want it to also show that Thing.N2 failed for the same reasons as Thing.N3 and Thing.N4.
I tried introducing the func (n *NullInt64) Value() method because it was mentioned in the documentation. But I think I misunderstood something. Can anyone tell me what I did wrong?
UPDATE
There is an Example specifically for that. You may check it out. My other proposed solution should still work though.
Since the value you are trying to validate is Int64 inside sql.NullInt64, the easiest way would be to remove the validate tag and just register a Struct Level validation using:
validate.RegisterStructValidation(NullInt64StructLevelValidation, NullInt64{})
while NullInt64StructLevelValidation is a StructLevelFunc that looks like this:
func NullInt64StructLevelValidation(sl validator.StructLevel) {
ni := sl.Current().Interface().(NullInt64)
if ni.NullInt64.Int64 < 10 {
sl.ReportError(ni.NullInt64.Int64, "Int64", "", "min", "")
}
}
Note #1: this line thing := Thing{number,&number,n,&n} has one argument too many. I assume you meant thing := Thing{number, n, &n}
Note #2: Go tooling including gofmt is considered to be one of the most powerful features of the language. Please consider using it/them.
EDIT #1:
I don't think implementing Valuer interface is of any value in this context.
I am trying to create a bot and retrieve the list of channels.
I used the bot example in repository and it is mostly working, except for the part where it has to get the list of channels.
Either I am doing something silly or GetChannels API really does not work the way it is described in bot_sample.go .
I made a smaller separate function to test that part.
Adding code here for better readability:
func mattermostPrintChannels(client *mattermost.Client) {
channelsResult, err := client.GetChannels("")
if err != nil {
fmt.Print("Couldn't get channels: ", err)
return
}
channelList := channelsResult.Data.(*mattermost.ChannelList)
fmt.Print("Channels:")
for _, channel := range channelList.Channels {
fmt.Printf("%s -> %s", channel.Id, channel.DisplayName)
}
}
This code gives me the error:
./mattermost.go:30: channelList.Channels undefined (type
*model.ChannelList has no field or method Channels)
Now if I just print the contents of ChannelList variable (using spew), I get the following:
channelList: : ([]interface {}) (len=1 cap=1) {
(*model.ChannelList)(<nil>)
}
JimB is correct. The model.ChannelList type used to be a struct, but it recently changed to []*model.Channel. You'll want to change
for _, channel := range channelList.Channels {
to
for _, channel := range *channelList {
I was wondering if it is possible to dynamically create variables in Go?
I have provided a pseudo-code below to illustrate what I mean. I am storing the newly created variables in a slice:
func method() {
slice := make([]type)
for(i=0;i<10;i++)
{
var variable+i=i;
slice := append(slice, variablei)
}
}
At the end of the loop, the slice should contain the variables: variable1, variable2...variable9
Go has no dynamic variables.
Dynamic variables in most languages are implemented as Map (Hashtable).
So you can have one of following maps in your code that will do what you want
var m1 map[string]int
var m2 map[string]string
var m3 map[string]interface{}
here is Go code that does what you what
http://play.golang.org/p/d4aKTi1OB0
package main
import "fmt"
func method() []int {
var slice []int
for i := 0; i < 10; i++ {
m1 := map[string]int{}
key := fmt.Sprintf("variable%d", i)
m1[key] = i
slice = append(slice, m1[key])
}
return slice
}
func main() {
fmt.Println(method())
}
No; you cannot refer to local variables if you don’t know their names at compile-time.
If you need the extra indirection you can do it using pointers instead.
func function() {
slice := []*int{}
for i := 0; i < 10; i++ {
variable := i
slice = append(slice, &variable)
}
// slice now contains ten pointers to integers
}
Also note that the parentheses in the for loop ought to be omitted, and putting the opening brace on a new line is a syntax error due to automatic semicolon insertion after ++. makeing a slice requires you to pass a length, hence I don’t use it since append is used anyway.