diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 773e18606..3094f2513 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -19,6 +19,7 @@ services: command: "node --config-path /config --privnet" volumes: - ../config/protocol.privnet.docker.one.yml:/config/protocol.privnet.yml + - ./wallets/wallet1.json:/wallet1.json - volume_chain:/chains networks: neo_go_network: @@ -33,6 +34,7 @@ services: command: "node --config-path /config --privnet" volumes: - ../config/protocol.privnet.docker.two.yml:/config/protocol.privnet.yml + - ./wallets/wallet2.json:/wallet2.json - volume_chain:/chains networks: neo_go_network: @@ -47,6 +49,7 @@ services: command: "node --config-path /config --privnet" volumes: - ../config/protocol.privnet.docker.three.yml:/config/protocol.privnet.yml + - ./wallets/wallet3.json:/wallet3.json - volume_chain:/chains networks: neo_go_network: @@ -61,6 +64,7 @@ services: command: "node --config-path /config --privnet" volumes: - ../config/protocol.privnet.docker.four.yml:/config/protocol.privnet.yml + - ./wallets/wallet4.json:/wallet4.json - volume_chain:/chains networks: neo_go_network: @@ -75,6 +79,7 @@ services: command: "node --config-path /config --privnet" volumes: - ../config/protocol.privnet.docker.single.yml:/config/protocol.privnet.yml + - ./wallets/wallet1.json:/wallet1.json - volume_chain:/chains - ./1600-privnet-blocks-single.acc.gz:/privnet-blocks.acc.gz networks: diff --git a/.docker/wallets/wallet1.json b/.docker/wallets/wallet1.json new file mode 100644 index 000000000..d03726fd9 --- /dev/null +++ b/.docker/wallets/wallet1.json @@ -0,0 +1 @@ +{"name":"wallet1","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AKkkumHbBipZ46UMZJoFynJMXzSRnBvKcs","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/.docker/wallets/wallet1_solo.json b/.docker/wallets/wallet1_solo.json new file mode 100644 index 000000000..ebdae79ce --- /dev/null +++ b/.docker/wallets/wallet1_solo.json @@ -0,0 +1 @@ +{"name":"wallet1","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AKkkumHbBipZ46UMZJoFynJMXzSRnBvKcs","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null},{"address":"AbU69m8WUZJSWanfr1Cy66cpEcsmMcX7BR","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"512102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc251ae","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} diff --git a/.docker/wallets/wallet2.json b/.docker/wallets/wallet2.json new file mode 100644 index 000000000..ee6136680 --- /dev/null +++ b/.docker/wallets/wallet2.json @@ -0,0 +1 @@ +{"name":"wallet2","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AWLYWXB8C9Lt1nHdDZJnC5cpYJjgRDLk17","label":null,"isDefault":false,"lock":false,"key":"6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L","contract":{"script":"2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406eac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/.docker/wallets/wallet3.json b/.docker/wallets/wallet3.json new file mode 100644 index 000000000..3c72d1751 --- /dev/null +++ b/.docker/wallets/wallet3.json @@ -0,0 +1 @@ +{"name":"wallet3","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AR3uEnLUdfm1tPMJmiJQurAXGL7h3EXQ2F","label":null,"isDefault":false,"lock":false,"key":"6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh","contract":{"script":"2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/.docker/wallets/wallet4.json b/.docker/wallets/wallet4.json new file mode 100644 index 000000000..d73ab4f7d --- /dev/null +++ b/.docker/wallets/wallet4.json @@ -0,0 +1 @@ +{"name":"wallet4","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AJmjUqf1jDenxYpuNS4i2NxD9FQYieDpBF","label":null,"isDefault":false,"lock":false,"key":"6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc","contract":{"script":"2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/config/protocol.privnet.docker.four.yml b/config/protocol.privnet.docker.four.yml index 058c97a92..4981f4fee 100644 --- a/config/protocol.privnet.docker.four.yml +++ b/config/protocol.privnet.docker.four.yml @@ -57,5 +57,5 @@ ApplicationConfiguration: Enabled: false Port: 20014 UnlockWallet: - Path: "6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc" + Path: "/wallet4.json" Password: "four" diff --git a/config/protocol.privnet.docker.one.yml b/config/protocol.privnet.docker.one.yml index 76932694e..28f7e9a3e 100644 --- a/config/protocol.privnet.docker.one.yml +++ b/config/protocol.privnet.docker.one.yml @@ -57,5 +57,5 @@ ApplicationConfiguration: Enabled: false Port: 20011 UnlockWallet: - Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y" + Path: "/wallet1.json" Password: "one" diff --git a/config/protocol.privnet.docker.single.yml b/config/protocol.privnet.docker.single.yml index 62bd270c1..3c12813aa 100644 --- a/config/protocol.privnet.docker.single.yml +++ b/config/protocol.privnet.docker.single.yml @@ -51,5 +51,5 @@ ApplicationConfiguration: Enabled: false Port: 20011 UnlockWallet: - Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y" + Path: "/wallet1.json" Password: "one" diff --git a/config/protocol.privnet.docker.three.yml b/config/protocol.privnet.docker.three.yml index 83cda9e1d..d0b83f35a 100644 --- a/config/protocol.privnet.docker.three.yml +++ b/config/protocol.privnet.docker.three.yml @@ -57,5 +57,5 @@ ApplicationConfiguration: Enabled: false Port: 20013 UnlockWallet: - Path: "6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh" + Path: "/wallet3.json" Password: "three" diff --git a/config/protocol.privnet.docker.two.yml b/config/protocol.privnet.docker.two.yml index be61e6968..9936ae13d 100644 --- a/config/protocol.privnet.docker.two.yml +++ b/config/protocol.privnet.docker.two.yml @@ -57,5 +57,5 @@ ApplicationConfiguration: Enabled: false Port: 20012 UnlockWallet: - Path: "6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L" + Path: "/wallet2.json" Password: "two" diff --git a/go.mod b/go.mod index 2110c6fcc..89a65a3f5 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/go-redis/redis v6.10.2+incompatible github.com/go-yaml/yaml v2.1.0+incompatible github.com/mr-tron/base58 v1.1.2 - github.com/nspcc-dev/dbft v0.0.0-20200116150450-80b3f6f0dff8 + github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a github.com/nspcc-dev/rfc6979 v0.2.0 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.2.1 diff --git a/go.sum b/go.sum index 5db146de9..70c367128 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254 h1:A4OkQDQOSPsJF8qU github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae h1:T5V1QANlNMKun0EPB3eqg2PTXG4rmLhzDyEiV63kdB0= github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY= -github.com/nspcc-dev/dbft v0.0.0-20200116150450-80b3f6f0dff8 h1:WjfnKH75ncU5iySB6ooTsbg2P0q1iQoecTN4gHIuEbs= -github.com/nspcc-dev/dbft v0.0.0-20200116150450-80b3f6f0dff8/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= +github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a h1:ajvxgEe9qY4vvoSmrADqdDx7hReodKTnT2IXN++qZG8= +github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk= github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= github.com/nspcc-dev/neofs-crypto v0.2.3 h1:aca3X2aly92ENRbFK+kH6Hd+J9EQ4Eu6XMVoITSIKtc= diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index 6aebda543..9ca831ac1 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -14,6 +14,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm/opcode" + "github.com/CityOfZion/neo-go/pkg/wallet" "github.com/nspcc-dev/dbft" "github.com/nspcc-dev/dbft/block" "github.com/nspcc-dev/dbft/crypto" @@ -56,6 +57,7 @@ type service struct { messages chan Payload transactions chan *transaction.Transaction lastProposal []util.Uint256 + wallet *wallet.Wallet } // Config is a configuration for consensus services. @@ -104,12 +106,18 @@ func NewService(cfg Config) (Service, error) { return srv, nil } - priv, pub := getKeyPair(cfg.Wallet) + var err error + + if srv.wallet, err = wallet.NewWalletFromFile(cfg.Wallet.Path); err != nil { + return nil, err + } + + defer srv.wallet.Close() srv.dbft = dbft.New( dbft.WithLogger(srv.log), dbft.WithSecondsPerBlock(cfg.TimePerBlock), - dbft.WithKeyPair(priv, pub), + dbft.WithGetKeyPair(srv.getKeyPair), dbft.WithTxPerBlock(10000), dbft.WithRequestTx(cfg.RequestTx), dbft.WithGetTx(srv.getTx), @@ -180,14 +188,23 @@ func (s *service) validatePayload(p *Payload) bool { return p.Verify(h) } -func getKeyPair(cfg *config.WalletConfig) (crypto.PrivateKey, crypto.PublicKey) { - // TODO: replace with wallet opening from the given path (#588) - key, err := keys.NEP2Decrypt(cfg.Path, cfg.Password) - if err != nil { - return nil, nil +func (s *service) getKeyPair(pubs []crypto.PublicKey) (int, crypto.PrivateKey, crypto.PublicKey) { + for i := range pubs { + script := pubs[i].(*publicKey).GetVerificationScript() + acc := s.wallet.GetAccount(hash.Hash160(script)) + if acc == nil { + continue + } + + key, err := keys.NEP2Decrypt(acc.EncryptedWIF, s.Config.Wallet.Password) + if err != nil { + continue + } + + return i, &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()} } - return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()} + return -1, nil, nil } // OnPayload handles Payload receive. diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 1cd450f77..2b7d0a4e4 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -7,6 +7,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" "github.com/nspcc-dev/dbft/block" "github.com/nspcc-dev/dbft/payload" @@ -182,7 +183,7 @@ func newTestService(t *testing.T) *service { Chain: newTestChain(t), RequestTx: func(...util.Uint256) {}, Wallet: &config.WalletConfig{ - Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y", + Path: "./testdata/wallet1.json", Password: "one", }, }) @@ -192,35 +193,35 @@ func newTestService(t *testing.T) *service { } func getTestValidator(i int) (*privateKey, *publicKey) { - var wallet *config.WalletConfig + var wif, password string + switch i { case 0: - wallet = &config.WalletConfig{ - Path: "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y", - Password: "one", - } + wif = "6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y" + password = "one" + case 1: - wallet = &config.WalletConfig{ - Path: "6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L", - Password: "two", - } + wif = "6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L" + password = "two" + case 2: - wallet = &config.WalletConfig{ - Path: "6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh", - Password: "three", - } + wif = "6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh" + password = "three" + case 3: - wallet = &config.WalletConfig{ - Path: "6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc", - Password: "four", - } + wif = "6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc" + password = "four" + default: return nil, nil } - priv, pub := getKeyPair(wallet) + key, err := keys.NEP2Decrypt(wif, password) + if err != nil { + return nil, nil + } - return priv.(*privateKey), pub.(*publicKey) + return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()} } func newTestChain(t *testing.T) *core.Blockchain { diff --git a/pkg/consensus/testdata/wallet1.json b/pkg/consensus/testdata/wallet1.json new file mode 100644 index 000000000..d03726fd9 --- /dev/null +++ b/pkg/consensus/testdata/wallet1.json @@ -0,0 +1 @@ +{"name":"wallet1","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AKkkumHbBipZ46UMZJoFynJMXzSRnBvKcs","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYLmjBYJ4wQTCEfqvnznGJwZeW9pfUcV5m5oreHxqryUgqKpTRAFt9L8Y","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/pkg/consensus/testdata/wallet2.json b/pkg/consensus/testdata/wallet2.json new file mode 100644 index 000000000..ee6136680 --- /dev/null +++ b/pkg/consensus/testdata/wallet2.json @@ -0,0 +1 @@ +{"name":"wallet2","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AWLYWXB8C9Lt1nHdDZJnC5cpYJjgRDLk17","label":null,"isDefault":false,"lock":false,"key":"6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L","contract":{"script":"2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406eac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYXHjPaNvW8YknSXaKsTWjf9FRxo1s4naV2jdmSQEgzaqKGX368rndN3L","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/pkg/consensus/testdata/wallet3.json b/pkg/consensus/testdata/wallet3.json new file mode 100644 index 000000000..3c72d1751 --- /dev/null +++ b/pkg/consensus/testdata/wallet3.json @@ -0,0 +1 @@ +{"name":"wallet3","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AR3uEnLUdfm1tPMJmiJQurAXGL7h3EXQ2F","label":null,"isDefault":false,"lock":false,"key":"6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh","contract":{"script":"2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYX86vYiHfUbpD95hfN1xgnvcSxy5skxfWYKu3ztjecxk6ikYs2kcWbeh","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/pkg/consensus/testdata/wallet4.json b/pkg/consensus/testdata/wallet4.json new file mode 100644 index 000000000..d73ab4f7d --- /dev/null +++ b/pkg/consensus/testdata/wallet4.json @@ -0,0 +1 @@ +{"name":"wallet4","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"accounts":[{"address":"AJmjUqf1jDenxYpuNS4i2NxD9FQYieDpBF","label":null,"isDefault":false,"lock":false,"key":"6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc","contract":{"script":"2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62ac","parameters":[{"name":"parameter0","type":"Signature"}],"deployed":false},"extra":null},{"address":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","label":null,"isDefault":false,"lock":false,"key":"6PYRXVwHSqFSukL3CuXxdQ75VmsKpjeLgQLEjt83FrtHf1gCVphHzdD4nc","contract":{"script":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae","parameters":[{"name":"parameter0","type":"Signature"},{"name":"parameter1","type":"Signature"},{"name":"parameter2","type":"Signature"}],"deployed":false},"extra":null}],"extra":null} \ No newline at end of file diff --git a/pkg/wallet/account.go b/pkg/wallet/account.go index c1ddd1317..591e1971e 100644 --- a/pkg/wallet/account.go +++ b/pkg/wallet/account.go @@ -1,8 +1,11 @@ package wallet import ( + "encoding/hex" + "encoding/json" "errors" + "github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -43,8 +46,8 @@ type Account struct { // Contract represents a subset of the smartcontract to embed in the // Account so it's NEP-6 compliant. type Contract struct { - // Script hash of the contract deployed on the blockchain. - Script util.Uint160 `json:"script"` + // Script of the contract deployed on the blockchain. + Script []byte `json:"script"` // A list of parameters used deploying this contract. Parameters []interface{} `json:"parameters"` @@ -53,6 +56,54 @@ type Contract struct { Deployed bool `json:"deployed"` } +// contract is an intermediate struct used for json unmarshalling. +type contract struct { + // Script is a hex-encoded script of the contract. + Script string `json:"script"` + + // A list of parameters used deploying this contract. + Parameters []interface{} `json:"parameters"` + + // Indicates whether the contract has been deployed to the blockchain. + Deployed bool `json:"deployed"` +} + +// ScriptHash returns the hash of contract's script. +func (c Contract) ScriptHash() util.Uint160 { + return hash.Hash160(c.Script) +} + +// MarshalJSON implements json.Marshaler interface. +func (c Contract) MarshalJSON() ([]byte, error) { + var cc contract + + cc.Script = hex.EncodeToString(c.Script) + cc.Parameters = c.Parameters + cc.Deployed = c.Deployed + + return json.Marshal(cc) +} + +// UnmarshalJSON implements json.Unmarshaler interface. +func (c *Contract) UnmarshalJSON(data []byte) error { + var cc contract + + if err := json.Unmarshal(data, &cc); err != nil { + return err + } + + script, err := hex.DecodeString(cc.Script) + if err != nil { + return err + } + + c.Script = script + c.Parameters = cc.Parameters + c.Deployed = cc.Deployed + + return nil +} + // NewAccount creates a new Account with a random generated PrivateKey. func NewAccount() (*Account, error) { priv, err := keys.NewPrivateKey() diff --git a/pkg/wallet/account_test.go b/pkg/wallet/account_test.go index da84055f2..81eef739b 100644 --- a/pkg/wallet/account_test.go +++ b/pkg/wallet/account_test.go @@ -2,8 +2,10 @@ package wallet import ( "encoding/hex" + "encoding/json" "testing" + "github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/internal/keytestcases" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -47,6 +49,31 @@ func TestNewFromWif(t *testing.T) { } } +func TestContract_MarshalJSON(t *testing.T) { + var c Contract + + data := []byte(`{"script":"0102","parameters":[1],"deployed":false}`) + require.NoError(t, json.Unmarshal(data, &c)) + require.Equal(t, []byte{1, 2}, c.Script) + + result, err := json.Marshal(c) + require.NoError(t, err) + require.JSONEq(t, string(data), string(result)) + + data = []byte(`1`) + require.Error(t, json.Unmarshal(data, &c)) + + data = []byte(`{"script":"ERROR","parameters":[1],"deployed":false}`) + require.Error(t, json.Unmarshal(data, &c)) +} + +func TestContract_ScriptHash(t *testing.T) { + script := []byte{0, 1, 2, 3} + c := &Contract{Script: script} + + require.Equal(t, hash.Hash160(script), c.ScriptHash()) +} + func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) { if want, have := tk.Address, acc.Address; want != have { t.Fatalf("expected %s got %s", want, have) diff --git a/pkg/wallet/wallet.go b/pkg/wallet/wallet.go index 413a318fb..c54aa20cc 100644 --- a/pkg/wallet/wallet.go +++ b/pkg/wallet/wallet.go @@ -6,6 +6,7 @@ import ( "os" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/util" ) const ( @@ -117,3 +118,14 @@ func (w *Wallet) Close() { rc.Close() } } + +// GetAccount returns account corresponding to the provided scripthash. +func (w *Wallet) GetAccount(h util.Uint160) *Account { + for _, acc := range w.Accounts { + if c := acc.Contract; c != nil && h.Equals(c.ScriptHash()) { + return acc + } + } + + return nil +} diff --git a/pkg/wallet/wallet_test.go b/pkg/wallet/wallet_test.go index 2a80ca765..dca5590da 100644 --- a/pkg/wallet/wallet_test.go +++ b/pkg/wallet/wallet_test.go @@ -6,6 +6,7 @@ import ( "os" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -119,3 +120,28 @@ func removeWallet(t *testing.T, walletPath string) { err := os.RemoveAll(walletPath) require.NoError(t, err) } + +func TestWallet_GetAccount(t *testing.T) { + wallet := checkWalletConstructor(t) + accounts := []*Account{ + { + Contract: &Contract{ + Script: []byte{0, 1, 2, 3}, + }, + }, + { + Contract: &Contract{ + Script: []byte{3, 2, 1, 0}, + }, + }, + } + + for _, acc := range accounts { + wallet.AddAccount(acc) + } + + for i, acc := range accounts { + h := acc.Contract.ScriptHash() + assert.Equal(t, acc, wallet.GetAccount(h), "can't get %d account", i) + } +}