The following code snippet is a constituent piece of the instructions.go file in geth.
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
topics := make([]common.Hash, size)
stack := scope.Stack
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
addr := stack.pop()
topics[i] = addr.Bytes32()
}
d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
interpreter.evm.StateDB.AddLog(&types.Log{
Address: scope.Contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
})
return nil, nil
}
}
The question is, how does log0 ,log1,Log2 etc opcode works and what is their use in Ethereum virtual machine?
The LOG<n> opcodes are used for emitting event logs.
The <n> value depends on the number of indexed and non-indexed topics of the event. Since the <n> value is limited (currently at 4), there's also a limit of max indexed topics per each event definition (currently 3, so it's possible to process unindexed topics of the same event as well).
Example in Solidity:
event MyEmptyEvent();
event MyEvent(bool indexed, bool indexed, bool, bool);
function foo() external {
// Produces the `LOG0` opcode as there are no topics
emit MyEmptyEvent();
// Produces the `LOG3` opcode
// as the 2 indexed topics are stored separately
// but the unindexed topics are stored as 1 topic with concatenated value
emit MyEvent(true, true, true, true);
}
After a transaction is included in a mined block, the produced event logs are broadcasted along with other state changes (e.g. storage values and address balances).
There's a great article describing the details in more depth.
Related
Question:
I wrote a Sell() function which do stock reduction for a list goods in user's shopping cart. Assume there will be thousands of request within a second for those goods. Since we need to improve the throughput and make sure the service is not down under pressure or network error, etc. We deploy the inventory service in multiple servers. Here we have one database for inventory service.
We need transaction as we have a list of goods which in process, if one of the goods failed to do the stock reduction, we have to rollback.
We need a Redis distributed lock to make sure data consistency. Only one thread/routine will access/change the information of a specific goods at a time.
Since we need to place the loop inside between start transaction and commit() to ensure the property of transaction. We have to lock before transaction and unlock after commit. But this will make transaction Serialized. I am trying to use a fine-grained Redis lock which is basically every goods generates a lock using its ID. Clearly my code is wrong. I know there could be other options like optimistic lock Pessimistic Lock. But How do I implement this idea with Redis lock?
I simplified it as follows:
// assume no lock or unlock error, stock is enough, goodsID exist
tx := DB.Begin() // begin transaction
loop a list of goods in shop cart
for _, good = range [] goods {
mutex := GetRedisLock(good.ID) // for each item, get a distributed Redis lock by its name
mutex.lock()
inv := DB.Getby(goodID) // get inventory by goodID
inv.Stock -= good.ReductionNum // do stock reduction for this item
tx.Save(inv) // save current value to database
mutex.Unlock()
}
tx.Commit()
demo code in go:
func (*InventoryServer) Sell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {
client := goredislib.NewClient(&goredislib.Options{
Addr: "localhost:6379",
})
pool := goredis.NewPool(client)
rs := redsync.New(pool)
// start transaction
tx := global.DB.Begin()
for _, goodInfo := range req.GoodsInfo {
var inv model.Inventory
// create a new distributed lock for each goodID which needs to do reduction
mutex := rs.NewMutex(fmt.Sprintf("goodsID:%d", goodInfo.GoodsId))
if err := mutex.Lock(); err != nil {
return nil, status.Errorf(codes.Internal, "get redis lock error")
}
if result := global.DB.Where(&model.Inventory{Goods: goodInfo.GoodsId}).First(&inv); result.RowsAffected == 0 {
tx.Rollback()
return nil, status.Errorf(codes.NotFound, "no stock info")
}
if inv.Stocks < goodInfo.Num {
tx.Rollback()
return nil, status.Errorf(codes.ResourceExhausted, "not enough stock")
}
inv.Stocks -= goodInfo.Num
tx.Save(&inv)
if ok, err := mutex.Unlock(); !ok || err != nil {
return nil, status.Errorf(codes.Internal, "release redis lock error")
}
}
tx.Commit()
return &emptypb.Empty{}, nil
}
I have a requirement to save either [] or a list with different integer values like [1, 7, 8]. These values can be anything between 1-31.
My struct for this field (DateOfMonth) is:
type Subscription struct {
gorm.Model
Enabled bool `gorm:"DEFAULT:True"`
Deleted bool `gorm:"DEFAULT:False"`
UserID uint `gorm:"not null"`
Cap int `gorm:"DEFAULT:-1"`
DateOfMonth []int64 `gorm:"type:json default '[]'::json"`
}
Now, I need to read this value in an API and compare it with the current_date.
For this, I have tried:
type Result struct {
ID uint
Email string
UniqueIdentifier string
Cap int
DateOfMonth []uint8
}
var subscriptions []Result
if err := db.Table("users").Select("users.id, users.email, users.unique_identifier, subscriptions.cap, subscriptions.date_of_month").Joins("join subscriptions on users.id = subscriptions.user_id").Where("subscriptions.subscription_type_id=? and users.is_verified=? and subscriptions.enabled=?", subscription_type_id, true, true).Find(&subscriptions).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": true, "reason": "Subscribers not found!", "code": http.StatusBadRequest, "status": "failure"})
return
}
If I change DateOfMonth []uint8 to DateOfMonth []int64, it gives error.
The value that I receive in this field is a list of byte values
For example, [] -> [91 93] and [6] -> [91 54 93]
If I do, bytes.NewBuffer(s.DateOfMonth), I get the correct value but then I need to iterate over this slice to compare it with today's date. I have tried a lot of ways to get the actual value (6) in the loop (dom value) but to no avail.
// if len(s.DateOfMonth) > 0 {
// // date_of_month_new := binary.BigEndian.Uint64(date_of_month)
// todays_date_of_month := time.Now().Day()
// fmt.Println(todays_date_of_month) //, date_of_month, reflect.TypeOf(date_of_month))
// for _, dom := range s.DateOfMonth {
// fmt.Println("help", reflect.TypeOf(dom), dom, todays_date_of_month)
// // if dom == todays_date_of_month {
// // fmt.Println("matching", dom, todays_date_of_month)
// // }
// }
// }
I have even tried suggestions from various answers like this, this, this
What am I missing here? Your help will be highly appreciated.
Some of the errors that I got:
invalid sql type DateOfMonth (slice) for postgres
Golang cannot range over pointer to slice
cannot range over bytes.NewBuffer(s.DateOfMonth) (type *bytes.Buffer)
sql: Scan error on column index 4, name "date_of_month": unsupported Scan, storing driver.Value type []uint8 into type *[]int
Golang cannot range over pointer to slice
You are iterating over a pointer to a slice, instead of a slice. This means you will have to first de-reference your variable and then loop over it. Check out this example.
cannot range over bytes.NewBuffer(s.DateOfMonth) (type *bytes.Buffer)
You cannot range over type *bytes.Buffer. You can instead access the bytes of the type by using the method Buffer.Bytes(). Check out this example.
sql: Scan error on column index 4, name "date_of_month": unsupported Scan, storing driver.Value type []uint8 into type *[]int
Judging by the error I'm guessing this happens when you use type []int64 while scanning DateOfMonth. One of the possibilities for this error is your database storing the values as []uint8 instead of []int64.
invalid sql type DateOfMonth (slice) for postgres
I'll try and update my answer after I am able to reproduce this error successfully.
Here is the code I'm referring to:
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
Following is the output when it is run:
0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90
I don't get how x is being assigned in the return statement in the adder function? It does not seem to be passed anywhere in the function.
I also don't get how the sum variable works. Shouldn't it get reset everytime the function adder is called and be assigned the value 0?
Go handles first-class functions and closures in a pretty typical / standard way. For some good background on closures in general, see the Wikipedia article. In this case, calling adder itself:
Creates the int object named sum with value 0.
Returns a closure: a function-like thingy1 that, when called, has access to the variable sum.
The particular function-like thingy that adder returns, which its caller captures in an ordinary variable, is a function that takes one argument. You then call it, passing the one argument. There's nothing special about this argument-passing: it works the same way as it would anywhere else. Inside the function-like thingy, using the variable x gets you the value that the caller passed. Using the name sum gets you the captured int object, whatever its value is. Returning from the function leaves the captured int still captured, so a later call to the same function-like thingy sees the updated int in sum.
By calling adder twice, you get two slightly-different function-like thingies: each one has its own private sum. Both of these private sums are initially zero. Calling the function-like thingy whose value you've saved in pos gets you the function that uses one of them. Calling the slightly-different function-like thingy whose value you've saved in neg gets you the function that uses the other one.
1There's no real difference between this "function-like thingy" and an actual function except that this particular function-like thingy doesn't have a name by which you can invoke it. That's more or less what it means to have first-class functions.
If you're stuck on readability issues...
The original form of this is:
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
Let's rewrite this with a few type names and other syntactic changes that leave the core of the code the same. First, let's make a name that means func(int) int:
type adderClosure func(int) int
Then we can use that to rewrite adders first line:
func adder() adderClosure {
...
}
Now let's make a local variable inside adder to hold the function we're going to return. To be explicit and redundant, we can use this type again:
var ret adderClosure // not good style: just for illustration
Let's now assign that variable to our closure by doing this:
sum := 0
ret = func(x int) int {
sum += x
return sum
}
and then we can return ret to return the closure. Here's the complete code on the Go Playground.
The sum variable is inside each of the two closures when you assign pos and neg. The sum in the pos closure is updated by adding 1, 2, 3, 4 (fibonacci style) while the sum in the neg closure is updated by subtracting 2*1, 2*2, 2*3, 2*4 in each of the loop iterations.
Or, in more detail:
pos := adder() assigns to pos a function having a closure on sum where sum is 0 to begin. Then whenever you call the function pos, it will updated sum accordingly. The exact same is true with neg, and any other similar assignment.
Here's some similar (simpler) code in JavaScript to run in your browser console:
function adder() {
var sum = 0;
return function(i) {
sum += i;
return sum;
}
}
var pos = adder();
console.log( pos(1) ); // add 1 to 0 (1)
console.log( pos(2) ); // add 2 to 1 (3)
console.log( pos(3) ); // add 3 to 3 (6)
console.log( pos(4) ); // add 4 to 6 (10)
Here's some background about Closures in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Hope this helps.
I tried to rely on type inference for a function with signature:
proc mode(data: [?]int)
but the compiler said it could not resolve the return type (which is a warning in in itself I guess given there are only two return statements). I tried:
proc mode(data: [?]int): [?]int
but the compiler then said there was an internal error:
internal error: CAL0057 chpl Version 1.13.1.518d486
What is the correct way of specifying that the length of an array returned by a function can only be known at run time?
If the domain/size of the array being returned cannot be described directly in the function prototype, I believe your best bet at present is to omit any description of the return type and lean on Chapel's type inference machinery to determine that you're returning an array (as you attempted). For instance, here is a procedure that reads in an array of previously unknown size and returns it:
proc readArrFromConsole() {
var len = stdin.read(int);
var X: [1..len] real;
for x in X do
x = stdin.read(real);
return X;
}
var A = readArrFromConsole();
writeln(A);
Running it and typing this at the console:
3 1.2 3.4 5.6
Generates:
1.2 3.4 5.6
Your question mentions multiple return statements, which opens up the question about how aggressively Chapel unifies types across distinct arrays. A simple example with multiple arrays of the same type (each with a unique domain, size, and bounds) seems to work:
proc createArr() {
var len = stdin.read(int);
if (len > 0) {
var X: [1..len] real;
return X;
} else {
var Y: [-1..1] real;
return Y;
}
}
var A = createArr();
writeln(A);
To understand why the compiler couldn't resolve the return type in your example may require more information about what your procedure body / return statements contained.
I've come across this from time to time in recursive functions, in situations where omitting the return type fails; in this case I create a record which is an array with its domain, e.g.:
record stringarray {
var D: domain(1);
var strs : [D] string;
}
and then define the recursive array to return one of those records:
proc repeats() : stringarray {
var reps: stringarray;
//...
for child in children do {
childreps = child.repeats();
for childrep in childreps do
reps.push_back(childrep);
}
//...
return reps;
}
I was wondering why this is valid go code:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
but this isn't
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
is there a way to avoid the temporary variables?
To elaborate on my comment, the Effective Go mentions that the multi-value assignment from accessing a map key is called the "comma ok" pattern.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false.
Playground demonstrating this
We can see that this differs from calling a regular function where the compiler would tell you that something is wrong:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
On the playground this will output
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
This gives us a hint that it may be something the compiler is doing. Searching the source code for "commaOk" gives us a few places to look, including types.unpack
At the time of writing this it this the method's godoc reads:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
The key bits of this being that this method appears to determine whether or not something is actually a "comma ok" case.
Digging into that method tells us that it will check to see if the mode of the operands is indexing a map or if the mode is set to commaok (where this is defined does give us many hints on when it's used, but searching the source for assignments to commaok we can see it's used when getting a value from a channel and type assertions). Remember the bolded bit for later!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk is a parameter to the function. Checking out where unpack is called in that file we can see that all callers pass false as an argument. Searching the rest of the repository leads us to assignments.go in the Checker.initVars() method.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Since it seems that we can only use the "comma ok" pattern to get two return values when doing a multi-value assignment this seems like the right place to look! In the above code the length of the left hand side is checked, and when unpack is called the allowCommaOk parameter is the result of l == 2 && !returnPos.IsValid(). The !returnPos.IsValid() is somewhat confusing here as that would mean that the position has no file or line information associated with it, but we'll just ignore that.
Further down in that method we've got:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
So what does all of this tell us?
Since the unpack method takes an allowCommaOk parameter that's hardcoded to false everywhere except in assignment.go's Checker.initVars() method, we can probably assume that you will only ever get two values when doing an assignment and have two variables on the left-hand side.
The unpack method will determine whether or not you actually do get an ok value in return by checking if you are indexing a slice, grabbing a value from a channel, or doing a type assertion
Since you can only get the ok value when doing an assignment it looks like in your specific case you will always need to use variables
You may save a couple of key strokes by using named returns:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
But apart from that, I don't think what you want is possible.
Simply put: the reason why your second example isn't valid Go code is because the language specification says so. ;)
Indexing a map only yields a secondary value in an assignment to two variables. Return statement is not an assignment.
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Furthermore, indexing a map is not a "single call to a multi-valued function", which is one of the three ways to return values from a function (the second one, the other two not being relevant here):
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
As for your actual question: the only way to avoid temporary variables would be using non-temporary variables, but usually that would be quite unwise - and probably not much of an optimization even when safe.
So, why doesn't the language specification allow this kind of special use of map indexing (or type assertion or channel receive, both of which can also utilize the "comma ok" idiom) in return statements? That's a good question. My guess: to keep the language specification simple.
I'm no Go expert but I believe you are getting compile time error when you are trying to return the array i.e. return all[id]. The reason could be because the functions return type is specially mentioned as (Info, bool) and when you are doing return all[id] it can't map the return type of all[id] to (Info, bool).
However the solution mentioned above, the variables being returned i and ok are the same that are mentioned in the return type of the function (i Info, ok bool) and hence the compiler knows what it's returning as opposed to just doing (i Info, ok bool).
By default, maps in golang return a single value when accessing a key
https://blog.golang.org/go-maps-in-action
Hence, return all[id] won't compile for a function that expects 2 return values.