Merge branch 'develop' into qt5.4
This commit is contained in:
		
							
								
								
									
										155
									
								
								accounts/abi/abi.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								accounts/abi/abi.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					package abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Callable method given a `Name` and whether the method is a constant.
 | 
				
			||||||
 | 
					// If the method is `Const` no transaction needs to be created for this
 | 
				
			||||||
 | 
					// particular Method call. It can easily be simulated using a local VM.
 | 
				
			||||||
 | 
					// For example a `Balance()` method only needs to retrieve something
 | 
				
			||||||
 | 
					// from the storage and therefor requires no Tx to be send to the
 | 
				
			||||||
 | 
					// network. A method such as `Transact` does require a Tx and thus will
 | 
				
			||||||
 | 
					// be flagged `true`.
 | 
				
			||||||
 | 
					// Input specifies the required input parameters for this gives method.
 | 
				
			||||||
 | 
					type Method struct {
 | 
				
			||||||
 | 
						Name   string
 | 
				
			||||||
 | 
						Const  bool
 | 
				
			||||||
 | 
						Input  []Argument
 | 
				
			||||||
 | 
						Return Type // not yet implemented
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns the methods string signature according to the ABI spec.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     function foo(uint32 a, int b)    =    "foo(uint32,int256)"
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Please note that "int" is substitute for its canonical representation "int256"
 | 
				
			||||||
 | 
					func (m Method) String() (out string) {
 | 
				
			||||||
 | 
						out += m.Name
 | 
				
			||||||
 | 
						types := make([]string, len(m.Input))
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
						for _, input := range m.Input {
 | 
				
			||||||
 | 
							types[i] = input.Type.String()
 | 
				
			||||||
 | 
							i++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						out += "(" + strings.Join(types, ",") + ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m Method) Id() []byte {
 | 
				
			||||||
 | 
						return crypto.Sha3([]byte(m.String()))[:4]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Argument holds the name of the argument and the corresponding type.
 | 
				
			||||||
 | 
					// Types are used when packing and testing arguments.
 | 
				
			||||||
 | 
					type Argument struct {
 | 
				
			||||||
 | 
						Name string
 | 
				
			||||||
 | 
						Type Type
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *Argument) UnmarshalJSON(data []byte) error {
 | 
				
			||||||
 | 
						var extarg struct {
 | 
				
			||||||
 | 
							Name string
 | 
				
			||||||
 | 
							Type string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := json.Unmarshal(data, &extarg)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("argument json err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a.Type, err = NewType(extarg.Type)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						a.Name = extarg.Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The ABI holds information about a contract's context and available
 | 
				
			||||||
 | 
					// invokable methods. It will allow you to type check function calls and
 | 
				
			||||||
 | 
					// packs data accordingly.
 | 
				
			||||||
 | 
					type ABI struct {
 | 
				
			||||||
 | 
						Methods map[string]Method
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// tests, tests whether the given input would result in a successful
 | 
				
			||||||
 | 
					// call. Checks argument list count and matches input to `input`.
 | 
				
			||||||
 | 
					func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) {
 | 
				
			||||||
 | 
						method := abi.Methods[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var ret []byte
 | 
				
			||||||
 | 
						for i, a := range args {
 | 
				
			||||||
 | 
							input := method.Input[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							packed, err := input.Type.pack(a)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("`%s` %v", name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret = append(ret, packed...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Pack the given method name to conform the ABI. Method call's data
 | 
				
			||||||
 | 
					// will consist of method_id, args0, arg1, ... argN. Method id consists
 | 
				
			||||||
 | 
					// of 4 bytes and arguments are all 32 bytes.
 | 
				
			||||||
 | 
					// Method ids are created from the first 4 bytes of the hash of the
 | 
				
			||||||
 | 
					// methods string signature. (signature = baz(uint32,string32))
 | 
				
			||||||
 | 
					func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
 | 
				
			||||||
 | 
						method, exist := abi.Methods[name]
 | 
				
			||||||
 | 
						if !exist {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("method '%s' not found", name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// start with argument count match
 | 
				
			||||||
 | 
						if len(args) != len(method.Input) {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Input))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arguments, err := abi.pack(name, args...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set function id
 | 
				
			||||||
 | 
						packed := abi.Methods[name].Id()
 | 
				
			||||||
 | 
						packed = append(packed, arguments...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return packed, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (abi *ABI) UnmarshalJSON(data []byte) error {
 | 
				
			||||||
 | 
						var methods []Method
 | 
				
			||||||
 | 
						if err := json.Unmarshal(data, &methods); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						abi.Methods = make(map[string]Method)
 | 
				
			||||||
 | 
						for _, method := range methods {
 | 
				
			||||||
 | 
							abi.Methods[method.Name] = method
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func JSON(reader io.Reader) (ABI, error) {
 | 
				
			||||||
 | 
						dec := json.NewDecoder(reader)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var abi ABI
 | 
				
			||||||
 | 
						if err := dec.Decode(&abi); err != nil {
 | 
				
			||||||
 | 
							return ABI{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return abi, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										330
									
								
								accounts/abi/abi_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								accounts/abi/abi_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,330 @@
 | 
				
			|||||||
 | 
					package abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const jsondata = `
 | 
				
			||||||
 | 
					[
 | 
				
			||||||
 | 
						{ "name" : "balance", "const" : true },
 | 
				
			||||||
 | 
						{ "name" : "send", "const" : false, "input" : [ { "name" : "amount", "type" : "uint256" } ] }
 | 
				
			||||||
 | 
					]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const jsondata2 = `
 | 
				
			||||||
 | 
					[
 | 
				
			||||||
 | 
						{ "name" : "balance", "const" : true },
 | 
				
			||||||
 | 
						{ "name" : "send", "const" : false, "input" : [ { "name" : "amount", "type" : "uint256" } ] },
 | 
				
			||||||
 | 
						{ "name" : "test", "const" : false, "input" : [ { "name" : "number", "type" : "uint32" } ] },
 | 
				
			||||||
 | 
						{ "name" : "string", "const" : false, "input" : [ { "name" : "input", "type" : "string" } ] },
 | 
				
			||||||
 | 
						{ "name" : "bool", "const" : false, "input" : [ { "name" : "input", "type" : "bool" } ] },
 | 
				
			||||||
 | 
						{ "name" : "address", "const" : false, "input" : [ { "name" : "input", "type" : "address" } ] },
 | 
				
			||||||
 | 
						{ "name" : "string32", "const" : false, "input" : [ { "name" : "input", "type" : "string32" } ] },
 | 
				
			||||||
 | 
						{ "name" : "uint64[2]", "const" : false, "input" : [ { "name" : "input", "type" : "uint64[2]" } ] },
 | 
				
			||||||
 | 
						{ "name" : "uint64[]", "const" : false, "input" : [ { "name" : "input", "type" : "uint64[]" } ] },
 | 
				
			||||||
 | 
						{ "name" : "foo", "const" : false, "input" : [ { "name" : "input", "type" : "uint32" } ] },
 | 
				
			||||||
 | 
						{ "name" : "bar", "const" : false, "input" : [ { "name" : "input", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
 | 
				
			||||||
 | 
						{ "name" : "slice", "const" : false, "input" : [ { "name" : "input", "type" : "uint32[2]" } ] },
 | 
				
			||||||
 | 
						{ "name" : "slice256", "const" : false, "input" : [ { "name" : "input", "type" : "uint256[2]" } ] }
 | 
				
			||||||
 | 
					]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestType(t *testing.T) {
 | 
				
			||||||
 | 
						typ, err := NewType("uint32")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Kind != reflect.Ptr {
 | 
				
			||||||
 | 
							t.Error("expected uint32 to have kind Ptr")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typ, err = NewType("uint32[]")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Kind != reflect.Slice {
 | 
				
			||||||
 | 
							t.Error("expected uint32[] to have type slice")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Type != ubig_ts {
 | 
				
			||||||
 | 
							t.Error("expcted uith32[] to have type uint64")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typ, err = NewType("uint32[2]")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Kind != reflect.Slice {
 | 
				
			||||||
 | 
							t.Error("expected uint32[2] to have kind slice")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Type != ubig_ts {
 | 
				
			||||||
 | 
							t.Error("expcted uith32[2] to have type uint64")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ.Size != 2 {
 | 
				
			||||||
 | 
							t.Error("expected uint32[2] to have a size of 2")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestReader(t *testing.T) {
 | 
				
			||||||
 | 
						Uint256, _ := NewType("uint256")
 | 
				
			||||||
 | 
						exp := ABI{
 | 
				
			||||||
 | 
							Methods: map[string]Method{
 | 
				
			||||||
 | 
								"balance": Method{
 | 
				
			||||||
 | 
									"balance", true, nil, Type{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								"send": Method{
 | 
				
			||||||
 | 
									"send", false, []Argument{
 | 
				
			||||||
 | 
										Argument{"amount", Uint256},
 | 
				
			||||||
 | 
									}, Type{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// deep equal fails for some reason
 | 
				
			||||||
 | 
						t.Skip()
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(abi, exp) {
 | 
				
			||||||
 | 
							t.Errorf("\nabi: %v\ndoes not match exp: %v", abi, exp)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTestNumbers(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("balance"); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("balance", 1); err == nil {
 | 
				
			||||||
 | 
							t.Error("expected error for balance(1)")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("doesntexist", nil); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("doesntexist shouldn't exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("doesntexist", 1); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("doesntexist(1) shouldn't exist")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("send", big.NewInt(1000)); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i := new(int)
 | 
				
			||||||
 | 
						*i = 1000
 | 
				
			||||||
 | 
						if _, err := abi.Pack("send", i); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("expected send( ptr ) to throw, requires *big.Int instead of *int")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("send", 1000); err != nil {
 | 
				
			||||||
 | 
							t.Error("expected send(1000) to cast to big")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("test", uint32(1000)); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTestString(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("string", "hello world"); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str10 := string(make([]byte, 10))
 | 
				
			||||||
 | 
						if _, err := abi.Pack("string32", str10); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str32 := string(make([]byte, 32))
 | 
				
			||||||
 | 
						if _, err := abi.Pack("string32", str32); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str33 := string(make([]byte, 33))
 | 
				
			||||||
 | 
						if _, err := abi.Pack("string32", str33); err == nil {
 | 
				
			||||||
 | 
							t.Error("expected str33 to throw out of bound error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTestBool(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("bool", true); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTestSlice(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr := make([]byte, 20)
 | 
				
			||||||
 | 
						if _, err := abi.Pack("address", addr); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = make([]byte, 21)
 | 
				
			||||||
 | 
						if _, err := abi.Pack("address", addr); err == nil {
 | 
				
			||||||
 | 
							t.Error("expected address of 21 width to throw")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slice := make([]byte, 2)
 | 
				
			||||||
 | 
						if _, err := abi.Pack("uint64[2]", slice); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := abi.Pack("uint64[]", slice); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTestAddress(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr := make([]byte, 20)
 | 
				
			||||||
 | 
						if _, err := abi.Pack("address", addr); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMethodSignature(t *testing.T) {
 | 
				
			||||||
 | 
						String, _ := NewType("string")
 | 
				
			||||||
 | 
						String32, _ := NewType("string32")
 | 
				
			||||||
 | 
						m := Method{"foo", false, []Argument{Argument{"bar", String32}, Argument{"baz", String}}, Type{}}
 | 
				
			||||||
 | 
						exp := "foo(string32,string)"
 | 
				
			||||||
 | 
						if m.String() != exp {
 | 
				
			||||||
 | 
							t.Error("signature mismatch", exp, "!=", m.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idexp := crypto.Sha3([]byte(exp))[:4]
 | 
				
			||||||
 | 
						if !bytes.Equal(m.Id(), idexp) {
 | 
				
			||||||
 | 
							t.Errorf("expected ids to match %x != %x", m.Id(), idexp)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uintt, _ := NewType("uint")
 | 
				
			||||||
 | 
						m = Method{"foo", false, []Argument{Argument{"bar", uintt}}, Type{}}
 | 
				
			||||||
 | 
						exp = "foo(uint256)"
 | 
				
			||||||
 | 
						if m.String() != exp {
 | 
				
			||||||
 | 
							t.Error("signature mismatch", exp, "!=", m.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPack(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sig := crypto.Sha3([]byte("foo(uint32)"))[:4]
 | 
				
			||||||
 | 
						sig = append(sig, make([]byte, 32)...)
 | 
				
			||||||
 | 
						sig[35] = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed, err := abi.Pack("foo", uint32(10))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, sig) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", sig, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMultiPack(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sig := crypto.Sha3([]byte("bar(uint32,uint16)"))[:4]
 | 
				
			||||||
 | 
						sig = append(sig, make([]byte, 64)...)
 | 
				
			||||||
 | 
						sig[35] = 10
 | 
				
			||||||
 | 
						sig[67] = 11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed, err := abi.Pack("bar", uint32(10), uint16(11))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, sig) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", sig, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPackSlice(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sig := crypto.Sha3([]byte("slice(uint32[2])"))[:4]
 | 
				
			||||||
 | 
						sig = append(sig, make([]byte, 64)...)
 | 
				
			||||||
 | 
						sig[35] = 1
 | 
				
			||||||
 | 
						sig[67] = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed, err := abi.Pack("slice", []uint32{1, 2})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, sig) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", sig, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPackSliceBig(t *testing.T) {
 | 
				
			||||||
 | 
						abi, err := JSON(strings.NewReader(jsondata2))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sig := crypto.Sha3([]byte("slice256(uint256[2])"))[:4]
 | 
				
			||||||
 | 
						sig = append(sig, make([]byte, 64)...)
 | 
				
			||||||
 | 
						sig[35] = 1
 | 
				
			||||||
 | 
						sig[67] = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed, err := abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, sig) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", sig, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								accounts/abi/doc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								accounts/abi/doc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					// Package abi implements the Ethereum ABI (Application Binary
 | 
				
			||||||
 | 
					// Interface).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The Ethereum ABI is strongly typed, known at compile time
 | 
				
			||||||
 | 
					// and static. This ABI will handle basic type casting; unsigned
 | 
				
			||||||
 | 
					// to signed and visa versa. It does not handle slice casting such
 | 
				
			||||||
 | 
					// as unsigned slice to signed slice. Bit size type casting is also
 | 
				
			||||||
 | 
					// handled. ints with a bit size of 32 will be properly cast to int256,
 | 
				
			||||||
 | 
					// etc.
 | 
				
			||||||
 | 
					package abi
 | 
				
			||||||
							
								
								
									
										106
									
								
								accounts/abi/numbers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								accounts/abi/numbers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					package abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/ethutil"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var big_t = reflect.TypeOf(&big.Int{})
 | 
				
			||||||
 | 
					var ubig_t = reflect.TypeOf(&big.Int{})
 | 
				
			||||||
 | 
					var byte_t = reflect.TypeOf(byte(0))
 | 
				
			||||||
 | 
					var byte_ts = reflect.TypeOf([]byte(nil))
 | 
				
			||||||
 | 
					var uint_t = reflect.TypeOf(uint(0))
 | 
				
			||||||
 | 
					var uint8_t = reflect.TypeOf(uint8(0))
 | 
				
			||||||
 | 
					var uint16_t = reflect.TypeOf(uint16(0))
 | 
				
			||||||
 | 
					var uint32_t = reflect.TypeOf(uint32(0))
 | 
				
			||||||
 | 
					var uint64_t = reflect.TypeOf(uint64(0))
 | 
				
			||||||
 | 
					var int_t = reflect.TypeOf(int(0))
 | 
				
			||||||
 | 
					var int8_t = reflect.TypeOf(int8(0))
 | 
				
			||||||
 | 
					var int16_t = reflect.TypeOf(int16(0))
 | 
				
			||||||
 | 
					var int32_t = reflect.TypeOf(int32(0))
 | 
				
			||||||
 | 
					var int64_t = reflect.TypeOf(int64(0))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var uint_ts = reflect.TypeOf([]uint(nil))
 | 
				
			||||||
 | 
					var uint8_ts = reflect.TypeOf([]uint8(nil))
 | 
				
			||||||
 | 
					var uint16_ts = reflect.TypeOf([]uint16(nil))
 | 
				
			||||||
 | 
					var uint32_ts = reflect.TypeOf([]uint32(nil))
 | 
				
			||||||
 | 
					var uint64_ts = reflect.TypeOf([]uint64(nil))
 | 
				
			||||||
 | 
					var ubig_ts = reflect.TypeOf([]*big.Int(nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var int_ts = reflect.TypeOf([]int(nil))
 | 
				
			||||||
 | 
					var int8_ts = reflect.TypeOf([]int8(nil))
 | 
				
			||||||
 | 
					var int16_ts = reflect.TypeOf([]int16(nil))
 | 
				
			||||||
 | 
					var int32_ts = reflect.TypeOf([]int32(nil))
 | 
				
			||||||
 | 
					var int64_ts = reflect.TypeOf([]int64(nil))
 | 
				
			||||||
 | 
					var big_ts = reflect.TypeOf([]*big.Int(nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// U256 will ensure unsigned 256bit on big nums
 | 
				
			||||||
 | 
					func U256(n *big.Int) []byte {
 | 
				
			||||||
 | 
						return ethutil.LeftPadBytes(ethutil.U256(n).Bytes(), 32)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func S256(n *big.Int) []byte {
 | 
				
			||||||
 | 
						sint := ethutil.S256(n)
 | 
				
			||||||
 | 
						ret := ethutil.LeftPadBytes(sint.Bytes(), 32)
 | 
				
			||||||
 | 
						if sint.Cmp(ethutil.Big0) < 0 {
 | 
				
			||||||
 | 
							for i, b := range ret {
 | 
				
			||||||
 | 
								if b == 0 {
 | 
				
			||||||
 | 
									ret[i] = 1
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// S256 will ensure signed 256bit on big nums
 | 
				
			||||||
 | 
					func U2U256(n uint64) []byte {
 | 
				
			||||||
 | 
						return U256(big.NewInt(int64(n)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func S2S256(n int64) []byte {
 | 
				
			||||||
 | 
						return S256(big.NewInt(n))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
 | 
				
			||||||
 | 
					func packNum(value reflect.Value, to byte) []byte {
 | 
				
			||||||
 | 
						switch kind := value.Kind(); kind {
 | 
				
			||||||
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
 | 
							if to == UintTy {
 | 
				
			||||||
 | 
								return U2U256(value.Uint())
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return S2S256(int64(value.Uint()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
 | 
							if to == UintTy {
 | 
				
			||||||
 | 
								return U2U256(uint64(value.Int()))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return S2S256(value.Int())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							// This only takes care of packing and casting. No type checking is done here. It should be done prior to using this function.
 | 
				
			||||||
 | 
							if to == UintTy {
 | 
				
			||||||
 | 
								return U256(value.Interface().(*big.Int))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return S256(value.Interface().(*big.Int))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// checks whether the given reflect value is signed. This also works for slices with a number type
 | 
				
			||||||
 | 
					func isSigned(v reflect.Value) bool {
 | 
				
			||||||
 | 
						switch v.Type() {
 | 
				
			||||||
 | 
						case ubig_ts, big_ts, big_t, ubig_t:
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t:
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										72
									
								
								accounts/abi/numbers_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								accounts/abi/numbers_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					package abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNumberTypes(t *testing.T) {
 | 
				
			||||||
 | 
						ubytes := make([]byte, 32)
 | 
				
			||||||
 | 
						ubytes[31] = 1
 | 
				
			||||||
 | 
						sbytesmin := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned := U256(big.NewInt(1))
 | 
				
			||||||
 | 
						if !bytes.Equal(unsigned, ubytes) {
 | 
				
			||||||
 | 
							t.Error("expected %x got %x", ubytes, unsigned)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						signed := S256(big.NewInt(1))
 | 
				
			||||||
 | 
						if !bytes.Equal(signed, ubytes) {
 | 
				
			||||||
 | 
							t.Error("expected %x got %x", ubytes, unsigned)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						signed = S256(big.NewInt(-1))
 | 
				
			||||||
 | 
						if !bytes.Equal(signed, sbytesmin) {
 | 
				
			||||||
 | 
							t.Error("expected %x got %x", ubytes, unsigned)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPackNumber(t *testing.T) {
 | 
				
			||||||
 | 
						ubytes := make([]byte, 32)
 | 
				
			||||||
 | 
						ubytes[31] = 1
 | 
				
			||||||
 | 
						sbytesmin := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
 | 
				
			||||||
 | 
						maxunsigned := []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed := packNum(reflect.ValueOf(1), IntTy)
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, ubytes) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", ubytes, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						packed = packNum(reflect.ValueOf(-1), IntTy)
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, sbytesmin) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", ubytes, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						packed = packNum(reflect.ValueOf(1), UintTy)
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, ubytes) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", ubytes, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						packed = packNum(reflect.ValueOf(-1), UintTy)
 | 
				
			||||||
 | 
						if !bytes.Equal(packed, maxunsigned) {
 | 
				
			||||||
 | 
							t.Errorf("expected %x got %x", maxunsigned, packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packed = packNum(reflect.ValueOf("string"), UintTy)
 | 
				
			||||||
 | 
						if packed != nil {
 | 
				
			||||||
 | 
							t.Errorf("expected 'string' to pack to nil. got %x instead", packed)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSigned(t *testing.T) {
 | 
				
			||||||
 | 
						if isSigned(reflect.ValueOf(uint(10))) {
 | 
				
			||||||
 | 
							t.Error()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !isSigned(reflect.ValueOf(int(10))) {
 | 
				
			||||||
 | 
							t.Error()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !isSigned(reflect.ValueOf(big.NewInt(10))) {
 | 
				
			||||||
 | 
							t.Error()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										106
									
								
								accounts/abi/profile.cov
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								accounts/abi/profile.cov
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					mode: set
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:27.39,31.32 4 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:35.2,37.8 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:31.32,34.3 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:40.29,42.2 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:51.53,57.16 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:61.2,62.16 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:65.2,67.12 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:57.16,59.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:62.16,64.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:79.71,83.25 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:94.2,94.17 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:83.25,87.17 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:90.3,90.31 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:87.17,89.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:102.71,104.12 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:109.2,109.36 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:113.2,114.16 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:119.2,122.20 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:104.12,106.3 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:109.36,111.3 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:114.16,116.3 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:125.50,127.55 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:131.2,132.33 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:136.2,136.12 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:127.55,129.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:132.33,134.3 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:139.42,143.41 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:147.2,147.17 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/abi.go:143.41,145.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:39.30,41.2 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:43.30,46.32 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:56.2,56.12 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:46.32,47.25 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:47.25,48.14 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:52.4,52.9 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:48.14,50.13 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:59.30,61.2 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:63.29,65.2 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:67.51,68.36 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:91.2,91.12 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:69.2,70.19 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:75.2,76.19 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:81.2,83.19 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:70.19,72.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:72.4,74.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:76.19,78.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:78.4,80.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:83.19,85.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:85.4,87.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:94.37,95.18 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:101.2,101.14 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:96.2,97.14 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/numbers.go:98.2,99.14 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:32.46,35.16 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:38.2,43.9 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:55.2,56.16 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:60.2,64.55 4 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:69.2,69.13 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:111.2,113.8 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:35.16,37.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:44.2,47.17 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:48.2,50.12 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:51.2,52.60 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:56.16,58.3 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:64.55,67.3 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:69.13,72.16 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:73.3,74.21 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:75.3,76.22 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:77.3,78.66 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:80.3,81.16 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:82.3,86.17 4 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:87.3,91.18 4 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:92.3,93.27 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:94.3,95.30 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:96.3,100.21 4 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:101.3,104.17 3 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:107.3,108.60 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:104.17,106.5 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:116.37,118.2 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:126.51,128.36 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:179.2,179.20 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:129.2,130.23 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:133.3,133.34 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:134.2,135.23 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:138.3,138.34 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:139.2,142.49 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:145.3,145.34 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:146.2,147.42 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:150.3,150.60 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:151.2,152.42 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:157.3,157.23 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:162.3,162.78 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:166.3,167.36 2 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:170.3,170.21 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:171.2,172.19 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:130.23,132.4 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:135.23,137.4 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:142.49,144.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:147.42,149.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:152.42,154.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:157.23,159.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:162.78,164.4 1 0
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:167.36,169.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:172.19,174.4 1 1
 | 
				
			||||||
 | 
					github.com/ethereum/go-ethereum/abi/type.go:174.4,176.4 1 0
 | 
				
			||||||
							
								
								
									
										190
									
								
								accounts/abi/type.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								accounts/abi/type.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					package abi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/ethutil"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						IntTy byte = iota
 | 
				
			||||||
 | 
						UintTy
 | 
				
			||||||
 | 
						BoolTy
 | 
				
			||||||
 | 
						SliceTy
 | 
				
			||||||
 | 
						AddressTy
 | 
				
			||||||
 | 
						RealTy
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Type is the reflection of the supported argument type
 | 
				
			||||||
 | 
					type Type struct {
 | 
				
			||||||
 | 
						Kind       reflect.Kind
 | 
				
			||||||
 | 
						Type       reflect.Type
 | 
				
			||||||
 | 
						Size       int
 | 
				
			||||||
 | 
						T          byte   // Our own type checking
 | 
				
			||||||
 | 
						stringKind string // holds the unparsed string for deriving signatures
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// New type returns a fully parsed Type given by the input string or an error if it  can't be parsed.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Strings can be in the format of:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// 	Input  = Type [ "[" [ Number ] "]" ] Name .
 | 
				
			||||||
 | 
					// 	Type   = [ "u" ] "int" [ Number ] .
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//      string     int       uint       real
 | 
				
			||||||
 | 
					//      string32   int8      uint8      uint[]
 | 
				
			||||||
 | 
					//      address    int256    uint256    real[2]
 | 
				
			||||||
 | 
					func NewType(t string) (typ Type, err error) {
 | 
				
			||||||
 | 
						// 1. full string 2. type 3. (opt.) is slice 4. (opt.) size
 | 
				
			||||||
 | 
						freg, err := regexp.Compile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return Type{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						res := freg.FindAllStringSubmatch(t, -1)[0]
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							isslice bool
 | 
				
			||||||
 | 
							size    int
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case res[3] != "":
 | 
				
			||||||
 | 
							// err is ignored. Already checked for number through the regexp
 | 
				
			||||||
 | 
							size, _ = strconv.Atoi(res[3])
 | 
				
			||||||
 | 
							isslice = true
 | 
				
			||||||
 | 
						case res[2] != "":
 | 
				
			||||||
 | 
							isslice = true
 | 
				
			||||||
 | 
							size = -1
 | 
				
			||||||
 | 
						case res[0] == "":
 | 
				
			||||||
 | 
							return Type{}, fmt.Errorf("type parse error for `%s`", t)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						treg, err := regexp.Compile("([a-zA-Z]+)([0-9]*)?")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return Type{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parsedType := treg.FindAllStringSubmatch(res[1], -1)[0]
 | 
				
			||||||
 | 
						vsize, _ := strconv.Atoi(parsedType[2])
 | 
				
			||||||
 | 
						vtype := parsedType[1]
 | 
				
			||||||
 | 
						// substitute canonical representation
 | 
				
			||||||
 | 
						if vsize == 0 && (vtype == "int" || vtype == "uint") {
 | 
				
			||||||
 | 
							vsize = 256
 | 
				
			||||||
 | 
							t += "256"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if isslice {
 | 
				
			||||||
 | 
							typ.Kind = reflect.Slice
 | 
				
			||||||
 | 
							typ.Size = size
 | 
				
			||||||
 | 
							switch vtype {
 | 
				
			||||||
 | 
							case "int":
 | 
				
			||||||
 | 
								typ.Type = big_ts
 | 
				
			||||||
 | 
							case "uint":
 | 
				
			||||||
 | 
								typ.Type = ubig_ts
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return Type{}, fmt.Errorf("unsupported arg slice type: %s", t)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							switch vtype {
 | 
				
			||||||
 | 
							case "int":
 | 
				
			||||||
 | 
								typ.Kind = reflect.Ptr
 | 
				
			||||||
 | 
								typ.Type = big_t
 | 
				
			||||||
 | 
								typ.Size = 256
 | 
				
			||||||
 | 
								typ.T = IntTy
 | 
				
			||||||
 | 
							case "uint":
 | 
				
			||||||
 | 
								typ.Kind = reflect.Ptr
 | 
				
			||||||
 | 
								typ.Type = ubig_t
 | 
				
			||||||
 | 
								typ.Size = 256
 | 
				
			||||||
 | 
								typ.T = UintTy
 | 
				
			||||||
 | 
							case "bool":
 | 
				
			||||||
 | 
								typ.Kind = reflect.Bool
 | 
				
			||||||
 | 
							case "real": // TODO
 | 
				
			||||||
 | 
								typ.Kind = reflect.Invalid
 | 
				
			||||||
 | 
							case "address":
 | 
				
			||||||
 | 
								typ.Kind = reflect.Slice
 | 
				
			||||||
 | 
								typ.Type = byte_ts
 | 
				
			||||||
 | 
								typ.Size = 20
 | 
				
			||||||
 | 
								typ.T = AddressTy
 | 
				
			||||||
 | 
							case "string":
 | 
				
			||||||
 | 
								typ.Kind = reflect.String
 | 
				
			||||||
 | 
								typ.Size = -1
 | 
				
			||||||
 | 
								if vsize > 0 {
 | 
				
			||||||
 | 
									typ.Size = 32
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return Type{}, fmt.Errorf("unsupported arg type: %s", t)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						typ.stringKind = t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t Type) String() (out string) {
 | 
				
			||||||
 | 
						return t.stringKind
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test the given input parameter `v` and checks if it matches certain
 | 
				
			||||||
 | 
					// criteria
 | 
				
			||||||
 | 
					// * Big integers are checks for ptr types and if the given value is
 | 
				
			||||||
 | 
					//   assignable
 | 
				
			||||||
 | 
					// * Integer are checked for size
 | 
				
			||||||
 | 
					// * Strings, addresses and bytes are checks for type and size
 | 
				
			||||||
 | 
					func (t Type) pack(v interface{}) ([]byte, error) {
 | 
				
			||||||
 | 
						value := reflect.ValueOf(v)
 | 
				
			||||||
 | 
						switch kind := value.Kind(); kind {
 | 
				
			||||||
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
 | 
							if t.Type != ubig_t {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return packNum(value, t.T), nil
 | 
				
			||||||
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
 | 
							if t.Type != ubig_t {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return packNum(value, t.T), nil
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							// If the value is a ptr do a assign check (only used by
 | 
				
			||||||
 | 
							// big.Int for now)
 | 
				
			||||||
 | 
							if t.Type == ubig_t && value.Type() != ubig_t {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return packNum(value, t.T), nil
 | 
				
			||||||
 | 
						case reflect.String:
 | 
				
			||||||
 | 
							if t.Size > -1 && value.Len() > t.Size {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return []byte(ethutil.LeftPadString(t.String(), 32)), nil
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							if t.Size > -1 && value.Len() > t.Size {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Address is a special slice. The slice acts as one rather than a list of elements.
 | 
				
			||||||
 | 
							if t.T == AddressTy {
 | 
				
			||||||
 | 
								return ethutil.LeftPadBytes(v.([]byte), 32), nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Signed / Unsigned check
 | 
				
			||||||
 | 
							if (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("slice of incompatible types.")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var packed []byte
 | 
				
			||||||
 | 
							for i := 0; i < value.Len(); i++ {
 | 
				
			||||||
 | 
								packed = append(packed, packNum(value.Index(i), t.T)...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return packed, nil
 | 
				
			||||||
 | 
						case reflect.Bool:
 | 
				
			||||||
 | 
							if value.Bool() {
 | 
				
			||||||
 | 
								return ethutil.LeftPadBytes(ethutil.Big1.Bytes(), 32), nil
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return ethutil.LeftPadBytes(ethutil.Big0.Bytes(), 32), nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						panic("unreached")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										95
									
								
								accounts/account_manager.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								accounts/account_manager.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
						This file is part of go-ethereum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go-ethereum is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
						it under the terms of the GNU Lesser General Public License as published by
 | 
				
			||||||
 | 
						the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
						(at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go-ethereum is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
						but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
						MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
						GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						You should have received a copy of the GNU Lesser General Public License
 | 
				
			||||||
 | 
						along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @authors
 | 
				
			||||||
 | 
					 * 	Gustav Simonsson <gustav.simonsson@gmail.com>
 | 
				
			||||||
 | 
					 * @date 2015
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This abstracts part of a user's interaction with an account she controls.
 | 
				
			||||||
 | 
					It's not an abstraction of core Ethereum accounts data type / logic -
 | 
				
			||||||
 | 
					for that see the core processing code of blocks / txs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Currently this is pretty much a passthrough to the KeyStore2 interface,
 | 
				
			||||||
 | 
					and accounts persistence is derived from stored keys' addresses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					package accounts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						crand "crypto/rand"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: better name for this struct?
 | 
				
			||||||
 | 
					type Account struct {
 | 
				
			||||||
 | 
						Address []byte
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AccountManager struct {
 | 
				
			||||||
 | 
						keyStore crypto.KeyStore2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: get key by addr - modify KeyStore2 GetKey to work with addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: pass through passphrase for APIs which require access to private key?
 | 
				
			||||||
 | 
					func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
 | 
				
			||||||
 | 
						am := &AccountManager{
 | 
				
			||||||
 | 
							keyStore: keyStore,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return *am
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
 | 
				
			||||||
 | 
						key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						signature, err = crypto.Sign(toSign, key.PrivateKey)
 | 
				
			||||||
 | 
						return signature, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (am AccountManager) NewAccount(auth string) (*Account, error) {
 | 
				
			||||||
 | 
						key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ua := &Account{
 | 
				
			||||||
 | 
							Address: key.Address,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ua, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// set of accounts == set of keys in given key store
 | 
				
			||||||
 | 
					// TODO: do we need persistence of accounts as well?
 | 
				
			||||||
 | 
					func (am *AccountManager) Accounts() ([]Account, error) {
 | 
				
			||||||
 | 
						addresses, err := am.keyStore.GetKeyAddresses()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						accounts := make([]Account, len(addresses))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, addr := range addresses {
 | 
				
			||||||
 | 
							accounts[i] = Account{
 | 
				
			||||||
 | 
								Address: addr,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return accounts, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								accounts/accounts_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								accounts/accounts_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					package accounts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAccountManager(t *testing.T) {
 | 
				
			||||||
 | 
						ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir())
 | 
				
			||||||
 | 
						am := NewAccountManager(ks)
 | 
				
			||||||
 | 
						pass := "" // not used but required by API
 | 
				
			||||||
 | 
						a1, err := am.NewAccount(pass)
 | 
				
			||||||
 | 
						toSign := crypto.GetEntropyCSPRNG(32)
 | 
				
			||||||
 | 
						_, err = am.Sign(a1, pass, toSign)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -133,8 +133,7 @@ func ImportPreSaleKey(keyStore KeyStore2, keyJSON []byte, password string) (*Key
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	id := uuid.NewRandom()
 | 
						key.Id = uuid.NewRandom()
 | 
				
			||||||
	key.Id = &id
 | 
					 | 
				
			||||||
	err = keyStore.StoreKey(key, password)
 | 
						err = keyStore.StoreKey(key, password)
 | 
				
			||||||
	return key, err
 | 
						return key, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -167,9 +166,10 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
 | 
				
			|||||||
	ecKey := ToECDSA(ethPriv)
 | 
						ecKey := ToECDSA(ethPriv)
 | 
				
			||||||
	key = &Key{
 | 
						key = &Key{
 | 
				
			||||||
		Id:         nil,
 | 
							Id:         nil,
 | 
				
			||||||
 | 
							Address:    PubkeyToAddress(ecKey.PublicKey),
 | 
				
			||||||
		PrivateKey: ecKey,
 | 
							PrivateKey: ecKey,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	derivedAddr := ethutil.Bytes2Hex(key.Address())
 | 
						derivedAddr := ethutil.Bytes2Hex(key.Address)
 | 
				
			||||||
	expectedAddr := preSaleKeyStruct.EthAddr
 | 
						expectedAddr := preSaleKeyStruct.EthAddr
 | 
				
			||||||
	if derivedAddr != expectedAddr {
 | 
						if derivedAddr != expectedAddr {
 | 
				
			||||||
		err = errors.New("decrypted addr not equal to expected addr")
 | 
							err = errors.New("decrypted addr not equal to expected addr")
 | 
				
			||||||
@@ -223,3 +223,8 @@ func PKCS7Unpad(in []byte) []byte {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return in[:len(in)-int(padding)]
 | 
						return in[:len(in)-int(padding)]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func PubkeyToAddress(p ecdsa.PublicKey) []byte {
 | 
				
			||||||
 | 
						pubBytes := FromECDSAPub(&p)
 | 
				
			||||||
 | 
						return Sha3(pubBytes[1:])[12:]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,9 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Key struct {
 | 
					type Key struct {
 | 
				
			||||||
	Id *uuid.UUID // Version 4 "random" for unique id not derived from key data
 | 
						Id uuid.UUID // Version 4 "random" for unique id not derived from key data
 | 
				
			||||||
 | 
						// to simplify lookups we also store the address
 | 
				
			||||||
 | 
						Address []byte
 | 
				
			||||||
	// we only store privkey as pubkey/address can be derived from it
 | 
						// we only store privkey as pubkey/address can be derived from it
 | 
				
			||||||
	// privkey in this struct is always in plaintext
 | 
						// privkey in this struct is always in plaintext
 | 
				
			||||||
	PrivateKey *ecdsa.PrivateKey
 | 
						PrivateKey *ecdsa.PrivateKey
 | 
				
			||||||
@@ -41,6 +43,7 @@ type Key struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type plainKeyJSON struct {
 | 
					type plainKeyJSON struct {
 | 
				
			||||||
	Id         []byte
 | 
						Id         []byte
 | 
				
			||||||
 | 
						Address    []byte
 | 
				
			||||||
	PrivateKey []byte
 | 
						PrivateKey []byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,18 +54,15 @@ type cipherJSON struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type encryptedKeyJSON struct {
 | 
					type encryptedKeyJSON struct {
 | 
				
			||||||
	Id     []byte
 | 
						Id      []byte
 | 
				
			||||||
	Crypto cipherJSON
 | 
						Address []byte
 | 
				
			||||||
}
 | 
						Crypto  cipherJSON
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (k *Key) Address() []byte {
 | 
					 | 
				
			||||||
	pubBytes := FromECDSAPub(&k.PrivateKey.PublicKey)
 | 
					 | 
				
			||||||
	return Sha3(pubBytes[1:])[12:]
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (k *Key) MarshalJSON() (j []byte, err error) {
 | 
					func (k *Key) MarshalJSON() (j []byte, err error) {
 | 
				
			||||||
	jStruct := plainKeyJSON{
 | 
						jStruct := plainKeyJSON{
 | 
				
			||||||
		*k.Id,
 | 
							k.Id,
 | 
				
			||||||
 | 
							k.Address,
 | 
				
			||||||
		FromECDSA(k.PrivateKey),
 | 
							FromECDSA(k.PrivateKey),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	j, err = json.Marshal(jStruct)
 | 
						j, err = json.Marshal(jStruct)
 | 
				
			||||||
@@ -78,8 +78,8 @@ func (k *Key) UnmarshalJSON(j []byte) (err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	u := new(uuid.UUID)
 | 
						u := new(uuid.UUID)
 | 
				
			||||||
	*u = keyJSON.Id
 | 
						*u = keyJSON.Id
 | 
				
			||||||
	k.Id = u
 | 
						k.Id = *u
 | 
				
			||||||
 | 
						k.Address = keyJSON.Address
 | 
				
			||||||
	k.PrivateKey = ToECDSA(keyJSON.PrivateKey)
 | 
						k.PrivateKey = ToECDSA(keyJSON.PrivateKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
@@ -101,7 +101,8 @@ func NewKey(rand io.Reader) *Key {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	id := uuid.NewRandom()
 | 
						id := uuid.NewRandom()
 | 
				
			||||||
	key := &Key{
 | 
						key := &Key{
 | 
				
			||||||
		Id:         &id,
 | 
							Id:         id,
 | 
				
			||||||
 | 
							Address:    PubkeyToAddress(privateKeyECDSA.PublicKey),
 | 
				
			||||||
		PrivateKey: privateKeyECDSA,
 | 
							PrivateKey: privateKeyECDSA,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return key
 | 
						return key
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,6 +69,7 @@ import (
 | 
				
			|||||||
	"crypto/aes"
 | 
						"crypto/aes"
 | 
				
			||||||
	"crypto/cipher"
 | 
						"crypto/cipher"
 | 
				
			||||||
	crand "crypto/rand"
 | 
						crand "crypto/rand"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
@@ -96,21 +97,26 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K
 | 
				
			|||||||
	return GenerateNewKeyDefault(ks, rand, auth)
 | 
						return GenerateNewKeyDefault(ks, rand, auth)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePassphrase) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) {
 | 
					func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
 | 
				
			||||||
	keyBytes, err := DecryptKey(ks, keyId, auth)
 | 
						keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	key = &Key{
 | 
						key = &Key{
 | 
				
			||||||
		Id:         keyId,
 | 
							Id:         uuid.UUID(keyId),
 | 
				
			||||||
 | 
							Address:    keyAddr,
 | 
				
			||||||
		PrivateKey: ToECDSA(keyBytes),
 | 
							PrivateKey: ToECDSA(keyBytes),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return key, err
 | 
						return key, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) {
 | 
				
			||||||
 | 
						return GetKeyAddresses(ks.keysDirPath)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 | 
					func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 | 
				
			||||||
	authArray := []byte(auth)
 | 
						authArray := []byte(auth)
 | 
				
			||||||
	salt := getEntropyCSPRNG(32)
 | 
						salt := GetEntropyCSPRNG(32)
 | 
				
			||||||
	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
 | 
						derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -125,7 +131,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iv := getEntropyCSPRNG(aes.BlockSize) // 16
 | 
						iv := GetEntropyCSPRNG(aes.BlockSize) // 16
 | 
				
			||||||
	AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv)
 | 
						AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv)
 | 
				
			||||||
	cipherText := make([]byte, len(toEncrypt))
 | 
						cipherText := make([]byte, len(toEncrypt))
 | 
				
			||||||
	AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
 | 
						AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
 | 
				
			||||||
@@ -136,7 +142,8 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 | 
				
			|||||||
		cipherText,
 | 
							cipherText,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	keyStruct := encryptedKeyJSON{
 | 
						keyStruct := encryptedKeyJSON{
 | 
				
			||||||
		*key.Id,
 | 
							key.Id,
 | 
				
			||||||
 | 
							key.Address,
 | 
				
			||||||
		cipherStruct,
 | 
							cipherStruct,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	keyJSON, err := json.Marshal(keyStruct)
 | 
						keyJSON, err := json.Marshal(keyStruct)
 | 
				
			||||||
@@ -144,54 +151,53 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON)
 | 
						return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePassphrase) DeleteKey(keyId *uuid.UUID, auth string) (err error) {
 | 
					func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) {
 | 
				
			||||||
	// only delete if correct passphrase is given
 | 
						// only delete if correct passphrase is given
 | 
				
			||||||
	_, err = DecryptKey(ks, keyId, auth)
 | 
						_, _, err = DecryptKey(ks, keyAddr, auth)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keyDirPath := path.Join(ks.keysDirPath, keyId.String())
 | 
						keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
 | 
				
			||||||
	return os.RemoveAll(keyDirPath)
 | 
						return os.RemoveAll(keyDirPath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DecryptKey(ks keyStorePassphrase, keyId *uuid.UUID, auth string) (keyBytes []byte, err error) {
 | 
					func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) {
 | 
				
			||||||
	fileContent, err := GetKeyFile(ks.keysDirPath, keyId)
 | 
						fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keyProtected := new(encryptedKeyJSON)
 | 
						keyProtected := new(encryptedKeyJSON)
 | 
				
			||||||
	err = json.Unmarshal(fileContent, keyProtected)
 | 
						err = json.Unmarshal(fileContent, keyProtected)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyId = keyProtected.Id
 | 
				
			||||||
	salt := keyProtected.Crypto.Salt
 | 
						salt := keyProtected.Crypto.Salt
 | 
				
			||||||
 | 
					 | 
				
			||||||
	iv := keyProtected.Crypto.IV
 | 
						iv := keyProtected.Crypto.IV
 | 
				
			||||||
 | 
					 | 
				
			||||||
	cipherText := keyProtected.Crypto.CipherText
 | 
						cipherText := keyProtected.Crypto.CipherText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	authArray := []byte(auth)
 | 
						authArray := []byte(auth)
 | 
				
			||||||
	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
 | 
						derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
 | 
						plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	keyBytes = plainText[:len(plainText)-32]
 | 
						keyBytes = plainText[:len(plainText)-32]
 | 
				
			||||||
	keyBytesHash := plainText[len(plainText)-32:]
 | 
						keyBytesHash := plainText[len(plainText)-32:]
 | 
				
			||||||
	if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
 | 
						if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
 | 
				
			||||||
		err = errors.New("Decryption failed: checksum mismatch")
 | 
							err = errors.New("Decryption failed: checksum mismatch")
 | 
				
			||||||
		return nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return keyBytes, err
 | 
						return keyBytes, keyId, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getEntropyCSPRNG(n int) []byte {
 | 
					func GetEntropyCSPRNG(n int) []byte {
 | 
				
			||||||
	mainBuff := make([]byte, n)
 | 
						mainBuff := make([]byte, n)
 | 
				
			||||||
	_, err := io.ReadFull(crand.Reader, mainBuff)
 | 
						_, err := io.ReadFull(crand.Reader, mainBuff)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
package crypto
 | 
					package crypto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"code.google.com/p/go-uuid/uuid"
 | 
						"encoding/hex"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
@@ -38,9 +38,10 @@ import (
 | 
				
			|||||||
type KeyStore2 interface {
 | 
					type KeyStore2 interface {
 | 
				
			||||||
	// create new key using io.Reader entropy source and optionally using auth string
 | 
						// create new key using io.Reader entropy source and optionally using auth string
 | 
				
			||||||
	GenerateNewKey(io.Reader, string) (*Key, error)
 | 
						GenerateNewKey(io.Reader, string) (*Key, error)
 | 
				
			||||||
	GetKey(*uuid.UUID, string) (*Key, error) // key from id and auth string
 | 
						GetKey([]byte, string) (*Key, error) // key from addr and auth string
 | 
				
			||||||
	StoreKey(*Key, string) error             // store key optionally using auth string
 | 
						GetKeyAddresses() ([][]byte, error)  // get all addresses
 | 
				
			||||||
	DeleteKey(*uuid.UUID, string) error      // delete key by id and auth string
 | 
						StoreKey(*Key, string) error         // store key optionally using auth string
 | 
				
			||||||
 | 
						DeleteKey([]byte, string) error      // delete key by addr and auth string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type keyStorePlain struct {
 | 
					type keyStorePlain struct {
 | 
				
			||||||
@@ -72,8 +73,8 @@ func GenerateNewKeyDefault(ks KeyStore2, rand io.Reader, auth string) (key *Key,
 | 
				
			|||||||
	return key, err
 | 
						return key, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err error) {
 | 
					func (ks keyStorePlain) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
 | 
				
			||||||
	fileContent, err := GetKeyFile(ks.keysDirPath, keyId)
 | 
						fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -83,32 +84,50 @@ func (ks keyStorePlain) GetKey(keyId *uuid.UUID, auth string) (key *Key, err err
 | 
				
			|||||||
	return key, err
 | 
						return key, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (ks keyStorePlain) GetKeyAddresses() (addresses [][]byte, err error) {
 | 
				
			||||||
 | 
						return GetKeyAddresses(ks.keysDirPath)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
 | 
					func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
 | 
				
			||||||
	keyJSON, err := json.Marshal(key)
 | 
						keyJSON, err := json.Marshal(key)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = WriteKeyFile(key.Id.String(), ks.keysDirPath, keyJSON)
 | 
						err = WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ks keyStorePlain) DeleteKey(keyId *uuid.UUID, auth string) (err error) {
 | 
					func (ks keyStorePlain) DeleteKey(keyAddr []byte, auth string) (err error) {
 | 
				
			||||||
	keyDirPath := path.Join(ks.keysDirPath, keyId.String())
 | 
						keyDirPath := path.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
 | 
				
			||||||
	err = os.RemoveAll(keyDirPath)
 | 
						err = os.RemoveAll(keyDirPath)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetKeyFile(keysDirPath string, keyId *uuid.UUID) (fileContent []byte, err error) {
 | 
					func GetKeyFile(keysDirPath string, keyAddr []byte) (fileContent []byte, err error) {
 | 
				
			||||||
	id := keyId.String()
 | 
						fileName := hex.EncodeToString(keyAddr)
 | 
				
			||||||
	return ioutil.ReadFile(path.Join(keysDirPath, id, id))
 | 
						return ioutil.ReadFile(path.Join(keysDirPath, fileName, fileName))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WriteKeyFile(id string, keysDirPath string, content []byte) (err error) {
 | 
					func WriteKeyFile(addr []byte, keysDirPath string, content []byte) (err error) {
 | 
				
			||||||
	keyDirPath := path.Join(keysDirPath, id)
 | 
						addrHex := hex.EncodeToString(addr)
 | 
				
			||||||
	keyFilePath := path.Join(keyDirPath, id)
 | 
						keyDirPath := path.Join(keysDirPath, addrHex)
 | 
				
			||||||
 | 
						keyFilePath := path.Join(keyDirPath, addrHex)
 | 
				
			||||||
	err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
 | 
						err = os.MkdirAll(keyDirPath, 0700) // read, write and dir search for user
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
 | 
						return ioutil.WriteFile(keyFilePath, content, 0600) // read, write for user
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetKeyAddresses(keysDirPath string) (addresses [][]byte, err error) {
 | 
				
			||||||
 | 
						fileInfos, err := ioutil.ReadDir(keysDirPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						addresses = make([][]byte, len(fileInfos))
 | 
				
			||||||
 | 
						for i, fileInfo := range fileInfos {
 | 
				
			||||||
 | 
							addresses[i] = make([]byte, 40)
 | 
				
			||||||
 | 
							addresses[i] = []byte(fileInfo.Name())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return addresses, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,12 +15,12 @@ func TestKeyStorePlain(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	k2 := new(Key)
 | 
						k2 := new(Key)
 | 
				
			||||||
	k2, err = ks.GetKey(k1.Id, pass)
 | 
						k2, err = ks.GetKey(k1.Address, pass)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !reflect.DeepEqual(k1.Id, k2.Id) {
 | 
						if !reflect.DeepEqual(k1.Address, k2.Address) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,7 +28,7 @@ func TestKeyStorePlain(t *testing.T) {
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ks.DeleteKey(k2.Id, pass)
 | 
						err = ks.DeleteKey(k2.Address, pass)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -42,11 +42,11 @@ func TestKeyStorePassphrase(t *testing.T) {
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	k2 := new(Key)
 | 
						k2 := new(Key)
 | 
				
			||||||
	k2, err = ks.GetKey(k1.Id, pass)
 | 
						k2, err = ks.GetKey(k1.Address, pass)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !reflect.DeepEqual(k1.Id, k2.Id) {
 | 
						if !reflect.DeepEqual(k1.Address, k2.Address) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,7 +54,7 @@ func TestKeyStorePassphrase(t *testing.T) {
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ks.DeleteKey(k2.Id, pass) // also to clean up created files
 | 
						err = ks.DeleteKey(k2.Address, pass) // also to clean up created files
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -68,17 +68,17 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err = ks.GetKey(k1.Id, "bar") // wrong passphrase
 | 
						_, err = ks.GetKey(k1.Address, "bar") // wrong passphrase
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ks.DeleteKey(k1.Id, "bar") // wrong passphrase
 | 
						err = ks.DeleteKey(k1.Address, "bar") // wrong passphrase
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = ks.DeleteKey(k1.Id, pass) // to clean up
 | 
						err = ks.DeleteKey(k1.Address, pass) // to clean up
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ if ls $dir/*.go &> /dev/null; then
 | 
				
			|||||||
    # echo $dir
 | 
					    # echo $dir
 | 
				
			||||||
    if [[ $dir != "./tests/vm" ]]
 | 
					    if [[ $dir != "./tests/vm" ]]
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
        go test -covermode=count -coverprofile=$dir/profile.tmp $dir
 | 
					        $GOROOT/bin/go test -covermode=count -coverprofile=$dir/profile.tmp $dir
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
    if [ -f $dir/profile.tmp ]
 | 
					    if [ -f $dir/profile.tmp ]
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
@@ -25,7 +25,7 @@ if ls $dir/*.go &> /dev/null; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go tool cover -func profile.cov
 | 
					$GOROOT/bin/go tool cover -func profile.cov
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# To submit the test coverage result to coveralls.io,
 | 
					# To submit the test coverage result to coveralls.io,
 | 
				
			||||||
# use goveralls (https://github.com/mattn/goveralls)
 | 
					# use goveralls (https://github.com/mattn/goveralls)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user